Initial commit

This commit is contained in:
Gericom
2025-11-22 11:08:28 +01:00
commit 9cf3ffbfcf
358 changed files with 58350 additions and 0 deletions

83
common/ApList.cpp Normal file
View File

@@ -0,0 +1,83 @@
#include "common.h"
#include <algorithm>
#include "ApList.h"
const ApListEntry* ApList::FindEntry(u32 gameCode, u8 gameVersion)
{
if (_count != 0)
{
const auto gameEntry = std::lower_bound(_entries.get(), _entries.get() + _count, gameCode,
[gameVersion] (const ApListEntry& entry, u32 value)
{
if (entry.GetGameCode() == value)
return entry.GetGameVersion() < gameVersion;
return entry.GetGameCode() < value;
});
if (gameEntry != _entries.get() + _count &&
gameEntry->GetGameCode() == gameCode &&
gameEntry->GetGameVersion() == gameVersion)
{
return gameEntry;
}
}
return nullptr;
}
void ApListEntry::Dump() const
{
const char* dsProtectVersionString;
switch (GetDSProtectVersion())
{
case DSProtectVersion::v1_05: dsProtectVersionString = "v1.05"; break;
case DSProtectVersion::v1_06: dsProtectVersionString = "v1.06"; break;
case DSProtectVersion::v1_08: dsProtectVersionString = "v1.08"; break;
case DSProtectVersion::v1_10: dsProtectVersionString = "v1.10"; break;
case DSProtectVersion::v1_20: dsProtectVersionString = "v1.20"; break;
case DSProtectVersion::v1_22: dsProtectVersionString = "v1.22"; break;
case DSProtectVersion::v1_23: dsProtectVersionString = "v1.23"; break;
case DSProtectVersion::v1_23Z: dsProtectVersionString = "v1.23Z"; break;
case DSProtectVersion::v1_25: dsProtectVersionString = "v1.25"; break;
case DSProtectVersion::v1_26: dsProtectVersionString = "v1.26"; break;
case DSProtectVersion::v1_27: dsProtectVersionString = "v1.27"; break;
case DSProtectVersion::v1_28: dsProtectVersionString = "v1.28"; break;
case DSProtectVersion::v2_00: dsProtectVersionString = "v2.00"; break;
case DSProtectVersion::v2_01: dsProtectVersionString = "v2.01"; break;
case DSProtectVersion::v2_03: dsProtectVersionString = "v2.03"; break;
case DSProtectVersion::v2_05: dsProtectVersionString = "v2.05"; break;
case DSProtectVersion::v2_00s: dsProtectVersionString = "v2.00s"; break;
case DSProtectVersion::v2_01s: dsProtectVersionString = "v2.01s"; break;
case DSProtectVersion::v2_03s: dsProtectVersionString = "v2.03s"; break;
case DSProtectVersion::v2_05s: dsProtectVersionString = "v2.05s"; break;
default:
dsProtectVersionString = "unknown";
break;
}
LOG_DEBUG("%c%c%c%c - %d - DSProtect %s\n",
gameCode & 0xFF, (gameCode >> 8) & 0xFF, (gameCode >> 16) & 0xFF, gameCode >> 24,
gameVersion,
dsProtectVersionString);
if (regularOverlayId != AP_LIST_OVERLAY_ID_INVALID)
{
if (regularOverlayId == AP_LIST_OVERLAY_ID_STATIC_ARM9)
{
LOG_DEBUG("regular: main memory offset 0x%x\n", GetRegularOffset());
}
else
{
LOG_DEBUG("regular: overlay %d offset 0x%x\n", regularOverlayId, GetRegularOffset());
}
}
if (sOverlayId != AP_LIST_OVERLAY_ID_INVALID)
{
if (sOverlayId == AP_LIST_OVERLAY_ID_STATIC_ARM9)
{
LOG_DEBUG("s: main memory offset 0x%x\n", GetSOffset());
}
else
{
LOG_DEBUG("s: overlay %d offset 0x%x\n", sOverlayId, GetSOffset());
}
}
}

48
common/ApList.h Normal file
View File

@@ -0,0 +1,48 @@
#pragma once
#include <memory>
#include "common.h"
#include "DSProtectVersion.h"
#define AP_LIST_OVERLAY_ID_STATIC_ARM9 0xFFFE
#define AP_LIST_OVERLAY_ID_INVALID 0xFFFF
/// @brief Class representing an AP list entry.
class ApListEntry
{
u32 gameCode;
u16 gameVersion : 5;
u16 dsProtectVersion : 5; // see DSProtectVersion
u16 dsProtectFunctionMask : 6; // for versions < 1.23
u16 regularOverlayId; // 0xFFFE = static ARM9, 0xFFFF = invalid
u16 sOverlayId; // 0xFFFE = static ARM9, 0xFFFF = invalid
u8 regularOffset[3]; // 24 bit
u8 sOffset[3]; // 24 bit
public:
u32 GetGameCode() const { return gameCode; }
u8 GetGameVersion() const { return gameVersion; }
DSProtectVersion GetDSProtectVersion() const { return static_cast<DSProtectVersion>(dsProtectVersion); }
u8 GetDSProtectFunctionMask() const { return dsProtectFunctionMask; }
u16 GetRegularOverlayId() const { return regularOverlayId; }
u16 GetSOverlayId() const { return sOverlayId; }
u32 GetRegularOffset() const { return regularOffset[0] | (regularOffset[1] << 8) | (regularOffset[2] << 16); }
u32 GetSOffset() const { return sOffset[0] | (sOffset[1] << 8) | (sOffset[2] << 16); }
void Dump() const;
};
static_assert(sizeof(ApListEntry) == 0x10, "Invalid sizeof(ApListEntry)");
/// @brief Class representing an AP list.
class ApList
{
public:
ApList(std::unique_ptr<const ApListEntry[]> entries, u32 count)
: _entries(std::move(entries)), _count(count) { }
const ApListEntry* FindEntry(u32 gameCode, u8 gameVersion);
private:
std::unique_ptr<const ApListEntry[]> _entries;
u32 _count;
};

17
common/CardSaveType.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
/// @brief Enum representing the save type.
enum class CardSaveType
{
/// @brief The game has no save.
None = 0,
/// @brief EEPROM save.
Eeprom = 1,
/// @brief Flash save.
Flash = 2,
/// @brief NAND save.
Nand = 3
};

26
common/DSProtectVersion.h Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
/// @brief Enum representing a DS Protect version.
enum class DSProtectVersion : u32
{
v1_06,
v1_05,
v1_08,
v1_10,
v1_20,
v1_22,
v1_23,
v1_23Z,
v1_25,
v1_26,
v1_27,
v1_28,
v2_00,
v2_01,
v2_03,
v2_05,
v2_00s,
v2_01s,
v2_03s,
v2_05s
};

