Initial commit

This commit is contained in:
Gericom
2025-11-22 17:21:45 +01:00
commit 5d6f67c612
517 changed files with 63025 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
#include "common.h"
#include <libtwl/timer/timer.h>
#include <libtwl/rtos/rtosIrq.h>
#include "TickCounter.h"
TickCounter gTickCounter;
void TickCounter::TimerOverflowIrq()
{
_msb += 1 << 16;
}
void TickCounter::Start()
{
_msb = 0;
tmr_configure(0, TMCNT_H_CLK_SYS_DIV_64, 0, true);
rtos_ackIrqMask(RTOS_IRQ_TIMER0);
rtos_setIrqFunc(RTOS_IRQ_TIMER0, [] (u32 mask) { gTickCounter.TimerOverflowIrq(); });
rtos_enableIrqMask(RTOS_IRQ_TIMER0);
tmr_start(0);
}
void TickCounter::Stop()
{
rtos_disableIrqMask(RTOS_IRQ_TIMER0);
rtos_setIrqFunc(RTOS_IRQ_TIMER0, nullptr);
tmr_stop(0);
}
u64 TickCounter::GetValue()
{
u32 irqs = rtos_disableIrqs();
u32 value0 = tmr_getCounter(0);
u64 msb = _msb;
u32 value1 = tmr_getCounter(0);
rtos_restoreIrqs(irqs);
if (value1 < value0)
value1 += 1 << 16;
return msb + value1;
}

26
common/core/TickCounter.h Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
class TickCounter
{
public:
void Start();
void Stop();
u64 GetValue();
static u32 TicksToMilliSeconds(u32 ticks)
{
return ((ticks * 8201887ULL) + (1ULL << 31)) >> 32;
}
static u32 TicksToMicroSeconds(u32 ticks)
{
return (ticks * 4100943703ULL + (1 << 30)) >> 31;
}
private:
u64 _msb = 0;
void TimerOverflowIrq();
};
extern TickCounter gTickCounter;

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

17
common/dldiIpcCommand.h Normal file
View File

@@ -0,0 +1,17 @@
#pragma once
typedef enum
{
DLDI_IPC_CMD_SETUP,
DLDI_IPC_CMD_READ_SECTORS,
DLDI_IPC_CMD_WRITE_SECTORS
} DldiIpcCommand;
typedef struct alignas(32)
{
u32 cmd;
void* buffer;
u32 sector;
u32 count;
u8 sizeAlign[16]; // ensure the size is also cache aligned
} dldi_ipc_cmd_t;

16
common/dsiSdIpcCommand.h Normal file
View File

@@ -0,0 +1,16 @@
#pragma once
typedef enum
{
DSI_SD_IPC_CMD_READ_SECTORS,
DSI_SD_IPC_CMD_WRITE_SECTORS
} DsiSdIpcCommand;
typedef struct alignas(32)
{
u32 cmd;
void* buffer;
u32 sector;
u32 count;
u8 sizeAlign[16]; // ensure the size is also cache aligned
} dsisd_ipc_cmd_t;

11
common/ipc/IpcService.cpp Normal file
View File

@@ -0,0 +1,11 @@
#include "common.h"
#include <libtwl/ipc/ipcFifoSystem.h>
#include "IpcService.h"
void IpcService::Start()
{
ipc_setChannelHandler(_ipcChannel, [] (u32 channel, u32 data, void* arg)
{
static_cast<IpcService*>(arg)->OnMessageReceived(data);
}, this);
}

19
common/ipc/IpcService.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
#include <libtwl/ipc/ipcFifoSystem.h>
class IpcService
{
const u32 _ipcChannel;
protected:
explicit IpcService(u32 ipcChannel)
: _ipcChannel(ipcChannel) { }
void SendResponseMessage(u32 data) const
{
ipc_sendFifoMessage(_ipcChannel, data);
}
public:
virtual void Start();
virtual void OnMessageReceived(u32 data) = 0;
};

View File

@@ -0,0 +1,33 @@
#include "common.h"
#include "ThreadIpcService.h"
void ThreadIpcService::ThreadMain()
{
while (true)
{
rtos_waitEvent(&_event, false, true);
if (_messageValid)
{
_messageValid = false;
HandleMessage(_message);
}
}
}
void ThreadIpcService::Start()
{
rtos_createEvent(&_event);
rtos_createThread(&_thread, 5, [] (void* arg)
{
static_cast<ThreadIpcService*>(arg)->ThreadMain();
}, this, _stack, _stackSize);
rtos_wakeupThread(&_thread);
IpcService::Start();
}
void ThreadIpcService::OnMessageReceived(u32 data)
{
_message = data;
_messageValid = true;
rtos_signalEvent(&_event);
}