10
common/LoaderInfo.h Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
struct loader_info_t
{
u16 clusterShift;
u16 picoLoaderBootDrive;
u32 database;
u32 clusterMap9[10];
u32 clusterMap7[16];
};

41
common/SdkVersion.h Normal file
View File

@@ -0,0 +1,41 @@
#pragma once
#define SDK_VERSION_MAJOR_SHIFT 24
#define SDK_VERSION_MINOR_SHIFT 16
#define SDK_VERSION_RELEASE_STEP_SHIFT 0
#define SDK_VERSION_MAJOR_MASK 0x00FF
#define SDK_VERSION_MINOR_MASK 0x00FF
#define SDK_VERSION_RELEASE_STEP_MASK 0xFFFF
#define SDK_VERSION_MAJOR_NITRO_2 2
#define SDK_VERSION_MAJOR_NITRO_3 3
#define SDK_VERSION_MAJOR_NITRO_4 4
#define SDK_VERSION_MAJOR_TWL 5
#define SDK_VERSION_RELEASE_STEP_PREVIEW 10000
#define SDK_VERSION_RELEASE_STEP_RELEASE_CANDIDATE 20000
#define SDK_VERSION_RELEASE_STEP_RELEASE 30000
/// @brief Class representing an exact SDK version.
class SdkVersion
{
u32 _version;
public:
constexpr SdkVersion(u32 version)
: _version(version) { }
constexpr SdkVersion(u32 major, u32 minor, u32 releaseStep)
: _version((major << SDK_VERSION_MAJOR_SHIFT) | (minor << SDK_VERSION_MINOR_SHIFT) | releaseStep) { }
constexpr u32 GetMajor() const { return _version >> SDK_VERSION_MAJOR_SHIFT; }
constexpr u32 GetMinor() const { return (_version >> SDK_VERSION_MINOR_SHIFT) & SDK_VERSION_MINOR_MASK; }
constexpr u32 GetReleaseClass() const { return GetReleaseStep() / 10000; }
constexpr u32 GetReleaseMajor() const { return (GetReleaseStep() % 10000) / 100; }
constexpr u32 GetReleaseMinor() const { return (GetReleaseStep() % 10000) % 100; }
constexpr u32 GetReleaseStep() const { return _version & SDK_VERSION_RELEASE_STEP_MASK; }
constexpr bool IsTwlSdk() const { return GetMajor() == SDK_VERSION_MAJOR_TWL; }
constexpr friend auto operator<=>(const SdkVersion&, const SdkVersion&) = default;
};

52
common/TwlConfig.h Normal file
View File

@@ -0,0 +1,52 @@
#pragma once
#include <nds/ndstypes.h>
struct twl_config_t
{
u32 configFlags;
u8 field4;
u8 country;
u8 language;
u8 rtcYear;
s64 rtcOffset;
u8 eulaAgreeVersion[8];
u8 field18[2];
u8 alarmHour;
u8 alarmMinute;
u8 field1C[2];
u8 alarmEnable;
u8 field1F[2];
u8 systemMenuUsedTitleSlots;
u8 systemMenuFreeTitleSlots;
u8 field23;
u8 field24;
u8 field25[3];
u64 systemMenuLastSelectedTitleId;
u16 touchCalibrationX1Adc;
u16 touchCalibrationY1Adc;
u8 touchCalibrationX1Pixel;
u8 touchCalibrationY1Pixel;
u16 touchCalibrationX2Adc;
u16 touchCalibrationY2Adc;
u8 touchCalibrationX2Pixel;
u8 touchCalibrationY2Pixel;
u32 field3C;
u8 field40[4];
u8 favoriteColor;
u8 field45;
u8 birthdayMonth;
u8 birthdayDay;
u16 nickname[11];
u16 message[27];
u8 parentalControlsFlags;
u8 field95[6];
u8 parentalControlsRegion;
u8 parentalControlsAge;
u8 parentalControlsSecretQuestion;
u8 parentalControlsUnknown;
u8 field9F[2];
u8 parentalControlsPin[5];
u16 parentalControlsSecretAnswer[65];
};
static_assert(sizeof(twl_config_t) == 0x128);

17
common/argv.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
#define HOMEBREW_ARGV_MAGIC 0x5f617267
//structure used to set up argc/argv on the DS
struct homebrew_argv_t
{
int magic; // argv magic number, set to 0x5f617267 ('_arg') if valid
char* commandLine; // base address of command line, set of null terminated strings
int length; // total length of command line
int argc; // internal use, number of arguments
char** argv; // internal use, argv pointer
int dummy; // internal use
u32 host; // internal use, host ip for dslink
};
#define HOMEBREW_ARGV ((homebrew_argv_t*)0x02FFFE70)

1272
common/core/heap/tlsf.arm.c Normal file

File diff suppressed because it is too large Load Diff

90
common/core/heap/tlsf.h Normal file
View File

@@ -0,0 +1,90 @@
#ifndef INCLUDED_tlsf
#define INCLUDED_tlsf
/*
** Two Level Segregated Fit memory allocator, version 3.1.
** Written by Matthew Conte
** http://tlsf.baisoku.org
**
** Based on the original documentation by Miguel Masmano:
** http://www.gii.upv.es/tlsf/main/docs
**
** This implementation was written to the specification
** of the document, therefore no GPL restrictions apply.
**
** Copyright (c) 2006-2016, Matthew Conte
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of the copyright holder nor the
** names of its contributors may be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
** DISCLAIMED. IN NO EVENT SHALL MATTHEW CONTE BE LIABLE FOR ANY
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
** (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
** LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stddef.h>
#if defined(__cplusplus)
extern "C" {
#endif
/* tlsf_t: a TLSF structure. Can contain 1 to N pools. */
/* pool_t: a block of memory that TLSF can manage. */
typedef void* tlsf_t;
typedef void* pool_t;
/* Create/destroy a memory pool. */
tlsf_t tlsf_create(void* mem);
tlsf_t tlsf_create_with_pool(void* mem, size_t bytes);
void tlsf_destroy(tlsf_t tlsf);
pool_t tlsf_get_pool(tlsf_t tlsf);
/* Add/remove memory pools. */
pool_t tlsf_add_pool(tlsf_t tlsf, void* mem, size_t bytes);
void tlsf_remove_pool(tlsf_t tlsf, pool_t pool);
/* malloc/memalign/realloc/free replacements. */
void* tlsf_malloc(tlsf_t tlsf, size_t bytes);
void* tlsf_memalign(tlsf_t tlsf, size_t align, size_t bytes);
void* tlsf_realloc(tlsf_t tlsf, void* ptr, size_t size);
void tlsf_free(tlsf_t tlsf, void* ptr);
/* Returns internal block size, not original request size */
size_t tlsf_block_size(void* ptr);
/* Overheads/limits of internal structures. */
size_t tlsf_size(void);
size_t tlsf_align_size(void);
size_t tlsf_block_size_min(void);
size_t tlsf_block_size_max(void);
size_t tlsf_pool_overhead(void);
size_t tlsf_alloc_overhead(void);
/* Debugging. */
typedef void (*tlsf_walker)(void* ptr, size_t size, int used, void* user);
void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user);
/* Returns nonzero if any internal consistency check fails. */
int tlsf_check(tlsf_t tlsf);
int tlsf_check_pool(pool_t pool);
#if defined(__cplusplus)
};
#endif
#endif

312
common/core/mini-printf.c Normal file
View File

@@ -0,0 +1,312 @@
/*
* The Minimal snprintf() implementation
*
* Copyright (c) 2013,2014 Michal Ludvig <michal@logix.cz>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the auhor nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ----
*
* This is a minimal snprintf() implementation optimised
* for embedded systems with a very limited program memory.
* mini_snprintf() doesn't support _all_ the formatting
* the glibc does but on the other hand is a lot smaller.
* Here are some numbers from my STM32 project (.bin file size):
* no snprintf(): 10768 bytes
* mini snprintf(): 11420 bytes (+ 652 bytes)
* glibc snprintf(): 34860 bytes (+24092 bytes)
* Wasting nearly 24kB of memory just for snprintf() on
* a chip with 32kB flash is crazy. Use mini_snprintf() instead.
*
*/
#include "mini-printf.h"
static int
mini_strlen(const char *s)
{
int len = 0;
while (s[len] != '\0') len++;
return len;
}
static int
mini_itoa(long value, unsigned int radix, int uppercase, int unsig,
char *buffer)
{
char *pbuffer = buffer;
int negative = 0;
int i, len;
/* No support for unusual radixes. */
if (radix > 16)
return 0;
if (value < 0 && !unsig) {
negative = 1;
value = -value;
}
/* This builds the string back to front ... */
do {
int digit = value % radix;
*(pbuffer++) = (digit < 10 ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10);
value /= radix;
} while (value > 0);
if (negative)
*(pbuffer++) = '-';
*(pbuffer) = '\0';
/* ... now we reverse it (could do it recursively but will
* conserve the stack space) */
len = (pbuffer - buffer);
for (i = 0; i < len / 2; i++) {
char j = buffer[i];
buffer[i] = buffer[len-i-1];
buffer[len-i-1] = j;
}
return len;
}
static int
mini_pad(char* ptr, int len, char pad_char, int pad_to, char *buffer)
{
int i;
int overflow = 0;
char * pbuffer = buffer;
if(pad_to == 0) pad_to = len;
if(len > pad_to) {
len = pad_to;
overflow = 1;
}
for(i = pad_to - len; i > 0; i --) {
*(pbuffer++) = pad_char;
}
for(i = len; i > 0; i --) {
*(pbuffer++) = *(ptr++);
}
len = pbuffer - buffer;
if(overflow) {
for (i = 0; i < 3 && pbuffer > buffer; i ++) {
*(pbuffer-- - 1) = '*';
}
}
return len;
}
struct mini_buff {
char *buffer, *pbuffer;
unsigned int buffer_len;
};
static int
_puts(char *s, int len, void *buf)
{
if(!buf) return len;
struct mini_buff *b = buf;
char * p0 = b->buffer;
int i;
/* Copy to buffer */
for (i = 0; i < len; i++) {
if(b->pbuffer == b->buffer + b->buffer_len - 1) {
break;
}
*(b->pbuffer ++) = s[i];
}
*(b->pbuffer) = 0;
return b->pbuffer - p0;
}
#ifdef MINI_PRINTF_ENABLE_OBJECTS
static int (*mini_handler) (void* data, void* obj, int ch, int lhint, char** bf) = 0;
static void (*mini_handler_freeor)(void* data, void*) = 0;
static void * mini_handler_data = 0;
void mini_printf_set_handler(
void* data,
int (*handler)(void* data, void* obj, int ch, int len_hint, char** buf),
void (*freeor)(void* data, void* buf))
{
mini_handler = handler;
mini_handler_freeor = freeor;
mini_handler_data = data;
}
#endif
int
mini_vsnprintf(char *buffer, unsigned int buffer_len, const char *fmt, va_list va)
{
struct mini_buff b;
b.buffer = buffer;
b.pbuffer = buffer;
b.buffer_len = buffer_len;
if(buffer_len == 0) buffer = (void*) 0;
int n = mini_vpprintf(_puts, (buffer != (void*)0)?&b:(void*)0, fmt, va);
if(buffer == (void*) 0) {
return n;
}
return b.pbuffer - b.buffer;
}
int
mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va)
{
char bf[24];
char bf2[24];
char ch;
#ifdef MINI_PRINTF_ENABLE_OBJECTS
void* obj;
#endif
if(puts == (void*)0) {
/* run puts in counting mode. */
puts = _puts; buf = (void*)0;
}
int n = 0;
while ((ch=*(fmt++))) {
int len;
if (ch!='%') {
len = 1;
len = puts(&ch, len, buf);
} else {
char pad_char = ' ';
int pad_to = 0;
char l = 0;
char *ptr;
ch=*(fmt++);
/* Zero padding requested */
if (ch == '0') pad_char = '0';
while (ch >= '0' && ch <= '9') {
pad_to = pad_to * 10 + (ch - '0');
ch=*(fmt++);
}
if(pad_to > (signed int) sizeof(bf)) {
pad_to = sizeof(bf);
}
if (ch == 'l') {
l = 1;
ch=*(fmt++);
}
switch (ch) {
case 0:
goto end;
case 'u':
case 'd':
if(l) {
len = mini_itoa(va_arg(va, unsigned long), 10, 0, (ch=='u'), bf2);
} else {
if(ch == 'u') {
len = mini_itoa((unsigned long) va_arg(va, unsigned int), 10, 0, 1, bf2);
} else {
len = mini_itoa((long) va_arg(va, int), 10, 0, 0, bf2);
}
}
len = mini_pad(bf2, len, pad_char, pad_to, bf);
len = puts(bf, len, buf);
break;
case 'p':
case 'x':
case 'X':
if(l) {
len = mini_itoa(va_arg(va, unsigned long), 16, (ch=='X'), 1, bf2);
} else {
len = mini_itoa((unsigned long) va_arg(va, unsigned int), 16, (ch=='X'), 1, bf2);
}
len = mini_pad(bf2, len, pad_char, pad_to, bf);
len = puts(bf, len, buf);
break;
case 'c' :
ch = (char)(va_arg(va, int));
len = mini_pad(&ch, 1, pad_char, pad_to, bf);
len = puts(bf, len, buf);
break;
case 's' :
ptr = va_arg(va, char*);
len = mini_strlen(ptr);
if (pad_to > 0) {
len = mini_pad(ptr, len, pad_char, pad_to, bf);
len = puts(bf, len, buf);
} else {
len = puts(ptr, len, buf);
}
break;
#ifdef MINI_PRINTF_ENABLE_OBJECTS
case 'O' : /* Object by content (e.g. str) */
case 'R' : /* Object by representation (e.g. repr)*/
obj = va_arg(va, void*);
len = mini_handler(mini_handler_data, obj, ch, pad_to, &ptr);
if (pad_to > 0) {
len = mini_pad(ptr, len, pad_char, pad_to, bf);
len = puts(bf, len, buf);
} else {
len = puts(ptr, len, buf);
}
mini_handler_freeor(mini_handler_data, ptr);
break;
#endif
default:
len = 1;
len = puts(&ch, len, buf);
break;
}
}
n = n + len;
}
end:
return n;
}
int
mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...)
{
int ret;
va_list va;
va_start(va, fmt);
ret = mini_vsnprintf(buffer, buffer_len, fmt, va);
va_end(va);
return ret;
}
int
mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...)
{
int ret;
va_list va;
va_start(va, fmt);
ret = mini_vpprintf(puts, buf, fmt, va);
va_end(va);
return ret;
}