View File

@@ -0,0 +1,26 @@
#pragma once
#include <libtwl/rtos/rtosThread.h>
#include <libtwl/rtos/rtosEvent.h>
#include "IpcService.h"
class ThreadIpcService : public IpcService
{
rtos_thread_t _thread;
rtos_event_t _event;
u32* _stack;
u32 _stackSize;
u8 _priority;
bool _messageValid = false;
u32 _message;
void ThreadMain();
public:
ThreadIpcService(u32 ipcChannel, u8 priority, u32* stack, u32 stackSize)
: IpcService(ipcChannel), _stack(stack), _stackSize(stackSize), _priority(priority) { }
void Start() override;
void OnMessageReceived(u32 data) override;
virtual void HandleMessage(u32 data);
};

7
common/ipcChannels.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
#define IPC_CHANNEL_DSI_SD 16
#define IPC_CHANNEL_DLDI 17
#define IPC_CHANNEL_LOADER 18
#define IPC_CHANNEL_SOUND 19
#define IPC_CHANNEL_RTC 20

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,47 @@
#include "common.h"
#include "NitroEmulatorOutputStream.h"
#define ISND_DBGINFO_ADDRESS 0x027FFF60
#define ISND_DBGINFO_AGB_ADDR_OFFSET 0x1C
#define ISND_DBGINFO_AGB_ADDR (*(u32*)(ISND_DBGINFO_ADDRESS + ISND_DBGINFO_AGB_ADDR_OFFSET))
#define ISND_AGB_PRINT_ARM9_WRITE_PTR_OFFSET 0x90
#define ISND_AGB_PRINT_ARM7_WRITE_PTR_OFFSET 0x92
#define ISND_AGB_PRINT_ARM9_READ_PTR_OFFSET 0x94
#define ISND_AGB_PRINT_ARM7_READ_PTR_OFFSET 0x96
#define ISND_AGB_SOMETHING_OFFSET 0xFE
#define ISND_AGB_PRINT_ARM9_RING_OFFSET 0x8000
#define ISND_AGB_PRINT_ARM7_RING_OFFSET 0xC000
#define ISND_AGB_PRINT_RING_LENGTH 0x4000
NitroEmulatorOutputStream::NitroEmulatorOutputStream()
{
#ifdef LIBTWL_ARM9
*(vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_SOMETHING_OFFSET) = 0x202;
#endif
}
void NitroEmulatorOutputStream::Write(const char* str)
{
#ifdef LIBTWL_ARM9
char c;
vu16* ring = (vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_PRINT_ARM9_RING_OFFSET);
u32 writePtr = *(vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_PRINT_ARM9_WRITE_PTR_OFFSET);
u32 readPtr = *(vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_PRINT_ARM9_READ_PTR_OFFSET);
while ((c = *str++) != 0)
{
u32 newWritePtr = (writePtr + 1) & (ISND_AGB_PRINT_RING_LENGTH - 1);
while (newWritePtr == readPtr)
{
*(vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_PRINT_ARM9_WRITE_PTR_OFFSET) = writePtr;
readPtr = *(vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_PRINT_ARM9_READ_PTR_OFFSET);
}
if (writePtr & 1)
ring[writePtr >> 1] = (ring[writePtr >> 1] & 0xFF) | (c << 8);
else
ring[writePtr >> 1] = (ring[writePtr >> 1] & 0xFF00) | c;
writePtr = newWritePtr;
}
*(vu16*)(ISND_DBGINFO_AGB_ADDR + ISND_AGB_PRINT_ARM9_WRITE_PTR_OFFSET) = writePtr;
#endif
}

View File

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

View File