73
common/core/mini-printf.h Normal file
View File

@@ -0,0 +1,73 @@
/*
* The Minimal snprintf() implementation
*
* Copyright (c) 2013 Michal Ludvig <michal@logix.cz>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the auhor nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __MINI_PRINTF__
#define __MINI_PRINTF__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdarg.h>
#ifdef MINI_PRINTF_ENABLE_OBJECTS
/* If enabled, callback for object types (O and R).
* void* arguments matching %O and %R are sent to handler as obj.
* the result string created by handler at *buf is freed by freeor.
* */
void mini_printf_set_handler(
void * data,
/* handler returns number of chars in *buf; *buf is not NUL-terminated. */
int (*handler)(void* data, void* obj, int ch, int len_hint, char** buf),
void (*freeor)(void* data, void* buf));
#endif
/* String IO interface; returns number of bytes written, not including the ending NUL.
* Always appends a NUL at the end, therefore buffer_len shall be at least 1 in normal operation.
* If buffer is NULL or buffer_len is 0, returns number of bytes to be written, not including the ending NUL.
*/
int mini_vsnprintf(char* buffer, unsigned int buffer_len, const char *fmt, va_list va);
int mini_snprintf(char* buffer, unsigned int buffer_len, const char *fmt, ...);
/* Stream IO interface; returns number of bytes written.
* If puts is NULL, number of bytes to be written.
* puts shall return number of bytes written.
*/
int mini_vpprintf(int (*puts)(char* s, int len, void* buf), void* buf, const char *fmt, va_list va);
int mini_pprintf(int (*puts)(char*s, int len, void* buf), void* buf, const char *fmt, ...);
#ifdef __cplusplus
}
#endif
#define vsnprintf mini_vsnprintf
#define snprintf mini_snprintf
#endif

22
common/fileInfo.h Normal file
View File

@@ -0,0 +1,22 @@
#pragma once
#include "sharedMemory.h"
struct rom_file_info_t
{
u32 clusterShift;
u32 database;
u32 clusterMask;
u32 clusterMap[124];
u32 fileSize;
};
struct save_file_info_t
{
u32 clusterShift;
u32 database;
u32 clusterMask;
u32 clusterMap[29];
};
#define SHARED_ROM_FILE_INFO ((rom_file_info_t*)TWL_SHARED_MEMORY->ntrSharedMem.gap0)
#define SHARED_SAVE_FILE_INFO ((save_file_info_t*)TWL_SHARED_MEMORY->ntrSharedMem.gap200)

11
common/gameCode.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
static inline consteval u32 GAMECODE(const char code[4])
{
return code[0] | (code[1] << 8) | (code[2] << 16) | (code[3] << 24);
}
static inline consteval u32 GAMECODE_NO_REGION(const char code[3])
{
return code[0] | (code[1] << 8) | (code[2] << 16);
}

14
common/ipcCommands.h Normal file
View File

@@ -0,0 +1,14 @@
#pragma once
#define IPC_COMMAND_ARM9_WRAM_CONFIG 1
#define IPC_COMMAND_ARM9_CLEAR_MAIN_MEM 2
#define IPC_COMMAND_ARM9_APPLY_PATCHES 3
#define IPC_COMMAND_ARM9_APPLY_ARM7_PATCHES 4
#define IPC_COMMAND_ARM9_SET_AP_INFO 5
#define IPC_COMMAND_ARM9_SET_ROM_FILE_INFO 6
#define IPC_COMMAND_ARM9_INITIALIZE_SD_CARD 8
#define IPC_COMMAND_ARM9_INITIALIZE_LOADER_INFO 9
#define IPC_COMMAND_ARM9_GET_SD_FUNCTIONS 0xA
#define IPC_COMMAND_ARM9_DISPLAY_ERROR 0xB
#define IPC_COMMAND_ARM9_SWITCH_TO_DS_MODE 0xD
#define IPC_COMMAND_ARM9_BOOT 0xF

32
common/logger/ILogger.h Normal file
View File

@@ -0,0 +1,32 @@
#pragma once
#include <stdarg.h>
enum class LogLevel
{
Off,
Fatal,
Error,
Warning,
Info,
Debug,
Trace,
All
};
class ILogger
{
public:
virtual ~ILogger() { }
void Log(LogLevel level, const char* fmt, ...)
{
va_list vlist;
va_start(vlist, fmt);
LogV(level, fmt, vlist);
va_end(vlist);
}
virtual void LogV(LogLevel level, const char* fmt, va_list vlist) = 0;
};

View File

@@ -0,0 +1,10 @@
#pragma once
class IOutputStream
{
public:
virtual ~IOutputStream() { }
virtual void Write(const char* str) = 0;
virtual void Flush() = 0;
};

View File

@@ -0,0 +1,8 @@
#pragma once
#include "ILogger.h"
class NullLogger : public ILogger
{
public:
void LogV(LogLevel level, const char* fmt, va_list vlist) override { }
};

View File

@@ -0,0 +1,9 @@
#pragma once
#include "IOutputStream.h"
class NullOutputStream : public IOutputStream
{
public:
void Write(const char* str) { }
void Flush() { }
};

View File

@@ -0,0 +1,26 @@
#include <nds.h>
#include "picoAgbAdapter.h"
#include "PicoAgbAdapterOutputStream.h"
void PicoAgbAdapterOutputStream::Write(const char* str)
{
char c;
vu16* ring = PICO_AGB_PRINT_ARM9_RING;
u32 writePtr = PICO_AGB_PRINT_ARM9_WRITE_PTR;
u32 readPtr = PICO_AGB_PRINT_ARM9_READ_PTR;
while ((c = *str++) != 0)
{
u32 newWritePtr = (writePtr + 1) & (PICO_AGB_PRINT_RING_LENGTH - 1);
while (newWritePtr == readPtr)
{
PICO_AGB_PRINT_ARM9_WRITE_PTR = writePtr;
readPtr = PICO_AGB_PRINT_ARM9_READ_PTR;
}
if (writePtr & 1)
ring[writePtr >> 1] = (ring[writePtr >> 1] & 0xFF) | (c << 8);
else
ring[writePtr >> 1] = (ring[writePtr >> 1] & 0xFF00) | c;
writePtr = newWritePtr;
}
PICO_AGB_PRINT_ARM9_WRITE_PTR = writePtr;
}

View File

@@ -0,0 +1,11 @@
#pragma once
#include "IOutputStream.h"
class PicoAgbAdapterOutputStream : public IOutputStream
{
public:
PicoAgbAdapterOutputStream() { }
void Write(const char* str) override;
void Flush() override { }
};

44
common/moduleParams.h Normal file
View File

@@ -0,0 +1,44 @@
#pragma once
#define MODULE_PARAMS_NTR_MAGIC_LE 0x2106C0DE
#define MODULE_PARAMS_NTR_MAGIC_BE 0xDEC00621
#define MODULE_PARAMS_TWL_MAGIC_LE 0x6314C0DE
#define MODULE_PARAMS_TWL_MAGIC_BE 0xDEC01463
struct module_params_ntr_t
{
u32 autoloadListStart;
u32 autoloadListEnd;
u32 autoloadStart;
u32 bssStart;
u32 bssEnd;
u32 compressedEnd;
u32 sdkVersion;
u32 magicBigEndian; //0xDEC00621
u32 magicLittleEndian; //0x2106C0DE
};
// for the twl binaries of a hybrid or limited rom
struct module_params_twl_t
{
u32 autoloadListStart;
u32 autoloadListEnd;
u32 autoloadStart;
u32 compressedEnd;
u32 magicBigEndian; //0xDEC01463
u32 magicLittleEndian; //0x6314C0DE
};
// only on sdk 5
struct build_params_t
{
u32 reserved0[4];
u8 buildCode;
u8 sdkTarget;
u8 reserved1[2];
u8 version;
u8 reserved2[3];
u32 magicBigEndian; //0xDEC08133
u32 magicLittleEndian; //0x3381C0DE
};

144
common/ndsHeader.h Normal file
View File

@@ -0,0 +1,144 @@
#pragma once
#include <nds/ndstypes.h>
struct nds_header_ntr_t
{
u8 gameTitle[12];
u32 gameCode;
u8 makerCode[2];
u8 unitCode;
u8 encryptionSeedSelect;
u8 deviceCapacity;
u8 gap15[7];
u8 twlFlags;
u8 flags;
u8 softwareVersion;
u8 flags2;
u32 arm9RomOffset;
u32 arm9EntryAddress;
u32 arm9LoadAddress;
u32 arm9Size;
u32 arm7RomOffset;
u32 arm7EntryAddress;
u32 arm7LoadAddress;
u32 arm7Size;
u32 fntOffset;
u32 fntSize;
u32 fatOffset;
u32 fatSize;
u32 arm9OverlayTableOffset;
u32 arm9OverlayTableSize;
u32 arm7OverlayTableOffset;
u32 arm7OverlayTableSize;
u32 normalModeRomControl;
u32 secureModeRomControl;
u32 bannerOffset;
u16 secureAreaCrc;
u16 secureDelay;
u32 arm9AutoLoadDoneHookAddress;
u32 arm7AutoLoadDoneHookAddress;
u8 secureAreaDisable[8];
u32 ntrRomSize;
u32 romHeaderSize;
u32 arm9ModuleParamsAddress;
u32 arm7ModuleParamsAddress;
u16 ntrRegionEnd;
u16 twlRegionStart;
u16 nandRomRegionEnd;
u16 nandBackupRegionStart;
u8 gap98[0x28];
u8 nintendoLogo[0x9C];
u16 nintendoLogoCrc;
u16 headerCrc;
u32 debugRomOffset;
u32 debugRomSize;
u32 debugRomLoadAddress; // and arm9 entry
u32 debugRomArm7EntryAddress;
constexpr bool IsTwlRom() const
{
return unitCode & 2;
}
};
static_assert(sizeof(nds_header_ntr_t) == 0x170, "Invalid size for nds_header_ntr_t");
struct nds_header_twl_t
{
nds_header_ntr_t ntrHeader;
u8 gap170[0x10];
u32 globalMbkSettings[5]; // slot mapping
u32 arm9MbkSettings[3]; // wram mapping
u32 arm7MbkSettings[3]; // wram mapping
u8 mbk9Setting[3];
u8 wramCntSetting;
u32 regionFlags;
u32 accessControl;
u32 arm7ScfgExt7;
u8 gap1B8[3];
u8 twlFlags2;
u32 arm9iRomOffset;
u8 gap1C4[4];
u32 arm9iLoadAddress;
u32 arm9iSize;
u32 arm7iRomOffset;
u32 arm7DeviceListAddress;
u32 arm7iLoadAddress;
u32 arm7iSize;
u32 ntrDigestRegionOffset;
u32 ntrDigestRegionSize;
u32 twlDigestRegionOffset;
u32 twlDigestRegionSize;
u32 digestSectorHashtableOffset;
u32 digestSectorHashtableSize;
u32 digestBlockHashtableOffset;
u32 digestBlockHashtableSize;
u32 digestSectorSize;
u32 digestSectorsPerBlock;
u32 bannerSize;
u8 shared2File0Size;
u8 shared2File1Size;
u8 eulaVersion;
u8 twlManagementFlags;
u32 totalTwlRomSize; // can be 0
u8 shared2File2Size;
u8 shared2File3Size;
u8 shared2File4Size;
u8 shared2File5Size;
u32 arm9iModuleParamsAddress;
u32 arm7iModuleParamsAddress;
u32 modcryptArea1Offset;
u32 modcryptArea1Size;
u32 modcryptArea2Offset;
u32 modcryptArea2Size;
u64 titleId;
u32 twlPublicSavSize;
u32 twlPrivateSavSize;
u8 gap240[0xB0];
u8 parentalControlRatings[0x10];
u8 arm9Sha1Hmac[0x14];
u8 arm7Sha1Hmac[0x14];
u8 digestMasterSha1Hmac[0x14];
u8 bannerSha1Hmac[0x14];
u8 arm9iSha1Hmac[0x14];
u8 arm7iSha1Hmac[0x14];
u8 ntrHeaderArm9Arm7Sha1Hmac[0x14]; // whitelist phase 1
u8 ntrArm9OvtOverlaysFatSha1Hmac[0x14]; // whitelist phase 2
u8 arm9WithoutSecureAreaSha1Hmac[0x14];
u8 gap3B4[0xA4C];
u8 debugArguments[0x100];
u8 gapF00[0x80];
u8 headerRsaSha1Signature[0x80];
constexpr bool IsTwlRom() const
{
return ntrHeader.IsTwlRom();
}
constexpr bool IsDsiWare() const
{
return IsTwlRom() && ((titleId >> 32) & 0xFF) != 0;
}
};
static_assert(sizeof(nds_header_twl_t) == 0x1000, "Invalid size for nds_header_twl_t");