@@ -0,0 +1,16 @@
#pragma once
#include "IOutputStream.h"
#define REG_NOCASH_STRING_OUT (*(vu32*)0x04FFFA10)
#define REG_NOCASH_CHAR_OUT (*(vu32*)0x04FFFA1C)
class NocashOutputStream : public IOutputStream
{
public:
void Write(const char* str) override
{
REG_NOCASH_STRING_OUT = (u32)str;
}
void Flush() override { }
};

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,28 @@
#include "common.h"
#include "picoAgbAdapter.h"
#include "PicoAgbAdapterOutputStream.h"
void PicoAgbAdapterOutputStream::Write(const char* str)
{
#ifdef LIBTWL_ARM9
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;
#endif
}

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 { }
};

View File

@@ -0,0 +1,26 @@
#pragma once
#include <memory>
#include "core/mini-printf.h"
#include "ILogger.h"
#include "IOutputStream.h"
class PlainLogger : public ILogger
{
LogLevel _maxLogLevel;
std::unique_ptr<IOutputStream> _outputStream;
char _logBuffer[512];
public:
PlainLogger(LogLevel maxLogLevel, std::unique_ptr<IOutputStream> outputStream)
: _maxLogLevel(maxLogLevel), _outputStream(std::move(outputStream))
{ }
void LogV(LogLevel level, const char* fmt, va_list vlist) override
{
if (level > _maxLogLevel)
return;
mini_vsnprintf(_logBuffer, sizeof(_logBuffer), fmt, vlist);
_outputStream->Write(_logBuffer);
}
};

View File

@@ -0,0 +1,26 @@
#pragma once
#include <memory>
#include <libtwl/rtos/rtosMutex.h>
#include "ILogger.h"
class ThreadSafeLogger : public ILogger
{
std::unique_ptr<ILogger> _logger;
rtos_mutex_t _mutex;
public:
explicit ThreadSafeLogger(std::unique_ptr<ILogger> logger)
: _logger(std::move(logger))
{
rtos_createMutex(&_mutex);
}
void LogV(LogLevel level, const char* fmt, va_list vlist) override
{
rtos_lockMutex(&_mutex);
{
_logger->LogV(level, fmt, vlist);
}
rtos_unlockMutex(&_mutex);
}
};

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

55
common/picoLoader7.h Normal file
View File

@@ -0,0 +1,55 @@
#pragma once
/// @brief The Pico Loader API version supported by this header file.
#define PICO_LOADER_API_VERSION 1
/// @brief Enum to specify the drive to boot from.
typedef enum
{
/// @brief Flashcard through DLDI.
PLOAD_BOOT_DRIVE_DLDI = 0,
/// @brief DSi SD card.
PLOAD_BOOT_DRIVE_DSI_SD = 1,
/// @brief AGB semihosting on the IS-NITRO-EMULATOR.
PLOAD_BOOT_DRIVE_AGB_SEMIHOSTING = 2,
/// @brief Flag to indicate that a multiboot rom needs to be loaded that is already in memory.
PLOAD_BOOT_DRIVE_MULTIBOOT_FLAG = 1u << 15
} PicoLoaderBootDrive;
/// @brief Struct containing the load params.
typedef struct
{
/// @brief The path of the rom to load.
char romPath[256];
/// @brief The path to the save file to use.
char savePath[256];
/// @brief The actual length of the argv arguments buffer.
u32 argumentsLength;
/// @brief Argv arguments buffer.
char arguments[256];
} pload_params_t;
/// @brief Struct representing the header of picoLoader7.bin.
typedef struct
{
/// @brief Pointer to the Pico Loader arm7 entry point (read-only).
void* const entryPoint;
/// @brief Sets the DLDI driver to use.
void* dldiDriver;
/// @brief Sets the boot drive. See \see PicoLoaderBootDrive.
u16 bootDrive;
/// @brief The supported Pico Loader API version (read-only).
const u16 apiVersion;
/// @brief The load params, see \see pload_params_t.
pload_params_t loadParams;
} pload_header7_t;

3
common/sharedMemory.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
#define SHARED_KEY_XY (*(vu16*)0x02FFFFA8)

19
common/soundIpcCommand.h Normal file
View File

@@ -0,0 +1,19 @@
#pragma once
enum SoundIpcCommand
{
SND_IPC_CMD_START_CHANNELS,
SND_IPC_CMD_STOP_CHANNELS,
SND_IPC_CMD_SETUP_CHANNEL
};
struct snd_ipc_cmd_setup_channel_t
{
u32 cmd : 8;
u32 channel : 24;
const void* sourceAddress;
u32 timer;
u32 loopStart;
u32 length;
u32 control;
};