39
common/ndsabi/macros.inc Normal file
View File

@@ -0,0 +1,39 @@
// SPDX-License-Identifier: Zlib
// SPDX-FileNotice: Modified from the original version by the BlocksDS project.
//
// Copyright (C) 2021-2023 agbabi contributors
//
// ARM assembly support macros
@ Shift and test upper two bits, clobbering \reg
@ Use mi for first bit, cs for second bit
.macro joaobapt_test_lsl reg shift = #0
movs \reg, \reg, lsl \shift
.endm
@ Test lowest two bits, clobbering \reg
@ Use mi for low bit, cs for high bit
.macro joaobapt_test reg
joaobapt_test_lsl \reg, #31
.endm
@ Test lowest two bits of \src, result stored in \dst
@ Use mi for low bit, cs for high bit
.macro joaobapt_test_into dst, src
movs \dst, \src, lsl #31
.endm
@ Branches depending on lowest two bits, clobbering \reg
@ b_mi = low bit case, b_cs = high bit case
.macro joaobapt_switch reg, b_mi, b_cs
joaobapt_test \reg
bmi \b_mi
bcs \b_cs
.endm
@ Branches depending on alignment of \a and \b, clobbering \scratch
@ b_byte = off-by-byte case, b_half = off-by-half case
.macro align_switch a, b, scratch, b_byte, b_half
eor \scratch, \a, \b
joaobapt_switch \scratch, \b_byte, \b_half
.endm

126
common/ndsabi/memcpy.s Normal file
View File

@@ -0,0 +1,126 @@
// SPDX-License-Identifier: Zlib
// SPDX-FileNotice: Modified from the original version by the BlocksDS project.
//
// Copyright (C) 2021-2023 agbabi contributors
//
// ABI:
// __aeabi_memcpy, __aeabi_memcpy4, __aeabi_memcpy8
// Standard:
// memcpy
// Support:
// __ndsabi_memcpy2, __ndsabi_memcpy1
#include <nds/asminc.h>
#include "macros.inc"
.syntax unified
.arm
BEGIN_ASM_FUNC __aeabi_memcpy
@ >6-bytes is roughly the threshold when byte-by-byte copy is slower
cmp r2, #6
ble __ndsabi_memcpy1
align_switch r0, r1, r3, __ndsabi_memcpy1, .Lcopy_halves
@ Check if r0 (or r1) needs word aligning
rsbs r3, r0, #4
joaobapt_test r3
@ Copy byte head to align
ldrbmi r3, [r1], #1
strbmi r3, [r0], #1
submi r2, r2, #1
@ r0, r1 are now half aligned
@ Copy half head to align
ldrhcs r3, [r1], #2
strhcs r3, [r0], #2
subcs r2, r2, #2
@ r0, r1 are now word aligned
BEGIN_ASM_FUNC_NO_SECTION __aeabi_memcpy8
BEGIN_ASM_FUNC_NO_SECTION __aeabi_memcpy4
cmp r2, #32
blt .Lcopy_words
@ Word aligned, 32-byte copy
push {r4-r10}
.Lloop_32:
subs r2, r2, #32
ldmiage r1!, {r3-r10}
stmiage r0!, {r3-r10}
bgt .Lloop_32
pop {r4-r10}
bxeq lr
@ < 32 bytes remaining to be copied
add r2, r2, #32
.Lcopy_words:
cmp r2, #4
blt .Lcopy_halves
.Lloop_4:
subs r2, r2, #4
ldrge r3, [r1], #4
strge r3, [r0], #4
bgt .Lloop_4
bxeq lr
@ Copy byte & half tail
@ This test still works when r2 is negative
joaobapt_test r2
@ Copy half
ldrhcs r3, [r1], #2
strhcs r3, [r0], #2
@ Copy byte
ldrbmi r3, [r1]
strbmi r3, [r0]
bx lr
.Lcopy_halves:
@ Copy byte head to align
tst r0, #1
ldrbne r3, [r1], #1
strbne r3, [r0], #1
subne r2, r2, #1
@ r0, r1 are now half aligned
BEGIN_ASM_FUNC_NO_SECTION __ndsabi_memcpy2
subs r2, r2, #2
ldrhge r3, [r1], #2
strhge r3, [r0], #2
bgt __ndsabi_memcpy2
bxeq lr
@ Copy byte tail
adds r2, r2, #2
ldrbne r3, [r1]
strbne r3, [r0]
bx lr
BEGIN_ASM_FUNC __ndsabi_memcpy1
subs r2, r2, #1
ldrbge r3, [r1], #1
strbge r3, [r0], #1
bgt __ndsabi_memcpy1
bx lr
BEGIN_ASM_FUNC memcpy
push {r0, lr}
bl __aeabi_memcpy
pop {r0, lr}
bx lr

45
common/ndsabi/memmove.s Normal file
View File

@@ -0,0 +1,45 @@
// SPDX-License-Identifier: Zlib
// SPDX-FileNotice: Modified from the original version by the BlocksDS project.
//
// Copyright (C) 2021-2023 agbabi contributors
//
// ABI:
// __aeabi_memmove, __aeabi_memmove4, __aeabi_memmove8
// Standard:
// memmove
#include <nds/asminc.h>
.syntax unified
.arm
BEGIN_ASM_FUNC __aeabi_memmove
cmp r0, r1
bgt __ndsabi_rmemcpy
b __aeabi_memcpy
BEGIN_ASM_FUNC __aeabi_memmove8
BEGIN_ASM_FUNC_NO_SECTION __aeabi_memmove4
cmp r0, r1
bgt __ndsabi_rmemcpy
b __aeabi_memcpy4
BEGIN_ASM_FUNC __ndsabi_memmove1
cmp r0, r1
bgt __ndsabi_rmemcpy1
b __ndsabi_memcpy1
BEGIN_ASM_FUNC memmove
push {r0, lr}
bl __aeabi_memmove
pop {r0, lr}
bx lr

120
common/ndsabi/memset.s Normal file
View File

@@ -0,0 +1,120 @@
// SPDX-License-Identifier: Zlib
// SPDX-FileNotice: Modified from the original version by the BlocksDS project.
//
// Copyright (C) 2021-2023 agbabi contributors
//
// ABI:
// __aeabi_memclr, __aeabi_memclr4, __aeabi_memclr8,
// __aeabi_memset, __aeabi_memset4, __aeabi_memset8
// Standard:
// memset
// Support:
// __ndsabi_wordset4, __ndsabi_lwordset4, __ndsabi_memset1
#include <nds/asminc.h>
#include "macros.inc"
.syntax unified
.arm
BEGIN_ASM_FUNC __aeabi_memclr
mov r2, #0
b __aeabi_memset
BEGIN_ASM_FUNC __aeabi_memclr8
BEGIN_ASM_FUNC_NO_SECTION __aeabi_memclr4
mov r2, #0
b __ndsabi_wordset4
BEGIN_ASM_FUNC __aeabi_memset
@ < 8 bytes probably won't be aligned: go byte-by-byte
cmp r1, #8
blt __ndsabi_memset1
@ Copy head to align to next word
rsb r3, r0, #4
joaobapt_test r3
strbmi r2, [r0], #1
submi r1, r1, #1
strbcs r2, [r0], #1
strbcs r2, [r0], #1
subcs r1, r1, #2
BEGIN_ASM_FUNC_NO_SECTION __aeabi_memset8
BEGIN_ASM_FUNC_NO_SECTION __aeabi_memset4
lsl r2, r2, #24
orr r2, r2, r2, lsr #8
orr r2, r2, r2, lsr #16
BEGIN_ASM_FUNC_NO_SECTION __ndsabi_wordset4
mov r3, r2
BEGIN_ASM_FUNC_NO_SECTION __ndsabi_lwordset4
@ 16 words is roughly the threshold when lwordset is slower
cmp r1, #64
blt .Lset_2_words
@ 8 word set
push {r4-r9}
mov r4, r2
mov r5, r3
mov r6, r2
mov r7, r3
mov r8, r2
mov r9, r3
.Lset_8_words:
subs r1, r1, #32
stmiage r0!, {r2-r9}
bgt .Lset_8_words
pop {r4-r9}
bxeq lr
@ Fixup remaining
add r1, r1, #32
.Lset_2_words:
subs r1, r1, #8
stmiage r0!, {r2-r3}
bgt .Lset_2_words
bxeq lr
@ Test for remaining word
adds r1, r1, #4
strge r2, [r0], #4
bxeq lr
@ Set tail
joaobapt_test r1
strhcs r2, [r0], #2
strbmi r2, [r0], #1
bx lr
BEGIN_ASM_FUNC __ndsabi_memset1
subs r1, r1, #1
strbge r2, [r0], #1
bgt __ndsabi_memset1
bx lr
BEGIN_ASM_FUNC memset
mov r3, r1
mov r1, r2
mov r2, r3
push {r0, lr}
bl __aeabi_memset
pop {r0, lr}
bx lr

106
common/ndsabi/rmemcpy.s Normal file
View File

@@ -0,0 +1,106 @@
// SPDX-License-Identifier: Zlib
// SPDX-FileNotice: Modified from the original version by the BlocksDS project.
//
// Copyright (C) 2021-2023 agbabi contributors
//
// Support:
// __ndsabi_rmemcpy, __ndsabi_rmemcpy1
#include <nds/asminc.h>
#include "macros.inc"
.syntax unified
.arm
BEGIN_ASM_FUNC __ndsabi_rmemcpy
@ >6-bytes is roughly the threshold when byte-by-byte copy is slower
cmp r2, #6
ble __ndsabi_rmemcpy1
align_switch r0, r1, r3, __ndsabi_rmemcpy1, .Lcopy_halves
@ Check if end needs word aligning
add r3, r0, r2
joaobapt_test r3
@ Copy byte tail to align
submi r2, r2, #1
ldrbmi r3, [r1, r2]
strbmi r3, [r0, r2]
@ r2 is now half aligned
@ Copy half tail to align
subcs r2, r2, #2
ldrhcs r3, [r1, r2]
strhcs r3, [r0, r2]
@ r2 is now word aligned
cmp r2, #32
blt .Lcopy_words
@ Word aligned, 32-byte copy
push {r0-r1, r4-r10}
add r0, r0, r2
add r1, r1, r2
.Lloop_32:
subs r2, r2, #32
ldmdbge r1!, {r3-r10}
stmdbge r0!, {r3-r10}
bgt .Lloop_32
pop {r0-r1, r4-r10}
bxeq lr
@ < 32 bytes remaining to be copied
add r2, r2, #32
.Lcopy_words:
subs r2, r2, #4
ldrge r3, [r1, r2]
strge r3, [r0, r2]
bgt .Lcopy_words
bxeq lr
@ Copy byte & half head
joaobapt_test_into r3, r2
@ Copy half
addcs r2, r2, #2
ldrhcs r3, [r1, r2]
strhcs r3, [r0, r2]
@ Copy byte
ldrbmi r3, [r1]
strbmi r3, [r0]
bx lr
.Lcopy_halves:
@ Copy byte tail to align
add r3, r0, r2
tst r3, #1
subne r2, r2, #1
ldrbne r3, [r1, r2]
strbne r3, [r0, r2]
@ r2 is now half aligned
.Lloop_2:
subs r2, r2, #2
ldrhge r3, [r1, r2]
strhge r3, [r0, r2]
bgt .Lloop_2
bxeq lr
@ Copy byte head
ldrb r3, [r1]
strb r3, [r0]
bx lr
BEGIN_ASM_FUNC_NO_SECTION __ndsabi_rmemcpy1
subs r2, r2, #1
ldrbge r3, [r1, r2]
strbge r3, [r0, r2]
bgt __ndsabi_rmemcpy1
bx lr

9
common/picoAgbAdapter.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#define PICO_AGB_PRINT_ARM9_RING ((vu16*)0x08000000)
#define PICO_AGB_PRINT_ARM9_READ_PTR (*(vu16*)0x08010000)
#define PICO_AGB_PRINT_ARM9_WRITE_PTR (*(vu16*)0x08010002)
#define PICO_AGB_PRINT_RING_LENGTH 0x8000
#define PICO_AGB_IDENTIFIER (*(vu32*)0x08010008)
#define PICO_AGB_IDENTIFIER_VALUE 0x4F434950

9
common/sections.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#define DEFINE_SECTION_SYMBOLS(sectionName) \
extern u8 __start_##sectionName[]; \
extern u8 __stop_##sectionName[]
#define SECTION_START(sectionName) ((void*)__start_##sectionName)
#define SECTION_END(sectionName) ((void*)__stop_##sectionName)
#define SECTION_SIZE(sectionName) ((u32)__stop_##sectionName - (u32)__start_##sectionName)

98
common/sharedMemory.h Normal file
View File

@@ -0,0 +1,98 @@
#pragma once
#include <nds/ndstypes.h>
#define BOOT_TYPE_INVALID 0
#define BOOT_TYPE_CARD 1
#define BOOT_TYPE_MULTIBOOT 2
#define BOOT_TYPE_NAND 3
#define BOOT_TYPE_MEMORY 4
struct shared_memory_multi_boot_info_t
{
u16 bootType;
u8 multibootInfo[0x40 - 2];
};
//0x02FFF800: 2KB
struct shared_memory_ntr_t
{
u8 gap0[0x200];
u8 gap200[0x80];
u8 cardRomHeader[0x160]; // without debug footer
u8 downloadParams[0x20];
u8 bootCheckInfo[0x20];
u32 resetParam;
u8 gap424[8];
u32 romOffset;
u8 slot2Info[0xC];
u32 vblankCounter;
shared_memory_multi_boot_info_t multibootInfo;
u8 firmwareUserData[0x100];
u8 arm9ExceptionStack[0x1C];
u32 arm9ExceptionVector;
u8 arenaInfo[0x48];
u8 rtcData[8];
u8 systemConfig[6];
u8 arm9Print;
u8 arm7Print;
u8 arm9ErrorPrint;
u8 arm7ErrorPrint;
u8 gap1FA[6];
u8 romHeader[0x160];
u8 isDebuggerData[0x20];
u32 arm9IpcSignalParam;
u32 arm7IpcSignalParam;
u32 arm9IpcHandleChecker;
u32 arm7IpcHandleChecker;
u32 lastMicrophoneAddress;
u16 microphoneSampleData;
u16 wifiCallbackControl;
u16 wifiRssiPool;
u8 setSlot2InfoOnce;
u8 slot2Inserted;
u32 arm7Param;
u32 arm9ThreadInfo;
u32 arm7ThreadInfo;
u16 padXYBuffer;
u8 touchData[4];
u16 autoloadSync;
u8 arm9LockId[8];
u8 arm7LockId[8];
u8 vramCLock[8];
u8 vramDLock[8];
u8 wram0Lock[8];
u8 wram1Lock[8];
u8 slot1Lock[8];
u8 slot2Lock[8];
u8 initLock[8];
u16 arm9MainMemoryCheck;
u16 arm7MainMemoryCheck;
u16 mainMemoryCmd;
};
static_assert(sizeof(shared_memory_ntr_t) == 0x800);
#define NTR_SHARED_MEMORY ((shared_memory_ntr_t*)0x027FF800)
#define NTR_SHARED_MEMORY_SDK5 ((shared_memory_ntr_t*)0x02FFF800)
//0x02FFC000: 16KB
struct shared_memory_twl_t
{
u8 twlCardRomHeader[0x1000];
u8 gap1000[0x7B0];
char sysMenuVersionInfoContentId[9];
char sysMenuVersionInfoContentLastInitialCode;
u16 sysMenuDisableSetHotboot;
u8 sdNandContext[0x44];
u8 titleIdList[0x400];
u8 mountInfo[0x3C0];
u8 bootSrlPath[0x40];
u8 twlRomHeader[0x1000];
u8 sharedArena[0x680];
u8 gap3680[0x180];
shared_memory_ntr_t ntrSharedMem;
};
static_assert(sizeof(shared_memory_twl_t) == 0x4000);
#define TWL_SHARED_MEMORY ((shared_memory_twl_t*)0x02FFC000)

View File

@@ -0,0 +1,35 @@
#pragma once
#define THUMB_R0 0
#define THUMB_R1 1
#define THUMB_R2 2
#define THUMB_R3 3
#define THUMB_R4 4
#define THUMB_R5 5
#define THUMB_R6 6
#define THUMB_R7 7
#define THUMB_HI_R8 8
#define THUMB_HI_R9 9
#define THUMB_HI_R10 10
#define THUMB_HI_R11 11
#define THUMB_HI_R12 12
#define THUMB_HI_SP 13
#define THUMB_HI_LR 14
#define THUMB_HI_PC 15
#define THUMB_LSLS_IMM(rd, rs, imm) (0x0000 | ((imm) << 6) | ((rs) << 3) | (rd))
#define THUMB_ADDS_IMM(rd, rs, imm) (0x1C00 | ((imm) << 6) | ((rs) << 3) | (rd))
#define THUMB_SUBS_IMM(rd, rs, imm) (0x1E00 | ((imm) << 6) | ((rs) << 3) | (rd))
#define THUMB_MOVS_IMM(rd, imm) (0x2000 | ((rd) << 8) | (imm))
#define THUMB_MOVS_REG(rd, rs) THUMB_ADDS_IMM((rd), (rs), 0)
#define THUMB_MOV_HIREG(rd, rs) (0x4600 | ((((rd) >> 3) & 1) << 7) | ((rs) << 3) | ((rd) & 7))
#define THUMB_NOP THUMB_MOV_HIREG(8, 8)
#define THUMB_BX(rs) (0x4700 | ((rs) << 3))
#define THUMB_BLX(rs) (0x4780 | ((rs) << 3))
#define THUMB_BX_LR THUMB_BX(THUMB_HI_LR)
#define THUMB_LDR_PC_IMM(rd, imm) (0x4800 | ((rd) << 8) | (((imm) >> 2) & 0xFF))
#define THUMB_STR_IMM(rd, rb, imm) (0x6000 | (((imm) >> 2) << 6) | ((rb) << 3) | (rd))
#define THUMB_STR_SP_IMM(rd, imm) (0x9000 | ((rd) << 8) | (((imm) >> 2) & 0xFF))
#define THUMB_LDR_SP_IMM(rd, imm) (0x9800 | ((rd) << 8) | (((imm) >> 2) & 0xFF))
#define THUMB_SVC(x) (0xDF00 | (x))