Removed hardcoded libn3ds.

This commit is contained in:
profi200 2022-06-29 15:55:07 +02:00
parent ee21e3edb0
commit bd6bc4fd54
No known key found for this signature in database
GPG Key ID: 17B42AE5911139F3
165 changed files with 6 additions and 48606 deletions

View File

@ -8,6 +8,7 @@ endif
TOPDIR ?= $(CURDIR)
include $(DEVKITARM)/base_rules
include $(TOPDIR)/../libn3ds/libn3ds11.mk
#---------------------------------------------------------------------------------
# TARGET is the name of the output
@ -18,13 +19,9 @@ include $(DEVKITARM)/base_rules
#---------------------------------------------------------------------------------
#TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := ../libn3ds/kernel/source ../libn3ds/source ../libn3ds/source/drivers/mmc \
../libn3ds/source/drivers ../libn3ds/source/arm11 ../libn3ds/source/arm11/allocator \
../libn3ds/source/arm11/drivers ../libn3ds/source/arm11/util/rbtree ../source/arm11 \
../thirdparty/inih
SOURCES += ../source/arm11 ../thirdparty/inih
DATA :=
INCLUDES := ../libn3ds/include ../libn3ds/kernel/include ../libn3ds/thirdparty ../include \
../thirdparty
INCLUDES += ../include ../thirdparty
DEFINES := -DARM11 -D_3DS -DVERS_STRING=\"$(VERS_STRING)\" \
-DVERS_MAJOR=$(VERS_MAJOR) -DVERS_MINOR=$(VERS_MINOR)
ASSETS :=

View File

@ -8,6 +8,7 @@ endif
TOPDIR ?= $(CURDIR)
include $(DEVKITARM)/base_rules
include $(TOPDIR)/../libn3ds/libn3ds9.mk
#---------------------------------------------------------------------------------
# TARGET is the name of the output
@ -18,10 +19,9 @@ include $(DEVKITARM)/base_rules
#---------------------------------------------------------------------------------
#TARGET := $(notdir $(CURDIR))
BUILD := build
SOURCES := ../libn3ds/source ../libn3ds/source/drivers/mmc ../libn3ds/source/drivers ../libn3ds/source/arm9 \
../libn3ds/source/arm9/drivers ../libn3ds/thirdparty/fatfs ../source/arm9
SOURCES += ../source/arm9
DATA :=
INCLUDES := ../libn3ds/include ../libn3ds/thirdparty ../include ../thirdparty
INCLUDES += ../include ../thirdparty
DEFINES := -DARM9 -D_3DS -DVERS_STRING=\"$(VERS_STRING)\" \
-DVERS_MAJOR=$(VERS_MAJOR) -DVERS_MINOR=$(VERS_MINOR)

View File

@ -1,324 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !__ASSEMBLER__
#include "types.h"
#endif
// Program status register (CPSR/SPSR)
#define PSR_USER_MODE (16)
#define PSR_FIQ_MODE (17)
#define PSR_IRQ_MODE (18)
#define PSR_SVC_MODE (19)
#define PSR_ABORT_MODE (23)
#define PSR_UNDEF_MODE (27)
#define PSR_SYS_MODE (31)
#define PSR_MODE_MASK (PSR_SYS_MODE)
#define PSR_T (1<<5) // Thumb mode
#define PSR_F (1<<6) // Interrupts (FIQ) disable flag
#define PSR_I (1<<7) // Interrupts (IRQ) disable flag
#define PSR_A (1<<8) // Imprecise aborts disable flag
#define PSR_E (1<<9) // Big endian
#define PSR_J (1<<24) // Jazelle mode
#define PSR_Q (1<<27)
#define PSR_V (1<<28) // Overflow flag
#define PSR_C (1<<29) // Carry flag
#define PSR_Z (1<<30) // Zero flag
#define PSR_N (1<<31) // Negative flag
#define PSR_INT_OFF (PSR_I | PSR_F) // IRQ and FIQ disabled flags
#if !__ASSEMBLER__
#define MAKE_INTR_NO_INOUT(isVolatile, name, inst, ...) \
ALWAYS_INLINE void __##name(void) \
{ \
if(isVolatile == 1) \
__asm__ volatile(inst : : : __VA_ARGS__); \
else \
__asm__(inst : : : __VA_ARGS__); \
}
#define MAKE_INTR_GET_REG(isVolatile, name, inst) \
ALWAYS_INLINE u32 __##name(void) \
{ \
u32 reg; \
if(isVolatile == 1) \
__asm__ volatile(inst : "=r" (reg) : : ); \
else \
__asm__(inst : "=r" (reg) : : ); \
return reg; \
}
#define MAKE_INTR_SET_REG_ZERO(isVolatile, name, inst, ...) \
ALWAYS_INLINE void __##name(void) \
{ \
if(isVolatile == 1) \
__asm__ volatile(inst : : "r" (0) : __VA_ARGS__); \
else \
__asm__(inst : : "r" (0) : __VA_ARGS__); \
}
#define MAKE_INTR_SET_REG(isVolatile, name, inst, ...) \
ALWAYS_INLINE void __##name(u32 reg) \
{ \
if(isVolatile == 1) \
__asm__ volatile(inst : : "r" (reg) : __VA_ARGS__); \
else \
__asm__(inst : : "r" (reg) : __VA_ARGS__); \
}
#define __bkpt(val) __asm__ volatile("bkpt #" #val : : : )
#if !__thumb__
// Program status register
MAKE_INTR_GET_REG(1, getCpsr, "mrs %0, cpsr")
MAKE_INTR_SET_REG(1, setCpsr_c, "msr cpsr_c, %0", "memory")
MAKE_INTR_SET_REG(1, setCpsr, "msr cpsr_cxsf, %0", "memory")
MAKE_INTR_GET_REG(1, getSpsr, "mrs %0, spsr")
MAKE_INTR_SET_REG(1, setSpsr_c, "msr spsr_c, %0", "memory")
MAKE_INTR_SET_REG(1, setSpsr, "msr spsr_cxsf, %0", "memory")
// Control Register
MAKE_INTR_GET_REG(1, getCr, "mrc p15, 0, %0, c1, c0, 0")
MAKE_INTR_SET_REG(1, setCr, "mcr p15, 0, %0, c1, c0, 0", "memory")
#endif // if !__thumb__
#ifdef ARM11
#define __cpsid(flags) __asm__ volatile("cpsid " #flags : : : "memory")
#define __cpsie(flags) __asm__ volatile("cpsie " #flags : : : "memory")
#define __setend(end) __asm__ volatile("setend " #end : : : "memory")
MAKE_INTR_NO_INOUT(1, nop, "nop")
MAKE_INTR_NO_INOUT(1, wfi, "wfi", "memory")
MAKE_INTR_NO_INOUT(1, wfe, "wfe", "memory")
MAKE_INTR_NO_INOUT(1, sev, "sev")
#if !__thumb__
ALWAYS_INLINE u8 __ldrexb(vu8 *addr)
{
u8 res;
__asm__ volatile("ldrexb %0, %1" : "=r" (res) : "Q" (*addr) : );
return res;
}
ALWAYS_INLINE u16 __ldrexh(vu16 *addr)
{
u16 res;
__asm__ volatile("ldrexh %0, %1" : "=r" (res) : "Q" (*addr) : );
return res;
}
ALWAYS_INLINE u32 __ldrex(vu32 *addr)
{
u32 res;
__asm__ volatile("ldrex %0, %1" : "=r" (res) : "Q" (*addr) : );
return res;
}
/*ALWAYS_INLINE u64 __ldrexd(vu64 *addr)
{
union
{
u32 r32[2];
u64 r64;
} r;
// TODO: "Error: even register required -- `ldrexd r3,r2,[r0]'"
#ifndef __ARMEB__ // Little endian
__asm__ volatile("ldrexd %0, %1, %2" : "=r" (r.r32[0]), "=r" (r.r32[1]) : "Q" (*addr) : );
#else // Big endian
__asm__ volatile("ldrexd %0, %1, %2" : "=r" (r.r32[1]), "=r" (r.r32[0]) : "Q" (*addr) : );
#endif
return r.r64;
}*/
ALWAYS_INLINE u32 __strexb(vu8 *addr, u8 val)
{
u32 res;
__asm__ volatile("strexb %0, %2, %1" : "=&r" (res), "=Q" (*addr) : "r" (val) : );
return res;
}
ALWAYS_INLINE u32 __strexh(vu16 *addr, u16 val)
{
u32 res;
__asm__ volatile("strexh %0, %2, %1" : "=&r" (res), "=Q" (*addr) : "r" (val) : );
return res;
}
ALWAYS_INLINE u32 __strex(vu32 *addr, u32 val)
{
u32 res;
__asm__ volatile("strex %0, %2, %1" : "=&r" (res), "=Q" (*addr) : "r" (val) : );
return res;
}
/*ALWAYS_INLINE u32 __strexd(vu64 *addr, u64 val)
{
union
{
u32 r32[2];
u64 r64;
} r;
r.r64 = val;
// TODO: "Error: even register required -- `strexd r0,r3,r2,[r1]'"
u32 res;
#ifndef __ARMEB__ // Little endian
__asm__ volatile("strexd %0, %2, %3, %1" : "=&r" (res), "=Q" (*addr) : "r" (r.r32[0]), "r" (r.r32[1]) : );
#else // Big endian
__asm__ volatile("strexd %0, %2, %3, %1" : "=&r" (res), "=Q" (*addr) : "r" (r.r32[1]), "r" (r.r32[0]) : );
#endif
return res;
}*/
MAKE_INTR_NO_INOUT(1, clrex, "clrex", "memory")
// Debug ID Register
MAKE_INTR_GET_REG(0, getDidr, "mrc p14, 0, %0, c0, c0, 0")
// Debug Status and Control Register
MAKE_INTR_GET_REG(1, getDscr, "mrc p14, 0, %0, c0, c1, 0")
MAKE_INTR_SET_REG(1, setDscr, "mcr p14, 0, %0, c0, c1, 0", "memory")
// Data Transfer Register
// Vector Catch Register
MAKE_INTR_GET_REG(1, getVcr, "mrc p14, 0, %0, c0, c7, 0")
MAKE_INTR_SET_REG(1, setVcr, "mcr p14, 0, %0, c0, c7, 0", "memory")
// Breakpoint Value Register 0-5
MAKE_INTR_GET_REG(1, getBvr0, "mrc p14, 0, %0, c0, c0, 4")
MAKE_INTR_SET_REG(1, setBvr0, "mcr p14, 0, %0, c0, c0, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr1, "mrc p14, 0, %0, c0, c1, 4")
MAKE_INTR_SET_REG(1, setBvr1, "mcr p14, 0, %0, c0, c1, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr2, "mrc p14, 0, %0, c0, c2, 4")
MAKE_INTR_SET_REG(1, setBvr2, "mcr p14, 0, %0, c0, c2, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr3, "mrc p14, 0, %0, c0, c3, 4")
MAKE_INTR_SET_REG(1, setBvr3, "mcr p14, 0, %0, c0, c3, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr4, "mrc p14, 0, %0, c0, c4, 4")
MAKE_INTR_SET_REG(1, setBvr4, "mcr p14, 0, %0, c0, c4, 4", "memory")
MAKE_INTR_GET_REG(1, getBvr5, "mrc p14, 0, %0, c0, c5, 4")
MAKE_INTR_SET_REG(1, setBvr5, "mcr p14, 0, %0, c0, c5, 4", "memory")
// Breakpoint Control Register 0-5
MAKE_INTR_GET_REG(1, getBcr0, "mrc p14, 0, %0, c0, c0, 5")
MAKE_INTR_SET_REG(1, setBcr0, "mcr p14, 0, %0, c0, c0, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr1, "mrc p14, 0, %0, c0, c1, 5")
MAKE_INTR_SET_REG(1, setBcr1, "mcr p14, 0, %0, c0, c1, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr2, "mrc p14, 0, %0, c0, c2, 5")
MAKE_INTR_SET_REG(1, setBcr2, "mcr p14, 0, %0, c0, c2, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr3, "mrc p14, 0, %0, c0, c3, 5")
MAKE_INTR_SET_REG(1, setBcr3, "mcr p14, 0, %0, c0, c3, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr4, "mrc p14, 0, %0, c0, c4, 5")
MAKE_INTR_SET_REG(1, setBcr4, "mcr p14, 0, %0, c0, c4, 5", "memory")
MAKE_INTR_GET_REG(1, getBcr5, "mrc p14, 0, %0, c0, c5, 5")
MAKE_INTR_SET_REG(1, setBcr5, "mcr p14, 0, %0, c0, c5, 5", "memory")
// Watchpoint Value Register 0-1
MAKE_INTR_GET_REG(1, getWvr0, "mrc p14, 0, %0, c0, c0, 6")
MAKE_INTR_SET_REG(1, setWvr0, "mcr p14, 0, %0, c0, c0, 6", "memory")
MAKE_INTR_GET_REG(1, getWvr1, "mrc p14, 0, %0, c0, c1, 6")
MAKE_INTR_SET_REG(1, setWvr1, "mcr p14, 0, %0, c0, c1, 6", "memory")
// Watchpoint Control Register 0-1
MAKE_INTR_GET_REG(1, getWcr0, "mrc p14, 0, %0, c0, c0, 7")
MAKE_INTR_SET_REG(1, setWcr0, "mcr p14, 0, %0, c0, c0, 7", "memory")
MAKE_INTR_GET_REG(1, getWcr1, "mrc p14, 0, %0, c0, c1, 7")
MAKE_INTR_SET_REG(1, setWcr1, "mcr p14, 0, %0, c0, c1, 7", "memory")
ALWAYS_INLINE u32 __getCpuId(void)
{
u32 cpuId;
__asm__("mrc p15, 0, %0, c0, c0, 5" : "=r" (cpuId) : );
return cpuId & 3;
}
// Auxiliary Control Register
MAKE_INTR_GET_REG(1, getAcr, "mrc p15, 0, %0, c1, c0, 1")
MAKE_INTR_SET_REG(1, setAcr, "mcr p15, 0, %0, c1, c0, 1", "memory")
// Translation Table Base Register 0
MAKE_INTR_GET_REG(1, getTtbr0, "mrc p15, 0, %0, c2, c0, 0")
MAKE_INTR_SET_REG(1, setTtbr0, "mcr p15, 0, %0, c2, c0, 0", "memory")
// Translation Table Base Register 1
MAKE_INTR_GET_REG(1, getTtbr1, "mrc p15, 0, %0, c2, c0, 1")
MAKE_INTR_SET_REG(1, setTtbr1, "mcr p15, 0, %0, c2, c0, 1", "memory")
// Translation Table Base Control Register
MAKE_INTR_GET_REG(1, getTtbcr, "mrc p15, 0, %0, c2, c0, 2")
MAKE_INTR_SET_REG(1, setTtbcr, "mcr p15, 0, %0, c2, c0, 2", "memory")
// Domain Access Control Register
MAKE_INTR_GET_REG(1, getDacr, "mrc p15, 0, %0, c3, c0, 0")
MAKE_INTR_SET_REG(1, setDacr, "mcr p15, 0, %0, c3, c0, 0", "memory")
// Data Fault Status Register
MAKE_INTR_GET_REG(1, getDfsr, "mrc p15, 0, %0, c5, c0, 0")
MAKE_INTR_SET_REG(1, setDfsr, "mcr p15, 0, %0, c5, c0, 0", "memory")
// Instruction Fault Status Register
MAKE_INTR_GET_REG(1, getIfsr, "mrc p15, 0, %0, c5, c0, 1")
MAKE_INTR_SET_REG(1, setIfsr, "mcr p15, 0, %0, c5, c0, 1", "memory")
// Fault Address Register
MAKE_INTR_GET_REG(1, getFar, "mrc p15, 0, %0, c6, c0, 0")
MAKE_INTR_SET_REG(1, setFar, "mcr p15, 0, %0, c6, c0, 0", "memory")
// Watchpoint Fault Address Register
MAKE_INTR_GET_REG(1, getWfar, "mrc p15, 0, %0, c6, c0, 1")
MAKE_INTR_SET_REG(1, setWfar, "mcr p15, 0, %0, c6, c0, 1", "memory")
// Flush Prefetch Buffer
// Data Synchronization Barrier
// Data Memory Barrier
MAKE_INTR_SET_REG_ZERO(1, isb, "mcr p15, 0, %0, c7, c5, 4", "memory")
MAKE_INTR_SET_REG_ZERO(1, dsb, "mcr p15, 0, %0, c7, c10, 4", "memory")
MAKE_INTR_SET_REG_ZERO(1, dmb, "mcr p15, 0, %0, c7, c10, 5", "memory")
// FCSE PID Register
MAKE_INTR_GET_REG(1, getFcsepidr, "mrc p15, 0, %0, c13, c0, 0")
MAKE_INTR_SET_REG(1, setFcsepidr, "mcr p15, 0, %0, c13, c0, 0", "memory")
// Context ID Register
MAKE_INTR_GET_REG(1, getCidr, "mrc p15, 0, %0, c13, c0, 1")
MAKE_INTR_SET_REG(1, setCidr, "mcr p15, 0, %0, c13, c0, 1", "memory")
#endif // if !__thumb__
#elif ARM9
#if !__thumb__
MAKE_INTR_NO_INOUT(1, wfi, "mcr p15, 0, r0, c7, c0, 4", "memory")
#endif // if !__thumb__
#endif // ifdef ARM11
#undef MAKE_INTR_NO_INOUT
#undef MAKE_INTR_GET_REG
#undef MAKE_INTR_SET_REG_ZERO
#undef MAKE_INTR_SET_REG
#endif // if !__ASSEMBLER__

View File

@ -1,47 +0,0 @@
/**
* @file vram.h
* @brief VRAM allocator.
*/
#pragma once
/**
* @brief Allocates a 0x80-byte aligned buffer.
* @param size Size of the buffer to allocate.
* @return The allocated buffer.
*/
void* vramAlloc(size_t size);
/**
* @brief Allocates a buffer aligned to the given size.
* @param size Size of the buffer to allocate.
* @param alignment Alignment to use.
* @return The allocated buffer.
*/
void* vramMemAlign(size_t size, size_t alignment);
/**
* @brief Reallocates a buffer.
* Note: Not implemented yet.
* @param mem Buffer to reallocate.
* @param size Size of the buffer to allocate.
* @return The reallocated buffer.
*/
void* vramRealloc(void* mem, size_t size);
/**
* @brief Retrieves the allocated size of a buffer.
* @return The size of the buffer.
*/
size_t vramGetSize(void* mem);
/**
* @brief Frees a buffer.
* @param mem Buffer to free.
*/
void vramFree(void* mem);
/**
* @brief Gets the current VRAM free space.
* @return The current VRAM free space.
*/
u32 vramSpaceFree(void);

View File

@ -1,192 +0,0 @@
#pragma once
/*
* This code is part of libctru (https://github.com/devkitPro/libctru)
*/
/**
* @file console.h
* @brief 3ds stdio support.
*
* Provides stdio integration for printing to the 3DS screen as well as debug print
* functionality provided by stderr.
*
* General usage is to initialize the console by:
* @code
* consoleDemoInit()
* @endcode
* or to customize the console usage by:
* @code
* consoleInit()
* @endcode
*/
#include "types.h"
#include "drivers/gfx.h"
#ifdef __cplusplus
extern "C" {
#endif
#define CONSOLE_ESC(x) "\x1b[" #x
#define CONSOLE_RESET CONSOLE_ESC(0m)
#define CONSOLE_BLACK CONSOLE_ESC(30m)
#define CONSOLE_RED CONSOLE_ESC(31;1m)
#define CONSOLE_GREEN CONSOLE_ESC(32;1m)
#define CONSOLE_YELLOW CONSOLE_ESC(33;1m)
#define CONSOLE_BLUE CONSOLE_ESC(34;1m)
#define CONSOLE_MAGENTA CONSOLE_ESC(35;1m)
#define CONSOLE_CYAN CONSOLE_ESC(36;1m)
#define CONSOLE_WHITE CONSOLE_ESC(37;1m)
/// A callback for printing a character.
typedef bool(*ConsolePrint)(void* con, int c);
/// A font struct for the console.
typedef struct ConsoleFont
{
const u8* gfx; ///< A pointer to the font graphics
u16 asciiOffset; ///< Offset to the first valid character in the font table
u16 numChars; ///< Number of characters in the font graphics
}ConsoleFont;
/**
* @brief Console structure used to store the state of a console render context.
*
* Default values from consoleGetDefault();
* @code
* PrintConsole defaultConsole =
* {
* //Font:
* {
* (u8*)default_font_bin, //font gfx
* 0, //first ascii character in the set
* 128, //number of characters in the font set
* },
* 0,0, //cursorX cursorY
* 0,0, //prevcursorX prevcursorY
* 40, //console width
* 30, //console height
* 0, //window x
* 0, //window y
* 32, //window width
* 24, //window height
* 3, //tab size
* 0, //font character offset
* 0, //print callback
* false //console initialized
* };
* @endcode
*/
typedef struct PrintConsole
{
ConsoleFont font; ///< Font of the console
u16 *frameBuffer; ///< Framebuffer address
int cursorX; ///< Current X location of the cursor (as a tile offset by default)
int cursorY; ///< Current Y location of the cursor (as a tile offset by default)
int prevCursorX; ///< Internal state
int prevCursorY; ///< Internal state
int consoleWidth; ///< Width of the console hardware layer in characters
int consoleHeight; ///< Height of the console hardware layer in characters
int windowX; ///< Window X location in characters (not implemented)
int windowY; ///< Window Y location in characters (not implemented)
int windowWidth; ///< Window width in characters (not implemented)
int windowHeight; ///< Window height in characters (not implemented)
int tabSize; ///< Size of a tab
int fg; ///< Foreground color
int bg; ///< Background color
int flags; ///< Reverse/bright flags
ConsolePrint PrintChar; ///< Callback for printing a character. Should return true if it has handled rendering the graphics (else the print engine will attempt to render via tiles).
bool consoleInitialised; ///< True if the console is initialized
}PrintConsole;
#define CONSOLE_COLOR_BOLD (1<<0) ///< Bold text
#define CONSOLE_COLOR_FAINT (1<<1) ///< Faint text
#define CONSOLE_ITALIC (1<<2) ///< Italic text
#define CONSOLE_UNDERLINE (1<<3) ///< Underlined text
#define CONSOLE_BLINK_SLOW (1<<4) ///< Slow blinking text
#define CONSOLE_BLINK_FAST (1<<5) ///< Fast blinking text
#define CONSOLE_COLOR_REVERSE (1<<6) ///< Reversed color text
#define CONSOLE_CONCEAL (1<<7) ///< Concealed text
#define CONSOLE_CROSSED_OUT (1<<8) ///< Crossed out text
/// Console debug devices supported by libnds.
typedef enum {
debugDevice_NULL, ///< Swallows prints to stderr
debugDevice_3DMOO, ///< Directs stderr debug statements to 3dmoo
debugDevice_CONSOLE, ///< Directs stderr debug statements to 3DS console window
} debugDevice;
/**
* @brief Loads the font into the console.
* @param console Pointer to the console to update, if NULL it will update the current console.
* @param font The font to load.
*/
void consoleSetFont(PrintConsole* console, ConsoleFont* font);
/**
* @brief Sets the print window.
* @param console Console to set, if NULL it will set the current console window.
* @param x X location of the window.
* @param y Y location of the window.
* @param width Width of the window.
* @param height Height of the window.
*/
void consoleSetWindow(PrintConsole* console, int x, int y, int width, int height);
/**
* @brief Gets a pointer to the console with the default values.
* This should only be used when using a single console or without changing the console that is returned, otherwise use consoleInit().
* @return A pointer to the console with the default values.
*/
PrintConsole* consoleGetDefault(void);
/**
* @brief Make the specified console the render target.
* @param console A pointer to the console struct (must have been initialized with consoleInit(PrintConsole* console)).
* @return A pointer to the previous console.
*/
PrintConsole *consoleSelect(PrintConsole* console);
/**
* @brief Returns the currently used console.
* @return A pointer to the current console.
*/
PrintConsole *consoleGet(void);
/**
* @brief Returns the currently used foreground color.
* @return The foreground color in RGB565.
*/
u16 consoleGetFgColor(void);
/**
* @brief Initialise the console.
* @param screen The screen to use for the console.
* @param console A pointer to the console data to initialize (if it's NULL, the default console will be used).
* @return A pointer to the current console.
*/
PrintConsole* consoleInit(u8 screen, PrintConsole* console);
/// Clears the screan by using iprintf("\x1b[2J");
void consoleClear(void);
void consoleSetCursor(PrintConsole* console, int x, int y);
void drawConsoleWindow(PrintConsole* console, int thickness, u8 colorIndex);
u16 consoleGetRGB565Color(u8 colorIndex);
ssize_t con_write(UNUSED struct _reent *r,UNUSED void *fd,const char *ptr, size_t len);
#ifdef __cplusplus
}
#endif

View File

@ -1,50 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
noreturn void panic(void);
noreturn void panicMsg(const char *msg);
// Exception tests
/*static inline regTest(void)
{
__asm__ volatile("mov r0, #1\n\tmov r1, #2\n\tmov r2, #3\n\tmov r3, #4\n\tmov r4, #5\n\t"
"mov r5, #6\n\tmov r6, #7\n\tmov r7, #8\n\tmov r8, #9\n\tmov r9, #10\n\t"
"mov r10, #11\n\tmov r11, #12\n\tmov r12, #13\n\tmov r13, #14\n\t"
"mov r14, #15\n\tmov r15, #16\n\t" : :);
}
static inline breakpointTest(void)
{
__asm__ volatile("bkpt #0xCAFE" : :);
}
static inline dataAbortTest(void)
{
__asm__ volatile("mov r0, #4\n\tmov r1, #0xEF\n\tstr r1, [r0]" : :);
}
static inline undefInstrTest(void)
{
__asm__ volatile("udf #0xDEAD" : :);
}*/

View File

@ -1,123 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#define CFG11_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x40000)
typedef struct
{
vu8 sharedwram_32k_code[8]; // 0x000
vu8 sharedwram_32k_data[8]; // 0x008
u8 _0x10[0xf0];
vu32 nullpage_cnt; // 0x100
vu8 fiq_mask; // 0x104
vu8 unk105; // 0x105 Debug related? Mask?
u8 _0x106[2];
vu8 unk108; // 0x108 LGY gamecard related?
u8 _0x109[3];
vu8 cdma_cnt; // 0x10C
u8 _0x10d[3];
vu8 unk110; // 0x110 VRAM related?
u8 _0x111[0x2f];
vu16 gpuprot; // 0x140
u8 _0x142[0x3e];
vu8 wifi_power; // 0x180 Used for flight mode?
u8 _0x181[0x3f];
vu16 spi_cnt; // 0x1C0
u8 _0x1c2[0x3e];
vu32 unk200; // 0x200 GPIO3 related? 8x4 bits.
u8 _0x204[0x1fc];
vu8 gpu_n3ds_cnt; // 0x400 New3DS-only.
u8 _0x401[0xf];
vu32 cdma_peripherals; // 0x410 New3DS-only.
u8 _0x414[0xc];
vu8 bootrom_overlay_cnt; // 0x420 New3DS-only.
u8 _0x421[3];
vu32 bootrom_overlay_val; // 0x424 New3DS-only.
vu8 unk428; // 0x429 New3DS-only. 1 bit. Enable CPU core 1 access to overlay regs?
u8 _0x429[0xbd3];
const vu16 socinfo; // 0xFFC
} Cfg11;
static_assert(offsetof(Cfg11, socinfo) == 0xFFC, "Error: Member socinfo of Cfg11 is not at offset 0xFFC!");
ALWAYS_INLINE Cfg11* getCfg11Regs(void)
{
return (Cfg11*)CFG11_REGS_BASE;
}
// REG_CFG11_NULLPAGE_CNT
#define NULLPAGE_CNT_FAULT_EN (1u) // All data accesses to 0x000-0xFFF generate data aborts.
#define NULLPAGE_CNT_ACCESSED (1u<<16) // 0x000-0xFFF has been accessed flag. Write 0 to clear.
// REG_CFG11_FIQ_MASK
// Each bit 1 = masked/disabled.
#define FIQ_MASK_CPU0 (1u)
#define FIQ_MASK_CPU1 (1u<<1)
#define FIQ_MASK_CPU2 (1u<<2) // New3DS-only.
#define FIQ_MASK_CPU3 (1u<<3) // New3DS-only.
// REG_CFG11_CDMA_CNT
#define CDMA_CNT_MIC_EN (1u)
#define CDMA_CNT_NTRCARD_EN (1u<<1)
#define CDMA_CNT_CAM1_EN (1u<<2)
#define CDMA_CNT_CAM2_EN (1u<<3)
#define CDMA_CNT_TOSHSD2_EN (1u<<4) // WiFi
#define CDMA_CNT_TOSHSD3_EN (1u<<5)
// REG_CFG11_GPUPROT
// When the lower FCRAM protection is set to non-zero,
// the first 0x800000 bytes of upper FCRAM are protected.
#define GPUPROT_FCRAM_LO(x) (x) // Protect lower 128 MiB of FCRAM (0x28000000-(0x800000*x)).
#define GPUPROT_FCRAM_UP(x) ((x)<<4) // Protect upper 128 MiB of FCRAM (0x30000000-(0x800000*x)) (New3DS-only).
#define GPUPROT_AXIWRAM (1u<<8) // Protect AXIWRAM.
#define GPUPROT_QTM(x) ((x)<<9) // Protect QTM RAM (0x1F400000-(0x100000*x)). 2 bits. TODO: Confirm this.
#define GPUPROT_NO_PROT (0u)
#define GPUPROT_PROT_ALL (GPUPROT_QTM(3u) | GPUPROT_AXIWRAM | \
GPUPROT_FCRAM_UP(15u) | GPUPROT_FCRAM_LO(15u))
// REG_CFG11_WIFI_POWER
#define WIFI_POWER_ON (1u)
// REG_CFG11_SPI_CNT
#define SPI_CNT_SPI1_NEW_IF (1u) // New interface (NSPI).
#define SPI_CNT_SPI2_NEW_IF (1u<<1)
#define SPI_CNT_SPI3_NEW_IF (1u<<2)
// REG_CFG11_GPU_N3DS_CNT
#define GPU_N3DS_CNT_N3DS_MODE (1u) // Enable access to mem extensions.
#define GPU_N3DS_CNT_TEX_FIX (1u<<1) // Fixes some texture glitches in New3DS mode.
// REG_CFG11_CDMA_PERIPHERALS
// Each bit 1 = DMA requests go to CDMA2.
// TODO: Add individual periphals.
#define CDMA_PERIPHERALS_ALL (0x3FFFFu)
// REG_CFG11_BOOTROM_OVERLAY_CNT
#define BOOTROM_OVERLAY_CNT_EN (1u)
// REG_CFG11_SOCINFO
#define SOCINFO_CTR (1u) // Also set on New 3DS.
#define SOCINFO_LGR1 (1u<<1) // Never saw the daylight? Set on retail N3DS (LGR2).
#define SOCINFO_LGR2 (1u<<2) // Set on New 3DS.

View File

@ -1,56 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
typedef struct
{
u16 touchX[5];
u16 touchY[5];
u16 cpadY[8];
u16 cpadX[8];
} CdcAdcData;
/**
* @brief Initialize CODEC for Circle-Pad/Touchscreen/Sound.
*/
void CODEC_init(void);
/**
* @brief Deinitializes the CODEC chip for sleep or poweroff.
*/
void CODEC_deinit(void);
/**
* @brief The opposite of CODEC_deinit(). Does a partial init.
*/
void CODEC_wakeup(void);
/**
* @brief Get raw ADC data for Circle-Pad/Touchscreen.
*
* @param data The output data pointer. Must be 4 bytes aligned.
*
* @return Returns true if data was available and false otherwise.
*/
bool CODEC_getRawAdcData(CdcAdcData *data);

View File

@ -1,321 +0,0 @@
#pragma once
// Based on Texas Instruments TSC2117 SLAS550B.
// Adjusted for the custom Texas Instruments PAIC3010B, AIC3010B, AIC3010D
// and possibly other variants.
enum
{
CDC_REG_PAGE_CTRL = 0u, // Available on every page.
// ----------------------------------------------------------------------------------
// Control Registers, Page 0 (Default Page):
// Clock Multipliers, Dividers, Serial Interfaces, Flags, Interrupts, and GPIOs.
CDC_REG_SOFT_RST_TWL = 1u,
CDC_REG_0_2 = 2u, // Vendor and device ID?
CDC_REG_0_3 = 3u, // Revision?
CDC_REG_CLK_GEN_MUXING = 4u,
CDC_REG_PLL_P_R_VAL = 5u,
CDC_REG_PLL_J_VAL = 6u,
CDC_REG_PLL_D_VAL_MSB = 7u,
CDC_REG_PLL_D_VAL_LSB = 8u,
// 9-10 reserved.
CDC_REG_DAC_NDAC_VAL = 11u,
CDC_REG_DAC_MDAC_VAL = 12u,
// 13 DAC DOSR_VAL MSB?
// 14 DAC DOSR_VAL LSB?
// 15 DAC IDAC_VAL?
// 16 DAC miniDSP Engine Interpolation?
// 17 reserved.
CDC_REG_ADC_NADC_VAL = 18u,
CDC_REG_ADC_MADC_VAL = 19u,
// 20 ADC AOSR_VAL?
// 21 ADC IADC_VAL?
// 22 ADC miniDSP Engine Decimation?
// 23-24 reserved.
// 25 CLKOUT MUX?
// 26 CLKOUT M_VAL?
CDC_REG_INTERFACE_CTRL = 27u, // Audio
// 28 Data-Slot Offset Programmability?
// 29 Codec Interface Control 2?
// 30 BCLK N_VAL?
// 31 Codec Secondary Interface Control 1?
// 32 Codec Secondary Interface Control 2?
// 33 Codec Secondary Interface Control 3?
CDC_REG_I2C_BUS_COND = 34u, // I2C Bus Condition.
// 35 reserved.
CDC_REG_ADC_FLAG = 36u,
CDC_REG_DAC_FLAG1 = 37u, // TODO: Validate.
CDC_REG_DAC_FLAG2 = 38u, // TODO: Validate.
CDC_REG_OVERFLOW_FLAGS = 39u,
// 40-43 reserved.
CDC_REG_INT_FLAGS_DAC = 44u, // Interrupt Flags—DAC.
CDC_REG_INT_FLAGS_ADC = 45u, // Interrupt Flags—ADC.
// 46 Interrupt Flags DAC? Same as 44?
// 47 Interrupt Flags ADC? Same as 45?
// 48 INT1 Control Register?
// 49 INT2 Control Register?
CDC_REG_INT1_INT2_CTRL = 50u, // TODO: Validate.
CDC_REG_GPIO1_INOUT_PIN_CTRL = 51u, // TODO: Validate.
CDC_REG_GPIO2_INOUT_PIN_CTRL = 52u, // TODO: Validate.
CDC_REG_SDOUT_PIN_CTRL = 53u, // TODO: Validate.
// 54 SDIN (IN Pin) Control?
// 55 MISO (OUT Pin) Control?
// 56 SCLK (IN Pin) Control?
CDC_REG_GPI1_GPI2_PIN_CTRL = 57u, // TODO: Validate.
CDC_REG_GPI3_PIN_CTRL = 58u, // TODO: Validate.
// 59 reserved.
CDC_REG_DAC_INSTR_SET = 60u, // DAC Instruction Set.
CDC_REG_ADC_INSTR_SET = 61u, // ADC Instruction Set.
// 62 Programmable Instruction Mode-Control Bits?
CDC_REG_DAC_DATA_PATH_SETUP = 63u, // I2S1?
CDC_REG_DAC_VOLUME_CTRL = 64u, // I2S1?
CDC_REG_DAC_L_VOLUME_CTRL = 65u, // I2S1?
CDC_REG_DAC_R_VOLUME_CTRL = 66u, // I2S1?
// 67 Headset Detection?
// 68 DRC Control 1?
// 69 DRC Control 2?
// 70 DRC Control 3?
CDC_REG_L_BEEP_GEN = 71u, // Left Beep Generator.
CDC_REG_R_BEEP_GEN = 72u, // Right Beep Generator.
CDC_REG_BEEP_LEN_MSB = 73u,
CDC_REG_BEEP_LEN_MID_BITS = 74u, // Beep Length Middle Bits.
CDC_REG_BEEP_LEN_LSB = 75u,
CDC_REG_BEEP_SIN_X_MSB = 76u, // Beep Sin(x) MSB.
CDC_REG_BEEP_SIN_X_LSB = 77u, // Beep Sin(x) LSB.
CDC_REG_BEEP_COS_X_MSB = 78u, // Beep Cos(x) MSB.
CDC_REG_BEEP_COS_X_LSB = 79u, // Beep Cos(x) LSB.
// 80 reserved.
CDC_REG_ADC_DIGITAL_MIC = 81u, // TODO: Validate.
CDC_REG_ADC_DIG_VOL_FINE_ADJ = 82u, // TODO: Validate. ADC Digital Volume Control Fine Adjust.
// 83 ADC Digital Volume Control Coarse Adjust?
// 84-85 reserved.
CDC_REG_AGC_CTRL1 = 86u,
CDC_REG_AGC_CTRL2 = 87u,
CDC_REG_AGC_MAX_GAIN = 88u,
CDC_REG_AGC_ATTACK_TIME = 89u,
CDC_REG_AGC_DECAY_TIME = 90u,
CDC_REG_AGC_NOISE_DEBOUNCE = 91u,
CDC_REG_AGC_SIGNAL_DEBOUNCE = 92u,
CDC_REG_AGC_GAIN_APPLIED = 93u,
// 94-101 reserved.
// 102 ADC DC Measurement 1?
// 103 ADC DC Measurement 2?
// 104 ADC DC Measurement Output 1?
// 105 ADC DC Measurement Output 2?
// 106 ADC DC Measurement Output 3?
// 107-115 reserved.
CDC_REG_VOL_MICDET_PIN_SAR_ADC = 116u, // TODO: Validate.
// 117 VOL/MICDET-Pin Gain?
// 118-127 reserved.
// ----------------------------------------------------------------------------------
// Control Registers, Page 1:
// DAC and ADC Routing, PGA, Power-Controls and MISC Logic Related Programmabilities:
// 1-29 reserved.
// 30 Headphone and Speaker Amplifier Error Control?
CDC_REG_HEADPHONE_DRIVERS = 1u<<8 | 31u,
CDC_REG_CLASS_D_SPEAKER_AMP = 1u<<8 | 32u, // TODO: Validate.
CDC_REG_HP_POP_REM_SETTINGS = 1u<<8 | 33u, // HP Output Drivers POP Removal Settings.
CDC_REG_OUT_PGA_RD_PERIOD_CTRL = 1u<<8 | 34u, // Output Driver PGA Ramp-Down Period Control.
CDC_REG_DAC_LR_OUT_MIX_ROUTING = 1u<<8 | 35u, // DAC_L and DAC_R Output Mixer Routing.
CDC_REG_L_ANALOG_VOL_TO_HPL = 1u<<8 | 36u,
CDC_REG_R_ANALOG_VOL_TO_HPR = 1u<<8 | 37u,
CDC_REG_L_ANALOG_VOL_TO_SPL = 1u<<8 | 38u,
CDC_REG_R_ANALOG_VOL_TO_SPR = 1u<<8 | 39u,
CDC_REG_HPL_DRIVER = 1u<<8 | 40u,
CDC_REG_HPR_DRIVER = 1u<<8 | 41u,
CDC_REG_SPL_DRIVER = 1u<<8 | 42u,
CDC_REG_SPR_DRIVER = 1u<<8 | 43u,
// 44 HP Driver Control?
// 45 reserved.
CDC_REG_MICBIAS = 1u<<8 | 46u,
CDC_REG_MIC_PGA = 1u<<8 | 47u, // TODO: Validate.
CDC_REG_ADC_IN_SEL_FOR_P_TERMINAL = 1u<<8 | 48u, // TODO: Validate. Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal.
CDC_REG_ADC_IN_SEL_FOR_M_TERMINAL = 1u<<8 | 49u, // ADC Input Selection for M-Terminal.
CDC_REG_INPUT_CM_SETTINGS = 1u<<8 | 50u,
// 51-127 reserved.
// ----------------------------------------------------------------------------------
// Control Registers, Page 3: TSC Control and Data Programmabilities.
// 1 reserved.
CDC_REG_SAR_ADC_CTRL = 3u<<8 | 2u, // First ADC?
CDC_REG_SAR_ADC_CTRL2 = 3u<<8 | 3u, // TODO: Validate.
CDC_REG_PRECHARGE_AND_SENSE = 3u<<8 | 4u,
CDC_REG_PANEL_VOLT_STABIL = 3u<<8 | 5u, // Panel Voltage Stabilization.
CDC_REG_VOLT_REF = 3u<<8 | 6u, // TODO: Validate. Voltage Reference.
// 7-8 reserved.
CDC_REG_STATUS_BIT = 3u<<8 | 9u,
CDC_REG_STATUS_BIT2 = 3u<<8 | 10u, // TODO: Validate.
// 11-12 reserved.
// 13 Buffer Mode?
CDC_REG_RESERVED_3_14 = 3u<<8 | 14u, // Buffer mode moved here?
CDC_REG_SCAN_MODE_TIMER = 3u<<8 | 15u,
CDC_REG_SCAN_MODE_TIMER_CLK = 3u<<8 | 16u,
CDC_REG_SAR_ADC_CLK = 3u<<8 | 17u,
CDC_REG_DEBOUNCE_TIME_PEN_UP = 3u<<8 | 18u, // Debounce Time for Pen-Up Detection.
CDC_REG_AUTO_AUX_MEASURE_SEL = 3u<<8 | 19u, // Auto AUX Measurement Selection.
CDC_REG_TOUCH_PEN_DOWN = 3u<<8 | 20u, // TODO: Validate. Touch-Screen Pen Down.
CDC_REG_TRESHOLD_CHECK_FLAGS = 3u<<8 | 21u,
// 22 AUX1 Maximum Value Check (MSB)?
// 23 AUX1 Maximum Value Check (LSB)?
// 24 AUX1 Minimum Value Check (MSB)?
// 25 AUX1 Minimum Value Check (LSB)?
// 26 AUX2 Maximum Value Check (MSB)?
// 27 AUX2 Maximum Value Check (LSB)?
// 28 AUX2 Minimum Value Check (MSB)?
// 29 AUX2 Minimum Value Check (LSB)?
CDC_REG_TEMP_MAX_VAL_CHECK_MSB = 3u<<8 | 30u, // Temperature Maximum Value Check (MSB).
CDC_REG_TEMP_MAX_VAL_CHECK_LSB = 3u<<8 | 31u, // Temperature Maximum Value Check (LSB).
CDC_REG_TEMP_MIN_VAL_CHECK_MSB = 3u<<8 | 32u, // Temperature Minimum Value Check (MSB).
CDC_REG_TEMP_MIN_VAL_CHECK_LSB = 3u<<8 | 33u, // Temperature Minimum Value Check (LSB).
// 34-41 reserved.
CDC_REG_X_COORDINATE_DATA_MSB = 3u<<8 | 42u,
CDC_REG_X_COORDINATE_DATA_LSB = 3u<<8 | 43u,
CDC_REG_Y_COORDINATE_DATA_MSB = 3u<<8 | 44u,
CDC_REG_Y_COORDINATE_DATA_LSB = 3u<<8 | 45u,
// 46 Z1 MSB Register?
// 47 Z1 LSB Register?
// 48 Z2 MSB Register?
// 49 Z2 LSB Register
// 50-53 reserved.
CDC_REG_AUX1_DATA_MSB = 3u<<8 | 54u, // TODO: Validate.
CDC_REG_AUX1_DATA_LSB = 3u<<8 | 55u, // TODO: Validate.
CDC_REG_AUX2_DATA_MSB = 3u<<8 | 56u, // TODO: Validate.
CDC_REG_AUX2_DATA_LSB = 3u<<8 | 57u, // TODO: Validate.
CDC_REG_VBAT_DATA_MSB = 3u<<8 | 58u, // TODO: Validate.
CDC_REG_VBAT_DATA_LSB = 3u<<8 | 59u, // TODO: Validate.
// 60-65 reserved.
CDC_REG_TEMP1_MSB_DATA = 3u<<8 | 66u,
CDC_REG_TEMP1_LSB_DATA = 3u<<8 | 67u,
CDC_REG_TEMP2_MSB_DATA = 3u<<8 | 68u,
CDC_REG_TEMP2_LSB_DATA = 3u<<8 | 69u,
// 70-127 reserved.
// ----------------------------------------------------------------------------------
// Page 4.
// ----------------------------------------------------------------------------------
// Page 5.
// ----------------------------------------------------------------------------------
// Page 8.
// ----------------------------------------------------------------------------------
// Page 9.
// ----------------------------------------------------------------------------------
// Page 10.
// ----------------------------------------------------------------------------------
// Page 11.
// ----------------------------------------------------------------------------------
// Page 12.
// ----------------------------------------------------------------------------------
// Page 100 (only CTR).
CDC_REG_SOFT_RST_CTR = 100u<<8 | 1u,
// 2-33 reserved?
CDC_REG_100_34 = 100u<<8 | 34u,
// 35-36 reserved?
CDC_REG_100_37 = 100u<<8 | 37u,
CDC_REG_100_38 = 100u<<8 | 38u,
CDC_REG_100_39 = 100u<<8 | 39u,
// 40-43 reserved?
CDC_REG_100_44 = 100u<<8 | 44u,
CDC_REG_100_48 = 100u<<8 | 48u,
CDC_REG_100_49 = 100u<<8 | 49u,
// 50-66 reserved?
CDC_REG_100_67 = 100u<<8 | 67u,
CDC_REG_100_68 = 100u<<8 | 68u,
CDC_REG_HEADSET_SEL = 100u<<8 | 69u,
// 70-116 reserved?
CDC_REG_100_117 = 100u<<8 | 117u,
CDC_REG_100_118 = 100u<<8 | 118u,
CDC_REG_100_119 = 100u<<8 | 119u,
CDC_REG_100_120 = 100u<<8 | 120u,
CDC_REG_100_121 = 100u<<8 | 121u,
CDC_REG_100_122 = 100u<<8 | 122u,
CDC_REG_100_123 = 100u<<8 | 123u,
CDC_REG_100_124 = 100u<<8 | 124u,
// 125-128 reserved?
// ----------------------------------------------------------------------------------
// Page 101 (only CTR).
// 1-7 reserved?
CDC_REG_101_8 = 101u<<8 | 8u,
CDC_REG_101_9 = 101u<<8 | 9u,
CDC_REG_101_10 = 101u<<8 | 10u,
CDC_REG_101_11 = 101u<<8 | 11u,
CDC_REG_101_12 = 101u<<8 | 12u,
// 13-16 reserved?
CDC_REG_101_17 = 101u<<8 | 17u,
CDC_REG_101_18 = 101u<<8 | 18u,
CDC_REG_101_19 = 101u<<8 | 19u,
// 20-21 reserved?
CDC_REG_101_22 = 101u<<8 | 22u,
CDC_REG_101_23 = 101u<<8 | 23u,
// 24-26 reserved?
CDC_REG_101_27 = 101u<<8 | 27u,
CDC_REG_101_28 = 101u<<8 | 28u,
// 29-50 reserved?
CDC_REG_101_51 = 101u<<8 | 51u,
// 52-64 reserved?
CDC_REG_101_65 = 101u<<8 | 65u,
CDC_REG_101_66 = 101u<<8 | 66u,
// 67-69 reserved?
CDC_REG_101_70 = 101u<<8 | 70u,
CDC_REG_101_71 = 101u<<8 | 71u,
CDC_REG_101_72 = 101u<<8 | 72u,
// 73-118 reserved?
CDC_REG_101_119 = 101u<<8 | 119u,
CDC_REG_101_120 = 101u<<8 | 120u,
// 121 reserved?
CDC_REG_101_122 = 101u<<8 | 122u,
// 123-128 reserved?
// ----------------------------------------------------------------------------------
// Page 103 (only CTR).
// 1-22 reserved?
CDC_REG_103_23 = 103u<<8 | 23u,
CDC_REG_103_24 = 103u<<8 | 24u,
CDC_REG_103_25 = 103u<<8 | 25u,
CDC_REG_103_26 = 103u<<8 | 26u,
CDC_REG_103_27 = 103u<<8 | 27u,
// 28-35 reserved?
CDC_REG_103_36 = 103u<<8 | 36u,
CDC_REG_103_37 = 103u<<8 | 37u,
CDC_REG_103_38 = 103u<<8 | 38u,
CDC_REG_103_39 = 103u<<8 | 39u,
// 40-128 reserved?
// ----------------------------------------------------------------------------------
// Page 251 (only CTR).
// ----------------------------------------------------------------------------------
// Page 252.
// ----------------------------------------------------------------------------------
// Page 255 (only CTR).
// 1 reserved?
// 2 reserved?
// 3 reserved?
// 4 reserved?
CDC_REG_TWL_MODE = 255<<8 | 5u
};
// ----------------------------------------------------------------------------------
// CDC_REG_HEADSET_SEL (page 100 (0x64), reg 69 (0x45))
#define HEADSET_SEL_HP_SHIFT (4u)
#define HEADSET_SEL_SP (0u) // Force speaker output.
#define HEADSET_SEL_HP (1u<<HEADSET_SEL_HP_SHIFT) // Force headphone output.
#define HEADSET_SEL_HP_EN (1u<<5) // Enable headphone override.
#define HEADSET_SEL_MIC_SHIFT (6u)
#define HEADSET_SEL_INT_MIC (0u) // Force internal microphone input.
#define HEADSET_SEL_EXT_MIC (1u<<HEADSET_SEL_MIC_SHIFT) // Force external microphone input.
#define HEADSET_SEL_MIC_EN (1u<<7) // Enable microphone override.

View File

@ -1,235 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#define CSND_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x3000)
typedef struct
{
vu16 cnt; // 0x00
vs16 sr; // 0x02 Samplerate.
union
{
struct
{
vu16 vol_r; // 0x04 Range 0-0x8000.
vu16 vol_l; // 0x06 Range 0-0x8000.
};
vu32 vol; // 0x04 R and L combined.
};
union
{
struct
{
vu16 capvol_r; // 0x08 Unconfirmed. Range 0-0x8000.
vu16 capvol_l; // 0x0A Unconfirmed. Range 0-0x8000.
};
vu32 capvol; // 0x08 R and L combined.
};
vu32 st_addr; // 0x0C Start address and playback position.
vu32 size; // 0x10 Size in bytes.
vu32 lp_addr; // 0x14 Loop restart address.
vu32 st_adpcm; // 0x18 Start IMA-ADPCM state.
vu32 lp_adpcm; // 0x1C Loop Restart IMA-ADPCM state.
} CsndCh;
static_assert(offsetof(CsndCh, lp_adpcm) == 0x1C, "Error: Member lp_adpcm of CsndCh is not at offset 0x1C!");
typedef struct
{
vu16 cnt; // 0x0
u8 _0x2[2];
vs16 sr; // 0x4 Samplerate.
u8 _0x6[2];
vu32 size; // 0x8 Capture length in bytes.
vu32 addr; // 0xC Address.
} CsndCap;
static_assert(offsetof(CsndCap, addr) == 0xC, "Error: Member addr of CsndCap is not at offset 0xC!");
typedef struct
{
vu16 master_vol; // 0x000 CSND master volume range 0-0x8000.
vu16 unk_cnt; // 0x002
u8 _0x4[0xc];
vu32 unk010; // 0x010 FIFO related?
vu8 unk014; // 0x014 FIFO related?
u8 _0x15[0x3eb];
CsndCh ch[32]; // 0x400 32 sound channels. PSG on channel 8-13 and noise 14-15.
CsndCap cap[2]; // 0x800 2 capture units for right and left side.
} Csnd;
static_assert(offsetof(Csnd, cap[1].addr) == 0x81C, "Error: Member cap[1].addr of Csnd is not at offset 0x81C!");
ALWAYS_INLINE Csnd* getCsndRegs(void)
{
return (Csnd*)CSND_REGS_BASE;
}
ALWAYS_INLINE CsndCh* getCsndChRegs(u8 ch)
{
return &getCsndRegs()->ch[ch];
}
ALWAYS_INLINE CsndCap* getCsndCapRegs(u8 ch)
{
return &getCsndRegs()->cap[ch];
}
// REG_CSND_CH_CNT
#define CSND_CH_DUTY(d) (d) // For PSG (channel 8-13) only. In 12.5% units. 0 = high/12.5%.
#define CSND_CH_LERP (1u<<6) // Linear interpolation.
#define CSND_CH_HOLD (1u<<7) // Hold last sample after one shot.
#define CSND_CH_RPT_MANUAL (0u<<10)
#define CSND_CH_RPT_LOOP (1u<<10)
#define CSND_CH_RPT_ONE_SHOT (2u<<10)
#define CSND_CH_FMT_PCM8 (0u<<12) // Signed PCM8.
#define CSND_CH_FMT_PCM16 (1u<<12) // Signed PCM16 little endian.
#define CSND_CH_FMT_IMA_ADPCM (2u<<12)
#define CSND_CH_FMT_PSG_NOISE (3u<<12)
#define CSND_CH_PLAYING (1u<<14)
#define CSND_CH_START (1u<<15)
// REG_CSND_CAP_CNT
#define CSND_CAP_RPT_LOOP (0u)
#define CSND_CAP_RPT_ONE_SHOT (1u)
#define CSND_CAP_FMT_PCM16 (0u) // Signed PCM16 little endian.
#define CSND_CAP_FMT_PCM8 (1u<<1) // Signed PCM8.
#define CSND_CAP_UNK2 (1u<<2)
#define CSND_CAP_START (1u<<15)
// Samplerate helpers
#define CSND_SAMPLERATE(s) (-(s16)(67027964u / (s)))
#define CSND_PSG_FREQ(f) (CSND_SAMPLERATE(32u * (f)))
/**
* @brief Initializes the CSND hardware.
*/
void CSND_init(void);
/**
* @brief Calculates the left and right volumes.
*
* @param[in] lvol The left volume.
* @param[in] rvol The right volume.
*
* @return The volume pair needed for CSND_setupCh().
*/
static inline u32 CSND_calcVol(float lvol, float rvol)
{
return (u32)(lvol * 32768.f)<<16 | (u32)(rvol * 32768.f);
}
/**
* @brief Sets up a channel for sound playback (in paused state).
*
* @param[in] ch The sound channel. 0-31.
* @param[in] srFreq The sample rate/frequency.
* @param[in] vol The L/R volume pair.
* @param[in] data The start address.
* @param[in] data2 The loop restart address.
* @param[in] size The size.
* @param[in] flags The flags.
*/
void CSND_setupCh(u8 ch, s16 srFreq, u32 vol, const u32 *const data, const u32 *const data2, u32 size, u16 flags);
/**
* @brief Sets the sample rate/frequency of a channel.
*
* @param[in] ch The sound channel. 0-31.
* @param[in] srFreq The sample rate/frequency.
*/
static inline void CSND_setSrFreq(u8 ch, s16 srFreq)
{
getCsndChRegs(ch)->sr = srFreq;
}
/**
* @brief Pauses or unpauses a sound channel.
*
* @param[in] ch The sound channel. 0-31.
* @param[in] playing The play state.
*/
static inline void CSND_setChState(u8 ch, bool playing)
{
CsndCh *const csndCh = getCsndChRegs(ch);
csndCh->cnt = (csndCh->cnt & ~CSND_CH_PLAYING) | ((u16)playing<<14);
}
/**
* @brief Returns the current audio buffer position (address).
*
* @param[in] ch The sound channel. 0-31.
*
* @return The playback position (address).
*/
static inline u32 CSND_getChPos(u8 ch)
{
return getCsndChRegs(ch)->st_addr;
}
/**
* @brief Stops a sound channel.
*
* @param[in] ch The sound channel. 0-31.
*/
static inline void CSND_stopCh(u8 ch)
{
getCsndChRegs(ch)->cnt = 0; // Stop.
}
/**
* @brief Captures the output of all left/right sound channels combined.
*
* @param[in] ch The capture side. 0 = right, 1 = left.
* @param[in] sr The sample rate.
* @param data The output address.
* @param[in] size The size.
* @param[in] flags The flags.
*/
void CSND_startCap(u8 ch, s16 sr, u32 *const data, u32 size, u16 flags);
/**
* @brief Returns the current capture buffer position (address).
*
* @param[in] ch The capture side. 0 = right, 1 = left.
*
* @return The capture position (address).
*/
static inline u32 CSND_getCapPos(u8 ch)
{
return getCsndCapRegs(ch)->addr;
}
/**
* @brief Stops a capture channel.
*
* @param[in] ch The capture side. 0 = right, 1 = left.
*/
static inline void CSND_stopCap(u8 ch)
{
getCsndCapRegs(ch)->cnt = 0;
}

View File

@ -1,86 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
// Most register names from: https://github.com/torvalds/linux/blob/master/include/linux/irqchip/arm-gic.h
#define GIC_CPU_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x100)
#define GIC_DIST_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x1000)
typedef struct
{
vu32 ctrl; // 0x00 Control Register.
vu32 primask; // 0x04 Priority Mask Register.
vu32 binpoint; // 0x08 Binary Point Register.
const vu32 intack; // 0x0C Interrupt Acknowledge Register.
vu32 eoi; // 0x10 End of Interrupt Register.
const vu32 runningpri; // 0x14 Running Priority Register.
const vu32 highpri; // 0x18 Highest Pending Interrupt Register.
} GicCpu;
static_assert(offsetof(GicCpu, highpri) == 0x18, "Error: Member highpri of GicCpu is not at offset 0x18!");
typedef struct
{
vu32 ctrl; // 0x000 Interrupt Distributor Control Register.
const vu32 ctr; // 0x004 Interrupt Controller Type Register.
u8 _0x8[0xf8];
vu32 enable_set[8]; // 0x100 Interrupt Enable set Registers.
u8 _0x120[0x60];
vu32 enable_clear[8]; // 0x180 Interrupt Enable clear Registers.
u8 _0x1a0[0x60];
vu32 pending_set[8]; // 0x200 Interrupt Pending set Registers.
u8 _0x220[0x60];
vu32 pending_clear[8]; // 0x280 Interrupt Pending clear Registers.
u8 _0x2a0[0x60];
const vu32 active_set[8]; // 0x300 Interrupt Active Bit Registers.
u8 _0x320[0xe0];
vu32 pri[64]; // 0x400 Interrupt Priority Registers.
u8 _0x500[0x300];
vu32 target[64]; // 0x800 Interrupt CPU targets Registers.
u8 _0x900[0x300];
vu32 config[16]; // 0xC00 Interrupt Configuration Registers.
u8 _0xc40[0xc0];
const vu32 line_level[8]; // 0xD00 Interrupt Line Level Registers.
u8 _0xd20[0x1e0];
vu32 softint; // 0xF00 Software Interrupt Register.
u8 _0xf04[0xdc];
const vu32 periph_ident0; // 0xFE0 Periphal Identification Register 0.
const vu32 periph_ident1; // 0xFE4 Periphal Identification Register 1.
const vu32 periph_ident2; // 0xFE8 Periphal Identification Register 2.
const vu32 periph_ident3; // 0xFEC Periphal Identification Register 3.
const vu32 primecell0; // 0xFF0 PrimeCell Identification Register 0.
const vu32 primecell1; // 0xFF4 PrimeCell Identification Register 1.
const vu32 primecell2; // 0xFF8 PrimeCell Identification Register 2.
const vu32 primecell3; // 0xFFC PrimeCell Identification Register 3.
} GicDist;
static_assert(offsetof(GicDist, primecell3) == 0xFFC, "Error: Member primecell3 of GicDist is not at offset 0xFFC!");
ALWAYS_INLINE GicCpu* getGicCpuRegs(void)
{
return (GicCpu*)GIC_CPU_REGS_BASE;
}
ALWAYS_INLINE GicDist* getGicDistRegs(void)
{
return (GicDist*)GIC_DIST_REGS_BASE;
}

View File

@ -1,120 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "mem_map.h"
#define GPIO_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x47000)
// 3 GPIOs (bits 0-2)
#define REG_GPIO1_DAT *((const vu8*)(GPIO_REGS_BASE + 0x00)) // Read-only.
// 2 GPIOs (bits 0-1)
#define REG_GPIO2 *(( vu32*)(GPIO_REGS_BASE + 0x10))
#define REG_GPIO2_DAT *(( vu8*)(GPIO_REGS_BASE + 0x10))
#define REG_GPIO2_DIR *(( vu8*)(GPIO_REGS_BASE + 0x11)) // 0 = input, 1 = output.
#define REG_GPIO2_EDGE *(( vu8*)(GPIO_REGS_BASE + 0x12)) // IRQ edge 0 = falling, 1 = rising.
#define REG_GPIO2_IRQ *(( vu8*)(GPIO_REGS_BASE + 0x13)) // 1 = IRQ enable.
// 1 GPIO (bit 0)
#define REG_GPIO2_DAT2 *(( vu16*)(GPIO_REGS_BASE + 0x14)) // Only bit 0 writable.
// 12 GPIOs (bits 0-11)
#define REG_GPIO3_H1 *(( vu32*)(GPIO_REGS_BASE + 0x20)) // First half.
#define REG_GPIO3_DAT *(( vu16*)(GPIO_REGS_BASE + 0x20))
#define REG_GPIO3_DIR *(( vu16*)(GPIO_REGS_BASE + 0x22))
#define REG_GPIO3_H2 *(( vu32*)(GPIO_REGS_BASE + 0x24)) // Second half.
#define REG_GPIO3_EDGE *(( vu16*)(GPIO_REGS_BASE + 0x24))
#define REG_GPIO3_IRQ *(( vu16*)(GPIO_REGS_BASE + 0x26))
// 1 GPIO (bit 0)
#define REG_GPIO3_DAT2 *(( vu16*)(GPIO_REGS_BASE + 0x28)) // WiFi.
#define GPIO_INPUT (0u)
#define GPIO_OUTPUT (1u)
#define GPIO_NO_IRQ (0u)
#define GPIO_IRQ_FALLING (1u<<2 | 0u)
#define GPIO_IRQ_RISING (1u<<2 | 1u<<1)
// bits 3-7 pin number, bits 0-3 reg index.
#define MAKE_GPIO(pin, reg) ((pin)<<3 | (reg))
typedef enum
{
GPIO_1_0 = MAKE_GPIO(0u, 0u),
GPIO_1_1 = MAKE_GPIO(1u, 0u),
GPIO_1_2 = MAKE_GPIO(2u, 0u),
GPIO_2_0 = MAKE_GPIO(0u, 1u),
GPIO_2_1 = MAKE_GPIO(1u, 1u),
GPIO_2_2 = MAKE_GPIO(0u, 2u), // REG_GPIO2_DAT2
GPIO_3_0 = MAKE_GPIO(0u, 3u),
GPIO_3_1 = MAKE_GPIO(1u, 3u),
GPIO_3_2 = MAKE_GPIO(2u, 3u),
GPIO_3_3 = MAKE_GPIO(3u, 3u),
GPIO_3_4 = MAKE_GPIO(4u, 3u),
GPIO_3_5 = MAKE_GPIO(5u, 3u),
GPIO_3_6 = MAKE_GPIO(6u, 3u),
GPIO_3_7 = MAKE_GPIO(7u, 3u),
GPIO_3_8 = MAKE_GPIO(8u, 3u),
GPIO_3_9 = MAKE_GPIO(9u, 3u),
GPIO_3_10 = MAKE_GPIO(10u, 3u),
GPIO_3_11 = MAKE_GPIO(11u, 3u),
GPIO_3_12 = MAKE_GPIO(0u, 4u), // REG_GPIO3_DAT2
// Aliases
GPIO_1_TOUCHSCREEN = GPIO_1_1, // Unset while touchscreen pen down. Unused after CODEC init.
GPIO_1_SHELL = GPIO_1_2, // 1 when closed.
GPIO_2_HEADPH_JACK = GPIO_2_0, // Used after CODEC init.
GPIO_3_HEADPH_JACK = GPIO_3_8, // Unused/other function after CODEC init.
GPIO_3_MCU = GPIO_3_9
} Gpio;
#undef MAKE_GPIO
/**
* @brief Configures the specified GPIO.
*
* @param[in] gpio The gpio.
* @param[in] cfg The configuration. See defines above.
*/
void GPIO_config(Gpio gpio, u8 cfg);
/**
* @brief Reads a GPIO pin.
*
* @param[in] gpio The gpio.
*
* @return The state. Either 0 or 1.
*/
u8 GPIO_read(Gpio gpio);
/**
* @brief Writes a GPIO pin.
*
* @param[in] gpio The gpio.
* @param[in] val The value. Must be 0 or 1.
*/
void GPIO_write(Gpio gpio, u8 val);

View File

@ -1,769 +0,0 @@
// From https://github.com/devkitPro/libctru/blob/master/libctru/include/3ds/gpu/registers.h
/**
* @file registers.h
* @description GPU registers.
*/
#pragma once
///@name Miscellaneous registers (0x000-0x03F)
///@{
#define GPUREG_IRQ_ACK 0x0000 ///< Acknowledge P3D IRQ.
#define GPUREG_0001 0x0001 ///< Unknown.
#define GPUREG_0002 0x0002 ///< Unknown.
#define GPUREG_0003 0x0003 ///< Unknown.
#define GPUREG_0004 0x0004 ///< Unknown.
#define GPUREG_0005 0x0005 ///< Unknown.
#define GPUREG_0006 0x0006 ///< Unknown.
#define GPUREG_0007 0x0007 ///< Unknown.
#define GPUREG_0008 0x0008 ///< Unknown.
#define GPUREG_0009 0x0009 ///< Unknown.
#define GPUREG_000A 0x000A ///< Unknown.
#define GPUREG_000B 0x000B ///< Unknown.
#define GPUREG_000C 0x000C ///< Unknown.
#define GPUREG_000D 0x000D ///< Unknown.
#define GPUREG_000E 0x000E ///< Unknown.
#define GPUREG_000F 0x000F ///< Unknown.
#define GPUREG_FINALIZE 0x0010 ///< Used to finalize GPU drawing.
#define GPUREG_0011 0x0011 ///< Unknown.
#define GPUREG_0012 0x0012 ///< Unknown.
#define GPUREG_0013 0x0013 ///< Unknown.
#define GPUREG_0014 0x0014 ///< Unknown.
#define GPUREG_0015 0x0015 ///< Unknown.
#define GPUREG_0016 0x0016 ///< Unknown.
#define GPUREG_0017 0x0017 ///< Unknown.
#define GPUREG_0018 0x0018 ///< Unknown.
#define GPUREG_0019 0x0019 ///< Unknown.
#define GPUREG_001A 0x001A ///< Unknown.
#define GPUREG_001B 0x001B ///< Unknown.
#define GPUREG_001C 0x001C ///< Unknown.
#define GPUREG_001D 0x001D ///< Unknown.
#define GPUREG_001E 0x001E ///< Unknown.
#define GPUREG_001F 0x001F ///< Unknown.
#define GPUREG_IRQ_CMP 0x0020 ///< Triggers a P3D IRQ when the value written to GPUREG_FINALIZE matches this.
#define GPUREG_0021 0x0021 ///< Unknown.
#define GPUREG_0022 0x0022 ///< Unknown.
#define GPUREG_0023 0x0023 ///< Unknown.
#define GPUREG_0024 0x0024 ///< Unknown.
#define GPUREG_0025 0x0025 ///< Unknown.
#define GPUREG_0026 0x0026 ///< Unknown.
#define GPUREG_0027 0x0027 ///< Unknown.
#define GPUREG_0028 0x0028 ///< Unknown.
#define GPUREG_0029 0x0029 ///< Unknown.
#define GPUREG_002A 0x002A ///< Unknown.
#define GPUREG_002B 0x002B ///< Unknown.
#define GPUREG_002C 0x002C ///< Unknown.
#define GPUREG_002D 0x002D ///< Unknown.
#define GPUREG_002E 0x002E ///< Unknown.
#define GPUREG_002F 0x002F ///< Unknown.
#define GPUREG_IRQ_MASK 0x0030 ///< IRQ mask. Each bit 0 = enable.
#define GPUREG_0031 0x0031 ///< Unknown.
#define GPUREG_0032 0x0032 ///< Unknown.
#define GPUREG_0033 0x0033 ///< Unknown.
#define GPUREG_IRQ_AUTOSTOP 0x0034 ///< 1 = stop cmd list processing on IRQ.
#define GPUREG_0035 0x0035 ///< Unknown.
#define GPUREG_0036 0x0036 ///< Unknown.
#define GPUREG_0037 0x0037 ///< Unknown.
#define GPUREG_0038 0x0038 ///< Unknown.
#define GPUREG_0039 0x0039 ///< Unknown.
#define GPUREG_003A 0x003A ///< Unknown.
#define GPUREG_003B 0x003B ///< Unknown.
#define GPUREG_003C 0x003C ///< Unknown.
#define GPUREG_003D 0x003D ///< Unknown.
#define GPUREG_003E 0x003E ///< Unknown.
#define GPUREG_003F 0x003F ///< Unknown.
///@}
///@name Rasterizer registers (0x040-0x07F)
///@{
#define GPUREG_FACECULLING_CONFIG 0x0040 ///< Face culling configuration.
#define GPUREG_VIEWPORT_WIDTH 0x0041 ///< Viewport width.
#define GPUREG_VIEWPORT_INVW 0x0042 ///< Inverted viewport width.
#define GPUREG_VIEWPORT_HEIGHT 0x0043 ///< Viewport height.
#define GPUREG_VIEWPORT_INVH 0x0044 ///< Inverted viewport height.
#define GPUREG_0045 0x0045 ///< Unknown
#define GPUREG_0046 0x0046 ///< Unknown
#define GPUREG_FRAGOP_CLIP 0x0047 ///< Unknown
#define GPUREG_FRAGOP_CLIP_DATA0 0x0048 ///< Unknown
#define GPUREG_FRAGOP_CLIP_DATA1 0x0049 ///< Unknown
#define GPUREG_FRAGOP_CLIP_DATA2 0x004A ///< Unknown
#define GPUREG_FRAGOP_CLIP_DATA3 0x004B ///< Unknown
#define GPUREG_004C 0x004C ///< Unknown
#define GPUREG_DEPTHMAP_SCALE 0x004D ///< Depth map scale.
#define GPUREG_DEPTHMAP_OFFSET 0x004E ///< Depth map offset.
#define GPUREG_SH_OUTMAP_TOTAL 0x004F ///< Shader output map total.
#define GPUREG_SH_OUTMAP_O0 0x0050 ///< Shader output map 0.
#define GPUREG_SH_OUTMAP_O1 0x0051 ///< Shader output map 1.
#define GPUREG_SH_OUTMAP_O2 0x0052 ///< Shader output map 2.
#define GPUREG_SH_OUTMAP_O3 0x0053 ///< Shader output map 3.
#define GPUREG_SH_OUTMAP_O4 0x0054 ///< Shader output map 4.
#define GPUREG_SH_OUTMAP_O5 0x0055 ///< Shader output map 5.
#define GPUREG_SH_OUTMAP_O6 0x0056 ///< Shader output map 6.
#define GPUREG_0057 0x0057 ///< Unknown
#define GPUREG_0058 0x0058 ///< Unknown
#define GPUREG_0059 0x0059 ///< Unknown
#define GPUREG_005A 0x005A ///< Unknown
#define GPUREG_005B 0x005B ///< Unknown
#define GPUREG_005C 0x005C ///< Unknown
#define GPUREG_005D 0x005D ///< Unknown
#define GPUREG_005E 0x005E ///< Unknown
#define GPUREG_005F 0x005F ///< Unknown
#define GPUREG_0060 0x0060 ///< Unknown
#define GPUREG_EARLYDEPTH_FUNC 0x0061 ///< Unknown
#define GPUREG_EARLYDEPTH_TEST1 0x0062 ///< Unknown
#define GPUREG_EARLYDEPTH_CLEAR 0x0063 ///< Unknown
#define GPUREG_SH_OUTATTR_MODE 0x0064 ///< Shader output attributes mode.
#define GPUREG_SCISSORTEST_MODE 0x0065 ///< Scissor test mode.
#define GPUREG_SCISSORTEST_POS 0x0066 ///< Scissor test position.
#define GPUREG_SCISSORTEST_DIM 0x0067 ///< Scissor text dimensions.
#define GPUREG_VIEWPORT_XY 0x0068 ///< Viewport X and Y.
#define GPUREG_0069 0x0069 ///< Unknown
#define GPUREG_EARLYDEPTH_DATA 0x006A ///< Unknown
#define GPUREG_006B 0x006B ///< Unknown
#define GPUREG_006C 0x006C ///< Unknown
#define GPUREG_DEPTHMAP_ENABLE 0x006D ///< Depth map enable.
#define GPUREG_RENDERBUF_DIM 0x006E ///< Renderbuffer dimensions.
#define GPUREG_SH_OUTATTR_CLOCK 0x006F ///< Shader output attributes clock enable.
#define GPUREG_0070 0x0070 ///< Unknown
#define GPUREG_0071 0x0071 ///< Unknown
#define GPUREG_0072 0x0072 ///< Unknown
#define GPUREG_0073 0x0073 ///< Unknown
#define GPUREG_0074 0x0074 ///< Unknown
#define GPUREG_0075 0x0075 ///< Unknown
#define GPUREG_0076 0x0076 ///< Unknown
#define GPUREG_0077 0x0077 ///< Unknown
#define GPUREG_0078 0x0078 ///< Unknown
#define GPUREG_0079 0x0079 ///< Unknown
#define GPUREG_007A 0x007A ///< Unknown
#define GPUREG_007B 0x007B ///< Unknown
#define GPUREG_007C 0x007C ///< Unknown
#define GPUREG_007D 0x007D ///< Unknown
#define GPUREG_007E 0x007E ///< Unknown
#define GPUREG_007F 0x007F ///< Unknown
///@}
///@name Texturing registers (0x080-0x0FF)
///@{
#define GPUREG_TEXUNIT_CONFIG 0x0080 ///< Texture unit configuration.
#define GPUREG_TEXUNIT0_BORDER_COLOR 0x0081 ///< Texture unit 0 border color.
#define GPUREG_TEXUNIT0_DIM 0x0082 ///< Texture unit 0 dimensions.
#define GPUREG_TEXUNIT0_PARAM 0x0083 ///< Texture unit 0 parameters.
#define GPUREG_TEXUNIT0_LOD 0x0084 ///< Texture unit 0 LOD.
#define GPUREG_TEXUNIT0_ADDR1 0x0085 ///< Texture unit 0 address.
#define GPUREG_TEXUNIT0_ADDR2 0x0086 ///< Unknown.
#define GPUREG_TEXUNIT0_ADDR3 0x0087 ///< Unknown.
#define GPUREG_TEXUNIT0_ADDR4 0x0088 ///< Unknown.
#define GPUREG_TEXUNIT0_ADDR5 0x0089 ///< Unknown.
#define GPUREG_TEXUNIT0_ADDR6 0x008A ///< Unknown.
#define GPUREG_TEXUNIT0_SHADOW 0x008B ///< Unknown.
#define GPUREG_008C 0x008C ///< Unknown.
#define GPUREG_008D 0x008D ///< Unknown.
#define GPUREG_TEXUNIT0_TYPE 0x008E ///< Texture unit 0 type.
#define GPUREG_LIGHTING_ENABLE0 0x008F ///< Lighting toggle.
#define GPUREG_0090 0x0090 ///< Unknown.
#define GPUREG_TEXUNIT1_BORDER_COLOR 0x0091 ///< Texture unit 1 border color.
#define GPUREG_TEXUNIT1_DIM 0x0092 ///< Texture unit 1 dimensions.
#define GPUREG_TEXUNIT1_PARAM 0x0093 ///< Texture unit 1 parameters.
#define GPUREG_TEXUNIT1_LOD 0x0094 ///< Texture unit 1 LOD.
#define GPUREG_TEXUNIT1_ADDR 0x0095 ///< Texture unit 1 address.
#define GPUREG_TEXUNIT1_TYPE 0x0096 ///< Texture unit 1 type.
#define GPUREG_0097 0x0097 ///< Unknown.
#define GPUREG_0098 0x0098 ///< Unknown.
#define GPUREG_TEXUNIT2_BORDER_COLOR 0x0099 ///< Texture unit 2 border color.
#define GPUREG_TEXUNIT2_DIM 0x009A ///< Texture unit 2 dimensions.
#define GPUREG_TEXUNIT2_PARAM 0x009B ///< Texture unit 2 parameters.
#define GPUREG_TEXUNIT2_LOD 0x009C ///< Texture unit 2 LOD.
#define GPUREG_TEXUNIT2_ADDR 0x009D ///< Texture unit 2 address.
#define GPUREG_TEXUNIT2_TYPE 0x009E ///< Texture unit 2 type.
#define GPUREG_009F 0x009F ///< Unknown.
#define GPUREG_00A0 0x00A0 ///< Unknown.
#define GPUREG_00A1 0x00A1 ///< Unknown.
#define GPUREG_00A2 0x00A2 ///< Unknown.
#define GPUREG_00A3 0x00A3 ///< Unknown.
#define GPUREG_00A4 0x00A4 ///< Unknown.
#define GPUREG_00A5 0x00A5 ///< Unknown.
#define GPUREG_00A6 0x00A6 ///< Unknown.
#define GPUREG_00A7 0x00A7 ///< Unknown.
#define GPUREG_TEXUNIT3_PROCTEX0 0x00A8 ///< Unknown.
#define GPUREG_TEXUNIT3_PROCTEX1 0x00A9 ///< Unknown.
#define GPUREG_TEXUNIT3_PROCTEX2 0x00AA ///< Unknown.
#define GPUREG_TEXUNIT3_PROCTEX3 0x00AB ///< Unknown.
#define GPUREG_TEXUNIT3_PROCTEX4 0x00A ///< Unknown.
#define GPUREG_TEXUNIT3_PROCTEX5 0x00D ///< Unknown.
#define GPUREG_00AE 0x00AE ///< Unknown.
#define GPUREG_PROCTEX_LUT 0x00AF ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA0 0x00B0 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA1 0x00B1 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA2 0x00B2 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA3 0x00B3 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA4 0x00B4 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA5 0x00B5 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA6 0x00B6 ///< Unknown.
#define GPUREG_PROCTEX_LUT_DATA7 0x00B7 ///< Unknown.
#define GPUREG_00B8 0x00B8 ///< Unknown.
#define GPUREG_00B9 0x00B9 ///< Unknown.
#define GPUREG_00BA 0x00BA ///< Unknown.
#define GPUREG_00BB 0x00BB ///< Unknown.
#define GPUREG_00BC 0x00BC ///< Unknown.
#define GPUREG_00BD 0x00BD ///< Unknown.
#define GPUREG_00BE 0x00BE ///< Unknown.
#define GPUREG_00BF 0x00BF ///< Unknown.
#define GPUREG_TEXENV0_SOURCE 0x00C0 ///< Texture env 0 source.
#define GPUREG_TEXENV0_OPERAND 0x00C1 ///< Texture env 0 operand.
#define GPUREG_TEXENV0_COMBINER 0x00C2 ///< Texture env 0 combiner.
#define GPUREG_TEXENV0_COLOR 0x00C3 ///< Texture env 0 color.
#define GPUREG_TEXENV0_SCALE 0x00C4 ///< Texture env 0 scale.
#define GPUREG_00C5 0x00C5 ///< Unknown.
#define GPUREG_00C6 0x00C6 ///< Unknown.
#define GPUREG_00C7 0x00C7 ///< Unknown.
#define GPUREG_TEXENV1_SOURCE 0x00C8 ///< Texture env 1 source.
#define GPUREG_TEXENV1_OPERAND 0x00C9 ///< Texture env 1 operand.
#define GPUREG_TEXENV1_COMBINER 0x00CA ///< Texture env 1 combiner.
#define GPUREG_TEXENV1_COLOR 0x00CB ///< Texture env 1 color.
#define GPUREG_TEXENV1_SCALE 0x00CC ///< Texture env 1 scale.
#define GPUREG_00CD 0x00CD ///< Unknown.
#define GPUREG_00CE 0x00CE ///< Unknown.
#define GPUREG_00CF 0x00CF ///< Unknown.
#define GPUREG_TEXENV2_SOURCE 0x00D0 ///< Texture env 2 source.
#define GPUREG_TEXENV2_OPERAND 0x00D1 ///< Texture env 2 operand.
#define GPUREG_TEXENV2_COMBINER 0x00D2 ///< Texture env 2 combiner.
#define GPUREG_TEXENV2_COLOR 0x00D3 ///< Texture env 2 color.
#define GPUREG_TEXENV2_SCALE 0x00D4 ///< Texture env 2 scale.
#define GPUREG_00D5 0x00D5 ///< Unknown.
#define GPUREG_00D6 0x00D6 ///< Unknown.
#define GPUREG_00D7 0x00D7 ///< Unknown.
#define GPUREG_TEXENV3_SOURCE 0x00D8 ///< Texture env 3 source.
#define GPUREG_TEXENV3_OPERAND 0x00D9 ///< Texture env 3 operand.
#define GPUREG_TEXENV3_COMBINER 0x00DA ///< Texture env 3 combiner.
#define GPUREG_TEXENV3_COLOR 0x00DB ///< Texture env 3 color.
#define GPUREG_TEXENV3_SCALE 0x00DC ///< Texture env 3 scale.
#define GPUREG_00DD 0x00DD ///< Unknown.
#define GPUREG_00DE 0x00DE ///< Unknown.
#define GPUREG_00DF 0x00DF ///< Unknown.
#define GPUREG_TEXENV_UPDATE_BUFFER 0x00E0 ///< Texture env buffer update flag.
#define GPUREG_FOG_COLOR 0x00E1 ///< Unknown.
#define GPUREG_00E2 0x00E2 ///< Unknown.
#define GPUREG_00E3 0x00E3 ///< Unknown.
#define GPUREG_GAS_ATTENUATION 0x00E4 ///< Unknown.
#define GPUREG_GAS_ACCMAX 0x00E5 ///< Unknown.
#define GPUREG_FOG_LUT_INDEX 0x00E6 ///< Unknown.
#define GPUREG_00E7 0x00E7 ///< Unknown.
#define GPUREG_FOG_LUT_DATA0 0x00E8 ///< Unknown.
#define GPUREG_FOG_LUT_DATA1 0x00E9 ///< Unknown.
#define GPUREG_FOG_LUT_DATA2 0x00EA ///< Unknown.
#define GPUREG_FOG_LUT_DATA3 0x00EB ///< Unknown.
#define GPUREG_FOG_LUT_DATA4 0x00EC ///< Unknown.
#define GPUREG_FOG_LUT_DATA5 0x00ED ///< Unknown.
#define GPUREG_FOG_LUT_DATA6 0x00EE ///< Unknown.
#define GPUREG_FOG_LUT_DATA7 0x00EF ///< Unknown.
#define GPUREG_TEXENV4_SOURCE 0x00F0 ///< Texture env 4 source.
#define GPUREG_TEXENV4_OPERAND 0x00F1 ///< Texture env 4 operand.
#define GPUREG_TEXENV4_COMBINER 0x00F2 ///< Texture env 4 combiner.
#define GPUREG_TEXENV4_COLOR 0x00F3 ///< Texture env 4 color.
#define GPUREG_TEXENV4_SCALE 0x00F4 ///< Texture env 4 scale.
#define GPUREG_00F5 0x00F5 ///< Unknown.
#define GPUREG_00F6 0x00F6 ///< Unknown.
#define GPUREG_00F7 0x00F7 ///< Unknown.
#define GPUREG_TEXENV5_SOURCE 0x00F8 ///< Texture env 5 source.
#define GPUREG_TEXENV5_OPERAND 0x00F9 ///< Texture env 5 operand.
#define GPUREG_TEXENV5_COMBINER 0x00FA ///< Texture env 5 combiner.
#define GPUREG_TEXENV5_COLOR 0x00FB ///< Texture env 5 color.
#define GPUREG_TEXENV5_SCALE 0x00FC ///< Texture env 5 scale.
#define GPUREG_TEXENV_BUFFER_COLOR 0x00FD ///< Texture env buffer color.
#define GPUREG_00FE 0x00FE ///< Unknown.
#define GPUREG_00FF 0x00FF ///< Unknown.
///@}
///@name Framebuffer registers (0x100-0x13F)
///@{
#define GPUREG_COLOR_OPERATION 0x0100 ///< Configures fragment operation and blend mode.
#define GPUREG_BLEND_FUNC 0x0101 ///< Blend function configuration.
#define GPUREG_LOGIC_OP 0x0102 ///< Logical operator configuration.
#define GPUREG_BLEND_COLOR 0x0103 ///< Blend color.
#define GPUREG_FRAGOP_ALPHA_TEST 0x0104 ///< Alpha test configuration.
#define GPUREG_STENCIL_TEST 0x0105 ///< Stencil test configuration.
#define GPUREG_STENCIL_OP 0x0106 ///< Stencil test operation.
#define GPUREG_DEPTH_COLOR_MASK 0x0107 ///< Depth test and color mask configuration.
#define GPUREG_0108 0x0108 ///< Unknown.
#define GPUREG_0109 0x0109 ///< Unknown.
#define GPUREG_010A 0x010A ///< Unknown.
#define GPUREG_010B 0x010B ///< Unknown.
#define GPUREG_010C 0x010C ///< Unknown.
#define GPUREG_010D 0x010D ///< Unknown.
#define GPUREG_010E 0x010E ///< Unknown.
#define GPUREG_010F 0x010F ///< Unknown.
#define GPUREG_FRAMEBUFFER_INVALIDATE 0x0110 ///< Invalidates the frame buffer.
#define GPUREG_FRAMEBUFFER_FLUSH 0x0111 ///< Flushes the frame buffer.
#define GPUREG_COLORBUFFER_READ 0x0112 ///< Reads from the color buffer.
#define GPUREG_COLORBUFFER_WRITE 0x0113 ///< Writes to the color buffer.
#define GPUREG_DEPTHBUFFER_READ 0x0114 ///< Reads from the depth buffer.
#define GPUREG_DEPTHBUFFER_WRITE 0x0115 ///< Writes to the depth buffer.
#define GPUREG_DEPTHBUFFER_FORMAT 0x0116 ///< Depth buffer format.
#define GPUREG_COLORBUFFER_FORMAT 0x0117 ///< Color buffer format.
#define GPUREG_EARLYDEPTH_TEST2 0x0118 ///< Unknown.
#define GPUREG_0119 0x0119 ///< Unknown.
#define GPUREG_011A 0x011A ///< Unknown.
#define GPUREG_FRAMEBUFFER_BLOCK32 0x011B ///< Frame buffer block 32.
#define GPUREG_DEPTHBUFFER_LOC 0x011C ///< Depth buffer location.
#define GPUREG_COLORBUFFER_LOC 0x011D ///< Color buffer location.
#define GPUREG_FRAMEBUFFER_DIM 0x011E ///< Frame buffer dimensions.
#define GPUREG_011F 0x011F ///< Unknown.
#define GPUREG_GAS_LIGHT_XY 0x0120 ///< Unknown.
#define GPUREG_GAS_LIGHT_Z 0x0121 ///< Unknown.
#define GPUREG_GAS_LIGHT_Z_COLOR 0x0122 ///< Unknown.
#define GPUREG_GAS_LUT_INDEX 0x0123 ///< Unknown.
#define GPUREG_GAS_LUT_DATA 0x0124 ///< Unknown.
#define GPUREG_GAS_ACCMAX_FEEDBACK 0x0125 ///< Unknown.
#define GPUREG_GAS_DELTAZ_DEPTH 0x0126 ///< Unknown.
#define GPUREG_0127 0x0127 ///< Unknown.
#define GPUREG_0128 0x0128 ///< Unknown.
#define GPUREG_0129 0x0129 ///< Unknown.
#define GPUREG_012A 0x012A ///< Unknown.
#define GPUREG_012B 0x012B ///< Unknown.
#define GPUREG_012C 0x012C ///< Unknown.
#define GPUREG_012D 0x012D ///< Unknown.
#define GPUREG_012E 0x012E ///< Unknown.
#define GPUREG_012F 0x012F ///< Unknown.
#define GPUREG_FRAGOP_SHADOW 0x0130 ///< Unknown.
#define GPUREG_0131 0x0131 ///< Unknown.
#define GPUREG_0132 0x0132 ///< Unknown.
#define GPUREG_0133 0x0133 ///< Unknown.
#define GPUREG_0134 0x0134 ///< Unknown.
#define GPUREG_0135 0x0135 ///< Unknown.
#define GPUREG_0136 0x0136 ///< Unknown.
#define GPUREG_0137 0x0137 ///< Unknown.
#define GPUREG_0138 0x0138 ///< Unknown.
#define GPUREG_0139 0x0139 ///< Unknown.
#define GPUREG_013A 0x013A ///< Unknown.
#define GPUREG_013B 0x013B ///< Unknown.
#define GPUREG_013C 0x013C ///< Unknown.
#define GPUREG_013D 0x013D ///< Unknown.
#define GPUREG_013E 0x013E ///< Unknown.
#define GPUREG_013F 0x013F ///< Unknown.
///@}
///@name Fragment lighting registers (0x140-0x1FF)
///@{
#define GPUREG_LIGHT0_SPECULAR0 0x0140 ///< Light 0 specular lighting.
#define GPUREG_LIGHT0_SPECULAR1 0x0141 ///< Light 0 specular lighting.
#define GPUREG_LIGHT0_DIFFUSE 0x0142 ///< Light 0 diffuse lighting.
#define GPUREG_LIGHT0_AMBIENT 0x0143 ///< Light 0 ambient lighting.
#define GPUREG_LIGHT0_XY 0x0144 ///< Light 0 X and Y.
#define GPUREG_LIGHT0_Z 0x0145 ///< Light 0 Z.
#define GPUREG_LIGHT0_SPOTDIR_XY 0x0146 ///< Light 0 spotlight direction X and Y.
#define GPUREG_LIGHT0_SPOTDIR_Z 0x0147 ///< Light 0 spotlight direction Z.
#define GPUREG_0148 0x0148 ///< Unknown.
#define GPUREG_LIGHT0_CONFIG 0x0149 ///< Light 0 configuration.
#define GPUREG_LIGHT0_ATTENUATION_BIAS 0x014A ///< Light 0 attenuation bias.
#define GPUREG_LIGHT0_ATTENUATION_SCALE 0x014B ///< Light 0 attenuation scale.
#define GPUREG_014C 0x014C ///< Unknown.
#define GPUREG_014D 0x014D ///< Unknown.
#define GPUREG_014E 0x014E ///< Unknown.
#define GPUREG_014F 0x014F ///< Unknown.
#define GPUREG_LIGHT1_SPECULAR0 0x0150 ///< Light 1 specular lighting.
#define GPUREG_LIGHT1_SPECULAR1 0x0151 ///< Light 1 specular lighting.
#define GPUREG_LIGHT1_DIFFUSE 0x0152 ///< Light 1 diffuse lighting.
#define GPUREG_LIGHT1_AMBIENT 0x0153 ///< Light 1 ambient lighting.
#define GPUREG_LIGHT1_XY 0x0154 ///< Light 1 X and Y.
#define GPUREG_LIGHT1_Z 0x0155 ///< Light 1 Z.
#define GPUREG_LIGHT1_SPOTDIR_XY 0x0156 ///< Light 1 spotlight direction X and Y.
#define GPUREG_LIGHT1_SPOTDIR_Z 0x0157 ///< Light 1 spotlight direction Z.
#define GPUREG_0158 0x0158 ///< Unknown.
#define GPUREG_LIGHT1_CONFIG 0x0159 ///< Light 1 configuration.
#define GPUREG_LIGHT1_ATTENUATION_BIAS 0x015A ///< Light 1 attenuation bias.
#define GPUREG_LIGHT1_ATTENUATION_SCALE 0x015B ///< Light 1 attenuation scale.
#define GPUREG_015C 0x015C ///< Unknown.
#define GPUREG_015D 0x015D ///< Unknown.
#define GPUREG_015E 0x015E ///< Unknown.
#define GPUREG_015F 0x015F ///< Unknown.
#define GPUREG_LIGHT2_SPECULAR0 0x0160 ///< Light 2 specular lighting.
#define GPUREG_LIGHT2_SPECULAR1 0x0161 ///< Light 2 specular lighting.
#define GPUREG_LIGHT2_DIFFUSE 0x0162 ///< Light 2 diffuse lighting.
#define GPUREG_LIGHT2_AMBIENT 0x0163 ///< Light 2 ambient lighting.
#define GPUREG_LIGHT2_XY 0x0164 ///< Light 2 X and Y.
#define GPUREG_LIGHT2_Z 0x0165 ///< Light 2 Z.
#define GPUREG_LIGHT2_SPOTDIR_XY 0x0166 ///< Light 2 spotlight direction X and Y.
#define GPUREG_LIGHT2_SPOTDIR_Z 0x0167 ///< Light 2 spotlight direction Z.
#define GPUREG_0168 0x0168 ///< Unknown.
#define GPUREG_LIGHT2_CONFIG 0x0169 ///< Light 2 configuration.
#define GPUREG_LIGHT2_ATTENUATION_BIAS 0x016A ///< Light 2 attenuation bias.
#define GPUREG_LIGHT2_ATTENUATION_SCALE 0x016B ///< Light 2 attenuation scale.
#define GPUREG_016C 0x016C ///< Unknown.
#define GPUREG_016D 0x016D ///< Unknown.
#define GPUREG_016E 0x016E ///< Unknown.
#define GPUREG_016F 0x016F ///< Unknown.
#define GPUREG_LIGHT3_SPECULAR0 0x0170 ///< Light 3 specular lighting.
#define GPUREG_LIGHT3_SPECULAR1 0x0171 ///< Light 3 specular lighting.
#define GPUREG_LIGHT3_DIFFUSE 0x0172 ///< Light 3 diffuse lighting.
#define GPUREG_LIGHT3_AMBIENT 0x0173 ///< Light 3 ambient lighting.
#define GPUREG_LIGHT3_XY 0x0174 ///< Light 3 X and Y.
#define GPUREG_LIGHT3_Z 0x0175 ///< Light 3 Z.
#define GPUREG_LIGHT3_SPOTDIR_XY 0x0176 ///< Light 3 spotlight direction X and Y.
#define GPUREG_LIGHT3_SPOTDIR_Z 0x0177 ///< Light 3 spotlight direction Z.
#define GPUREG_0178 0x0178 ///< Unknown.
#define GPUREG_LIGHT3_CONFIG 0x0179 ///< Light 3 configuration.
#define GPUREG_LIGHT3_ATTENUATION_BIAS 0x017A ///< Light 3 attenuation bias.
#define GPUREG_LIGHT3_ATTENUATION_SCALE 0x017B ///< Light 3 attenuation scale.
#define GPUREG_017C 0x017C ///< Unknown.
#define GPUREG_017D 0x017D ///< Unknown.
#define GPUREG_017E 0x017E ///< Unknown.
#define GPUREG_017F 0x017F ///< Unknown.
#define GPUREG_LIGHT4_SPECULAR0 0x0180 ///< Light 4 specular lighting.
#define GPUREG_LIGHT4_SPECULAR1 0x0181 ///< Light 4 specular lighting.
#define GPUREG_LIGHT4_DIFFUSE 0x0182 ///< Light 4 diffuse lighting.
#define GPUREG_LIGHT4_AMBIENT 0x0183 ///< Light 4 ambient lighting.
#define GPUREG_LIGHT4_XY 0x0184 ///< Light 4 X and Y.
#define GPUREG_LIGHT4_Z 0x0185 ///< Light 4 Z.
#define GPUREG_LIGHT4_SPOTDIR_XY 0x0186 ///< Light 4 spotlight direction X and Y.
#define GPUREG_LIGHT4_SPOTDIR_Z 0x0187 ///< Light 4 spotlight direction Z.
#define GPUREG_0188 0x0188 ///< Unknown.
#define GPUREG_LIGHT4_CONFIG 0x0189 ///< Light 4 configuration.
#define GPUREG_LIGHT4_ATTENUATION_BIAS 0x018A ///< Light 4 attenuation bias.
#define GPUREG_LIGHT4_ATTENUATION_SCALE 0x018B ///< Light 4 attenuation scale.
#define GPUREG_018C 0x018C ///< Unknown.
#define GPUREG_018D 0x018D ///< Unknown.
#define GPUREG_018E 0x018E ///< Unknown.
#define GPUREG_018F 0x018F ///< Unknown.
#define GPUREG_LIGHT5_SPECULAR0 0x0190 ///< Light 5 specular lighting.
#define GPUREG_LIGHT5_SPECULAR1 0x0191 ///< Light 5 specular lighting.
#define GPUREG_LIGHT5_DIFFUSE 0x0192 ///< Light 5 diffuse lighting.
#define GPUREG_LIGHT5_AMBIENT 0x0193 ///< Light 5 ambient lighting.
#define GPUREG_LIGHT5_XY 0x0194 ///< Light 5 X and Y.
#define GPUREG_LIGHT5_Z 0x0195 ///< Light 5 Z.
#define GPUREG_LIGHT5_SPOTDIR_XY 0x0196 ///< Light 5 spotlight direction X and Y.
#define GPUREG_LIGHT5_SPOTDIR_Z 0x0197 ///< Light 5 spotlight direction Z.
#define GPUREG_0198 0x0198 ///< Unknown.
#define GPUREG_LIGHT5_CONFIG 0x0199 ///< Light 5 configuration.
#define GPUREG_LIGHT5_ATTENUATION_BIAS 0x019A ///< Light 5 attenuation bias.
#define GPUREG_LIGHT5_ATTENUATION_SCALE 0x019B ///< Light 5 attenuation scale.
#define GPUREG_019C 0x019C ///< Unknown.
#define GPUREG_019D 0x019D ///< Unknown.
#define GPUREG_019E 0x019E ///< Unknown.
#define GPUREG_019F 0x019F ///< Unknown.
#define GPUREG_LIGHT6_SPECULAR0 0x01A0 ///< Light 6 specular lighting.
#define GPUREG_LIGHT6_SPECULAR1 0x01A1 ///< Light 6 specular lighting.
#define GPUREG_LIGHT6_DIFFUSE 0x01A2 ///< Light 6 diffuse lighting.
#define GPUREG_LIGHT6_AMBIENT 0x01A3 ///< Light 6 ambient lighting.
#define GPUREG_LIGHT6_XY 0x01A4 ///< Light 6 X and Y.
#define GPUREG_LIGHT6_Z 0x01A5 ///< Light 6 Z.
#define GPUREG_LIGHT6_SPOTDIR_XY 0x01A6 ///< Light 6 spotlight direction X and Y.
#define GPUREG_LIGHT6_SPOTDIR_Z 0x01A7 ///< Light 6 spotlight direction Z.
#define GPUREG_01A8 0x01A8 ///< Unknown.
#define GPUREG_LIGHT6_CONFIG 0x01A9 ///< Light 6 configuration.
#define GPUREG_LIGHT6_ATTENUATION_BIAS 0x01AA ///< Light 6 attenuation bias.
#define GPUREG_LIGHT6_ATTENUATION_SCALE 0x01AB ///< Light 6 attenuation scale.
#define GPUREG_01AC 0x01AC ///< Unknown.
#define GPUREG_01AD 0x01AD ///< Unknown.
#define GPUREG_01AE 0x01AE ///< Unknown.
#define GPUREG_01AF 0x01AF ///< Unknown.
#define GPUREG_LIGHT7_SPECULAR0 0x01B0 ///< Light 7 specular lighting.
#define GPUREG_LIGHT7_SPECULAR1 0x01B1 ///< Light 7 specular lighting.
#define GPUREG_LIGHT7_DIFFUSE 0x01B2 ///< Light 7 diffuse lighting.
#define GPUREG_LIGHT7_AMBIENT 0x01B3 ///< Light 7 ambient lighting.
#define GPUREG_LIGHT7_XY 0x01B4 ///< Light 7 X and Y.
#define GPUREG_LIGHT7_Z 0x01B5 ///< Light 7 Z.
#define GPUREG_LIGHT7_SPOTDIR_XY 0x01B6 ///< Light 7 spotlight direction X and Y.
#define GPUREG_LIGHT7_SPOTDIR_Z 0x01B7 ///< Light 7 spotlight direction Z.
#define GPUREG_01B8 0x01B8 ///< Unknown.
#define GPUREG_LIGHT7_CONFIG 0x01B9 ///< Light 7 configuration.
#define GPUREG_LIGHT7_ATTENUATION_BIAS 0x01BA ///< Light 7 attenuation bias.
#define GPUREG_LIGHT7_ATTENUATION_SCALE 0x01BB ///< Light 7 attenuation scale.
#define GPUREG_01BC 0x01BC ///< Unknown.
#define GPUREG_01BD 0x01BD ///< Unknown.
#define GPUREG_01BE 0x01BE ///< Unknown.
#define GPUREG_01BF 0x01BF ///< Unknown.
#define GPUREG_LIGHTING_AMBIENT 0x01C0 ///< Ambient lighting.
#define GPUREG_01C1 0x01C1 ///< Unknown.
#define GPUREG_LIGHTING_NUM_LIGHTS 0x01C2 ///< Number of lights.
#define GPUREG_LIGHTING_CONFIG0 0x01C3 ///< Lighting configuration.
#define GPUREG_LIGHTING_CONFIG1 0x01C4 ///< Lighting configuration.
#define GPUREG_LIGHTING_LUT_INDEX 0x01C5 ///< LUT index.
#define GPUREG_LIGHTING_ENABLE1 0x01C6 ///< Lighting toggle.
#define GPUREG_01C7 0x01C7 ///< Unknown.
#define GPUREG_LIGHTING_LUT_DATA0 0x01C8 ///< LUT data 0.
#define GPUREG_LIGHTING_LUT_DATA1 0x01C9 ///< LUT data 1.
#define GPUREG_LIGHTING_LUT_DATA2 0x01CA ///< LUT data 2.
#define GPUREG_LIGHTING_LUT_DATA3 0x01CB ///< LUT data 3.
#define GPUREG_LIGHTING_LUT_DATA4 0x01CC ///< LUT data 4.
#define GPUREG_LIGHTING_LUT_DATA5 0x01CD ///< LUT data 5.
#define GPUREG_LIGHTING_LUT_DATA6 0x01CE ///< LUT data 6.
#define GPUREG_LIGHTING_LUT_DATA7 0x01CF ///< LUT data 7.
#define GPUREG_LIGHTING_LUTINPUT_ABS 0x01D0 ///< LUT input abs.
#define GPUREG_LIGHTING_LUTINPUT_SELECT 0x01D1 ///< LUT input selector.
#define GPUREG_LIGHTING_LUTINPUT_SCALE 0x01D2 ///< LUT input scale.
#define GPUREG_01D3 0x01D3 ///< Unknown.
#define GPUREG_01D4 0x01D4 ///< Unknown.
#define GPUREG_01D5 0x01D5 ///< Unknown.
#define GPUREG_01D6 0x01D6 ///< Unknown.
#define GPUREG_01D7 0x01D7 ///< Unknown.
#define GPUREG_01D8 0x01D8 ///< Unknown.
#define GPUREG_LIGHTING_LIGHT_PERMUTATION 0x01D9 ///< Light permutation.
#define GPUREG_01DA 0x01DA ///< Unknown.
#define GPUREG_01DB 0x01DB ///< Unknown.
#define GPUREG_01DC 0x01DC ///< Unknown.
#define GPUREG_01DD 0x01DD ///< Unknown.
#define GPUREG_01DE 0x01DE ///< Unknown.
#define GPUREG_01DF 0x01DF ///< Unknown.
#define GPUREG_01E0 0x01E0 ///< Unknown.
#define GPUREG_01E1 0x01E1 ///< Unknown.
#define GPUREG_01E2 0x01E2 ///< Unknown.
#define GPUREG_01E3 0x01E3 ///< Unknown.
#define GPUREG_01E4 0x01E4 ///< Unknown.
#define GPUREG_01E5 0x01E5 ///< Unknown.
#define GPUREG_01E6 0x01E6 ///< Unknown.
#define GPUREG_01E7 0x01E7 ///< Unknown.
#define GPUREG_01E8 0x01E8 ///< Unknown.
#define GPUREG_01E9 0x01E9 ///< Unknown.
#define GPUREG_01EA 0x01EA ///< Unknown.
#define GPUREG_01EB 0x01EB ///< Unknown.
#define GPUREG_01EC 0x01EC ///< Unknown.
#define GPUREG_01ED 0x01ED ///< Unknown.
#define GPUREG_01EE 0x01EE ///< Unknown.
#define GPUREG_01EF 0x01EF ///< Unknown.
#define GPUREG_01F0 0x01F0 ///< Unknown.
#define GPUREG_01F1 0x01F1 ///< Unknown.
#define GPUREG_01F2 0x01F2 ///< Unknown.
#define GPUREG_01F3 0x01F3 ///< Unknown.
#define GPUREG_01F4 0x01F4 ///< Unknown.
#define GPUREG_01F5 0x01F5 ///< Unknown.
#define GPUREG_01F6 0x01F6 ///< Unknown.
#define GPUREG_01F7 0x01F7 ///< Unknown.
#define GPUREG_01F8 0x01F8 ///< Unknown.
#define GPUREG_01F9 0x01F9 ///< Unknown.
#define GPUREG_01FA 0x01FA ///< Unknown.
#define GPUREG_01FB 0x01FB ///< Unknown.
#define GPUREG_01FC 0x01FC ///< Unknown.
#define GPUREG_01FD 0x01FD ///< Unknown.
#define GPUREG_01FE 0x01FE ///< Unknown.
#define GPUREG_01FF 0x01FF ///< Unknown.
///@}
///@name Geometry pipeline registers (0x200-0x27F)
///@{
#define GPUREG_ATTRIBBUFFERS_LOC 0x0200 ///< Attribute buffers location.
#define GPUREG_ATTRIBBUFFERS_FORMAT_LOW 0x0201 ///< Attribute buffers format low.
#define GPUREG_ATTRIBBUFFERS_FORMAT_HIGH 0x0202 ///< Attribute buffers format high.
#define GPUREG_ATTRIBBUFFER0_OFFSET 0x0203 ///< Attribute buffers 0 offset.
#define GPUREG_ATTRIBBUFFER0_CONFIG1 0x0204 ///< Attribute buffers 0 configuration.
#define GPUREG_ATTRIBBUFFER0_CONFIG2 0x0205 ///< Attribute buffers 0 configuration.
#define GPUREG_ATTRIBBUFFER1_OFFSET 0x0206 ///< Attribute buffers 1 offset.
#define GPUREG_ATTRIBBUFFER1_CONFIG1 0x0207 ///< Attribute buffers 1 configuration.
#define GPUREG_ATTRIBBUFFER1_CONFIG2 0x0208 ///< Attribute buffers 1 configuration.
#define GPUREG_ATTRIBBUFFER2_OFFSET 0x0209 ///< Attribute buffers 2 offset.
#define GPUREG_ATTRIBBUFFER2_CONFIG1 0x020A ///< Attribute buffers 2 configuration.
#define GPUREG_ATTRIBBUFFER2_CONFIG2 0x020B ///< Attribute buffers 2 configuration.
#define GPUREG_ATTRIBBUFFER3_OFFSET 0x020C ///< Attribute buffers 3 offset.
#define GPUREG_ATTRIBBUFFER3_CONFIG1 0x020D ///< Attribute buffers 3 configuration.
#define GPUREG_ATTRIBBUFFER3_CONFIG2 0x020E ///< Attribute buffers 3 configuration.
#define GPUREG_ATTRIBBUFFER4_OFFSET 0x020F ///< Attribute buffers 4 offset.
#define GPUREG_ATTRIBBUFFER4_CONFIG1 0x0210 ///< Attribute buffers 4 configuration.
#define GPUREG_ATTRIBBUFFER4_CONFIG2 0x0211 ///< Attribute buffers 4 configuration.
#define GPUREG_ATTRIBBUFFER5_OFFSET 0x0212 ///< Attribute buffers 5 offset.
#define GPUREG_ATTRIBBUFFER5_CONFIG1 0x0213 ///< Attribute buffers 5 configuration.
#define GPUREG_ATTRIBBUFFER5_CONFIG2 0x0214 ///< Attribute buffers 5 configuration.
#define GPUREG_ATTRIBBUFFER6_OFFSET 0x0215 ///< Attribute buffers 6 offset.
#define GPUREG_ATTRIBBUFFER6_CONFIG1 0x0216 ///< Attribute buffers 6 configuration.
#define GPUREG_ATTRIBBUFFER6_CONFIG2 0x0217 ///< Attribute buffers 6 configuration.
#define GPUREG_ATTRIBBUFFER7_OFFSET 0x0218 ///< Attribute buffers 7 offset.
#define GPUREG_ATTRIBBUFFER7_CONFIG1 0x0219 ///< Attribute buffers 7 configuration.
#define GPUREG_ATTRIBBUFFER7_CONFIG2 0x021A ///< Attribute buffers 7 configuration.
#define GPUREG_ATTRIBBUFFER8_OFFSET 0x021B ///< Attribute buffers 8 offset.
#define GPUREG_ATTRIBBUFFER8_CONFIG1 0x021C ///< Attribute buffers 8 configuration.
#define GPUREG_ATTRIBBUFFER8_CONFIG2 0x021D ///< Attribute buffers 8 configuration.
#define GPUREG_ATTRIBBUFFER9_OFFSET 0x021E ///< Attribute buffers 9 offset.
#define GPUREG_ATTRIBBUFFER9_CONFIG1 0x021F ///< Attribute buffers 9 configuration.
#define GPUREG_ATTRIBBUFFER9_CONFIG2 0x0220 ///< Attribute buffers 9 configuration.
#define GPUREG_ATTRIBBUFFERA_OFFSET 0x0221 ///< Attribute buffers A offset.
#define GPUREG_ATTRIBBUFFERA_CONFIG1 0x0222 ///< Attribute buffers A configuration.
#define GPUREG_ATTRIBBUFFERA_CONFIG2 0x0223 ///< Attribute buffers A configuration.
#define GPUREG_ATTRIBBUFFERB_OFFSET 0x0224 ///< Attribute buffers B offset.
#define GPUREG_ATTRIBBUFFERB_CONFIG1 0x0225 ///< Attribute buffers B configuration.
#define GPUREG_ATTRIBBUFFERB_CONFIG2 0x0226 ///< Attribute buffers B configuration.
#define GPUREG_INDEXBUFFER_CONFIG 0x0227 ///< Index buffer configuration.
#define GPUREG_NUMVERTICES 0x0228 ///< Number of vertices.
#define GPUREG_GEOSTAGE_CONFIG 0x0229 ///< Geometry stage configuration.
#define GPUREG_VERTEX_OFFSET 0x022A ///< Vertex offset.
#define GPUREG_022B 0x022B ///< Unknown.
#define GPUREG_022C 0x022C ///< Unknown.
#define GPUREG_POST_VERTEX_CACHE_NUM 0x022D ///< Unknown.
#define GPUREG_DRAWARRAYS 0x022E ///< Draw arrays trigger.
#define GPUREG_DRAWELEMENTS 0x022F ///< Draw arrays elements.
#define GPUREG_0230 0x0230 ///< Unknown.
#define GPUREG_VTX_FUNC 0x0231 ///< Unknown.
#define GPUREG_FIXEDATTRIB_INDEX 0x0232 ///< Fixed attribute index.
#define GPUREG_FIXEDATTRIB_DATA0 0x0233 ///< Fixed attribute data 0.
#define GPUREG_FIXEDATTRIB_DATA1 0x0234 ///< Fixed attribute data 1.
#define GPUREG_FIXEDATTRIB_DATA2 0x0235 ///< Fixed attribute data 2.
#define GPUREG_0236 0x0236 ///< Unknown.
#define GPUREG_0237 0x0237 ///< Unknown.
#define GPUREG_CMDBUF_SIZE0 0x0238 ///< Command buffer size 0.
#define GPUREG_CMDBUF_SIZE1 0x0239 ///< Command buffer size 1.
#define GPUREG_CMDBUF_ADDR0 0x023A ///< Command buffer address 0.
#define GPUREG_CMDBUF_ADDR1 0x023B ///< Command buffer address 1.
#define GPUREG_CMDBUF_JUMP0 0x023C ///< Command buffer jump 0.
#define GPUREG_CMDBUF_JUMP1 0x023D ///< Command buffer jump 1.
#define GPUREG_023E 0x023E ///< Unknown.
#define GPUREG_023F 0x023F ///< Unknown.
#define GPUREG_0240 0x0240 ///< Unknown.
#define GPUREG_0241 0x0241 ///< Unknown.
#define GPUREG_VSH_NUM_ATTR 0x0242 ///< Unknown.
#define GPUREG_0243 0x0243 ///< Unknown.
#define GPUREG_VSH_COM_MODE 0x0244 ///< Unknown.
#define GPUREG_START_DRAW_FUNC0 0x0245 ///< Unknown.
#define GPUREG_0246 0x0246 ///< Unknown.
#define GPUREG_0247 0x0247 ///< Unknown.
#define GPUREG_0248 0x0248 ///< Unknown.
#define GPUREG_0249 0x0249 ///< Unknown.
#define GPUREG_VSH_OUTMAP_TOTAL1 0x024A ///< Unknown.
#define GPUREG_024B 0x024B ///< Unknown.
#define GPUREG_024C 0x024C ///< Unknown.
#define GPUREG_024D 0x024D ///< Unknown.
#define GPUREG_024E 0x024E ///< Unknown.
#define GPUREG_024F 0x024F ///< Unknown.
#define GPUREG_0250 0x0250 ///< Unknown.
#define GPUREG_VSH_OUTMAP_TOTAL2 0x0251 ///< Unknown.
#define GPUREG_GSH_MISC0 0x0252 ///< Unknown.
#define GPUREG_GEOSTAGE_CONFIG2 0x0253 ///< Unknown.
#define GPUREG_GSH_MISC1 0x0254 ///< Unknown.
#define GPUREG_0255 0x0255 ///< Unknown.
#define GPUREG_0256 0x0256 ///< Unknown.
#define GPUREG_0257 0x0257 ///< Unknown.
#define GPUREG_0258 0x0258 ///< Unknown.
#define GPUREG_0259 0x0259 ///< Unknown.
#define GPUREG_025A 0x025A ///< Unknown.
#define GPUREG_025B 0x025B ///< Unknown.
#define GPUREG_025C 0x025C ///< Unknown.
#define GPUREG_025D 0x025D ///< Unknown.
#define GPUREG_PRIMITIVE_CONFIG 0x025E ///< Primitive configuration.
#define GPUREG_RESTART_PRIMITIVE 0x025F ///< Restart primitive flag.
#define GPUREG_0260 0x0260 ///< Unknown.
#define GPUREG_0261 0x0261 ///< Unknown.
#define GPUREG_0262 0x0262 ///< Unknown.
#define GPUREG_0263 0x0263 ///< Unknown.
#define GPUREG_0264 0x0264 ///< Unknown.
#define GPUREG_0265 0x0265 ///< Unknown.
#define GPUREG_0266 0x0266 ///< Unknown.
#define GPUREG_0267 0x0267 ///< Unknown.
#define GPUREG_0268 0x0268 ///< Unknown.
#define GPUREG_0269 0x0269 ///< Unknown.
#define GPUREG_026A 0x026A ///< Unknown.
#define GPUREG_026B 0x026B ///< Unknown.
#define GPUREG_026C 0x026C ///< Unknown.
#define GPUREG_026D 0x026D ///< Unknown.
#define GPUREG_026E 0x026E ///< Unknown.
#define GPUREG_026F 0x026F ///< Unknown.
#define GPUREG_0270 0x0270 ///< Unknown.
#define GPUREG_0271 0x0271 ///< Unknown.
#define GPUREG_0272 0x0272 ///< Unknown.
#define GPUREG_0273 0x0273 ///< Unknown.
#define GPUREG_0274 0x0274 ///< Unknown.
#define GPUREG_0275 0x0275 ///< Unknown.
#define GPUREG_0276 0x0276 ///< Unknown.
#define GPUREG_0277 0x0277 ///< Unknown.
#define GPUREG_0278 0x0278 ///< Unknown.
#define GPUREG_0279 0x0279 ///< Unknown.
#define GPUREG_027A 0x027A ///< Unknown.
#define GPUREG_027B 0x027B ///< Unknown.
#define GPUREG_027C 0x027C ///< Unknown.
#define GPUREG_027D 0x027D ///< Unknown.
#define GPUREG_027E 0x027E ///< Unknown.
#define GPUREG_027F 0x027F ///< Unknown.
///@}
///@name Geometry shader registers (0x280-0x2AF)
///@{
#define GPUREG_GSH_BOOLUNIFORM 0x0280 ///< Geometry shader bool uniforms.
#define GPUREG_GSH_INTUNIFORM_I0 0x0281 ///< Geometry shader integer uniform 0.
#define GPUREG_GSH_INTUNIFORM_I1 0x0282 ///< Geometry shader integer uniform 1.
#define GPUREG_GSH_INTUNIFORM_I2 0x0283 ///< Geometry shader integer uniform 2.
#define GPUREG_GSH_INTUNIFORM_I3 0x0284 ///< Geometry shader integer uniform 3.
#define GPUREG_0285 0x0285 ///< Unknown.
#define GPUREG_0286 0x0286 ///< Unknown.
#define GPUREG_0287 0x0287 ///< Unknown.
#define GPUREG_0288 0x0288 ///< Unknown.
#define GPUREG_GSH_INPUTBUFFER_CONFIG 0x0289 ///< Geometry shader input buffer configuration.
#define GPUREG_GSH_ENTRYPOINT 0x028A ///< Geometry shader entry point.
#define GPUREG_GSH_ATTRIBUTES_PERMUTATION_LOW 0x028B ///< Geometry shader attribute permutations low.
#define GPUREG_GSH_ATTRIBUTES_PERMUTATION_HIGH 0x028C ///< Geometry shader attribute permutations high.
#define GPUREG_GSH_OUTMAP_MASK 0x028D ///< Geometry shader output map mask.
#define GPUREG_028E 0x028E ///< Unknown.
#define GPUREG_GSH_CODETRANSFER_END 0x028F ///< Geometry shader code transfer end trigger.
#define GPUREG_GSH_FLOATUNIFORM_CONFIG 0x0290 ///< Geometry shader float uniform configuration.
#define GPUREG_GSH_FLOATUNIFORM_DATA 0x0291 ///< Geometry shader float uniform data.
#define GPUREG_0299 0x0299 ///< Unknown.
#define GPUREG_029A 0x029A ///< Unknown.
#define GPUREG_GSH_CODETRANSFER_CONFIG 0x029B ///< Geometry shader code transfer configuration.
#define GPUREG_GSH_CODETRANSFER_DATA 0x029C ///< Geometry shader code transfer data.
#define GPUREG_02A4 0x02A4 ///< Unknown.
#define GPUREG_GSH_OPDESCS_CONFIG 0x02A5 ///< Geometry shader operand description configuration.
#define GPUREG_GSH_OPDESCS_DATA 0x02A6 ///< Geometry shader operand description data.
#define GPUREG_02AE 0x02AE ///< Unknown.
#define GPUREG_02AF 0x02AF ///< Unknown.
///@}
///@name Vertex shader registers (0x2B0-0x2DF)
///@{
#define GPUREG_VSH_BOOLUNIFORM 0x02B0 ///< Vertex shader bool uniforms.
#define GPUREG_VSH_INTUNIFORM_I0 0x02B1 ///< Vertex shader integer uniform 0.
#define GPUREG_VSH_INTUNIFORM_I1 0x02B2 ///< Vertex shader integer uniform 1.
#define GPUREG_VSH_INTUNIFORM_I2 0x02B3 ///< Vertex shader integer uniform 2.
#define GPUREG_VSH_INTUNIFORM_I3 0x02B4 ///< Vertex shader integer uniform 3.
#define GPUREG_02B5 0x02B5 ///< Unknown.
#define GPUREG_02B6 0x02B6 ///< Unknown.
#define GPUREG_02B7 0x02B7 ///< Unknown.
#define GPUREG_02B8 0x02B8 ///< Unknown.
#define GPUREG_VSH_INPUTBUFFER_CONFIG 0x02B9 ///< Vertex shader input buffer configuration.
#define GPUREG_VSH_ENTRYPOINT 0x02BA ///< Vertex shader entry point.
#define GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW 0x02BB ///< Vertex shader attribute permutations low.
#define GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH 0x02BC ///< Vertex shader attribute permutations high.
#define GPUREG_VSH_OUTMAP_MASK 0x02BD ///< Vertex shader output map mask.
#define GPUREG_02BE 0x02BE ///< Unknown.
#define GPUREG_VSH_CODETRANSFER_END 0x02BF ///< Vertex shader code transfer end trigger.
#define GPUREG_VSH_FLOATUNIFORM_CONFIG 0x02C0 ///< Vertex shader float uniform configuration.
#define GPUREG_VSH_FLOATUNIFORM_DATA 0x02C1 ///< Vertex shader float uniform data.
#define GPUREG_02C9 0x02C9 ///< Unknown.
#define GPUREG_02CA 0x02CA ///< Unknown.
#define GPUREG_VSH_CODETRANSFER_CONFIG 0x02CB ///< Vertex shader code transfer configuration.
#define GPUREG_VSH_CODETRANSFER_DATA 0x02CC ///< Vertex shader code transfer data.
#define GPUREG_02D4 0x02D4 ///< Unknown.
#define GPUREG_VSH_OPDESCS_CONFIG 0x02D5 ///< Vertex shader operand description configuration.
#define GPUREG_VSH_OPDESCS_DATA 0x02D6 ///< Vertex shader operand description data.
#define GPUREG_02DE 0x02DE ///< Unknown.
#define GPUREG_02DF 0x02DF ///< Unknown.
///@}
///@name Unknown registers (0x2E0-0x2FF)
///@{
#define GPUREG_02E0 0x02E0 ///< Unknown.
#define GPUREG_02E1 0x02E1 ///< Unknown.
#define GPUREG_02E2 0x02E2 ///< Unknown.
#define GPUREG_02E3 0x02E3 ///< Unknown.
#define GPUREG_02E4 0x02E4 ///< Unknown.
#define GPUREG_02E5 0x02E5 ///< Unknown.
#define GPUREG_02E6 0x02E6 ///< Unknown.
#define GPUREG_02E7 0x02E7 ///< Unknown.
#define GPUREG_02E8 0x02E8 ///< Unknown.
#define GPUREG_02E9 0x02E9 ///< Unknown.
#define GPUREG_02EA 0x02EA ///< Unknown.
#define GPUREG_02EB 0x02EB ///< Unknown.
#define GPUREG_02EC 0x02EC ///< Unknown.
#define GPUREG_02ED 0x02ED ///< Unknown.
#define GPUREG_02EE 0x02EE ///< Unknown.
#define GPUREG_02EF 0x02EF ///< Unknown.
#define GPUREG_02F0 0x02F0 ///< Unknown.
#define GPUREG_02F1 0x02F1 ///< Unknown.
#define GPUREG_02F2 0x02F2 ///< Unknown.
#define GPUREG_02F3 0x02F3 ///< Unknown.
#define GPUREG_02F4 0x02F4 ///< Unknown.
#define GPUREG_02F5 0x02F5 ///< Unknown.
#define GPUREG_02F6 0x02F6 ///< Unknown.
#define GPUREG_02F7 0x02F7 ///< Unknown.
#define GPUREG_02F8 0x02F8 ///< Unknown.
#define GPUREG_02F9 0x02F9 ///< Unknown.
#define GPUREG_02FA 0x02FA ///< Unknown.
#define GPUREG_02FB 0x02FB ///< Unknown.
#define GPUREG_02FC 0x02FC ///< Unknown.
#define GPUREG_02FD 0x02FD ///< Unknown.
#define GPUREG_02FE 0x02FE ///< Unknown.
#define GPUREG_02FF 0x02FF ///< Unknown.
///@}

View File

@ -1,59 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "mem_map.h"
#define GX_REGS_BASE (IO_MEM_ARM11_ONLY + 0x200000)
#define REG_GX_GPU_CLK *((vu32*)(GX_REGS_BASE + 0x0004)) // ?
// PSC (memory fill) regs.
#define REG_GX_PSC_FILL0_S_ADDR *((vu32*)(GX_REGS_BASE + 0x0010)) // Start address
#define REG_GX_PSC_FILL0_E_ADDR *((vu32*)(GX_REGS_BASE + 0x0014)) // End address
#define REG_GX_PSC_FILL0_VAL *((vu32*)(GX_REGS_BASE + 0x0018)) // Fill value
#define REG_GX_PSC_FILL0_CNT *((vu32*)(GX_REGS_BASE + 0x001C))
#define REG_GX_PSC_FILL1_S_ADDR *((vu32*)(GX_REGS_BASE + 0x0020))
#define REG_GX_PSC_FILL1_E_ADDR *((vu32*)(GX_REGS_BASE + 0x0024))
#define REG_GX_PSC_FILL1_VAL *((vu32*)(GX_REGS_BASE + 0x0028))
#define REG_GX_PSC_FILL1_CNT *((vu32*)(GX_REGS_BASE + 0x002C))
#define REG_GX_PSC_VRAM *((vu32*)(GX_REGS_BASE + 0x0030)) // gsp mudule only changes bit 8-11.
#define REG_GX_PSC_STAT *((vu32*)(GX_REGS_BASE + 0x0034))
// PDC0/1 regs see lcd.h.
// PPF (transfer engine) regs.
#define REG_GX_PPF_IN_ADDR *((vu32*)(GX_REGS_BASE + 0x0C00))
#define REG_GX_PPF_OUT_ADDR *((vu32*)(GX_REGS_BASE + 0x0C04))
#define REG_GX_PPF_DT_OUTDIM *((vu32*)(GX_REGS_BASE + 0x0C08)) // Display transfer output dimensions.
#define REG_GX_PPF_DT_INDIM *((vu32*)(GX_REGS_BASE + 0x0C0C)) // Display transfer input dimensions.
#define REG_GX_PPF_FlAGS *((vu32*)(GX_REGS_BASE + 0x0C10))
#define REG_GX_PPF_UNK14 *((vu32*)(GX_REGS_BASE + 0x0C14)) // Transfer interval?
#define REG_GX_PPF_CNT *((vu32*)(GX_REGS_BASE + 0x0C18))
#define REG_GX_PPF_IRQ_POS *((vu32*)(GX_REGS_BASE + 0x0C1C)) // ?
#define REG_GX_PPF_LEN *((vu32*)(GX_REGS_BASE + 0x0C20)) // Texture copy size in bytes.
#define REG_GX_PPF_TC_INDIM *((vu32*)(GX_REGS_BASE + 0x0C24)) // Texture copy input width and gap in 16 byte units.
#define REG_GX_PPF_TC_OUTDIM *((vu32*)(GX_REGS_BASE + 0x0C28)) // Texture copy output width and gap in 16 byte units.
// P3D (GPU internal) regs. See gpu_regs.h.
#define REG_GX_P3D(reg) *((vu32*)(GX_REGS_BASE + 0x1000 + ((reg) * 4)))

View File

@ -1,105 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Based on code from https://github.com/smealum/ctrulib
*/
#include "types.h"
#include "mem_map.h"
#define HID_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x46000)
#define REG_HID_PAD (*((vu16*)(HID_REGS_BASE + 0x0)) ^ 0xFFFu)
#define REG_HID_PADCNT *((vu16*)(HID_REGS_BASE + 0x2))
enum
{
KEY_A = 1u<<0, // A
KEY_B = 1u<<1, // B
KEY_SELECT = 1u<<2, // Select
KEY_START = 1u<<3, // Start
KEY_DRIGHT = 1u<<4, // D-Pad Right
KEY_DLEFT = 1u<<5, // D-Pad Left
KEY_DUP = 1u<<6, // D-Pad Up
KEY_DDOWN = 1u<<7, // D-Pad Down
KEY_R = 1u<<8, // R
KEY_L = 1u<<9, // L
KEY_X = 1u<<10, // X
KEY_Y = 1u<<11, // Y
KEY_ZL = 1u<<14, // ZL (New 3DS only)
KEY_ZR = 1u<<15, // ZR (New 3DS only)
KEY_TOUCH = 1u<<20, // Touch (Not actually provided by HID)
KEY_CSTICK_RIGHT = 1u<<24, // C-Stick Right (New 3DS only)
KEY_CSTICK_LEFT = 1u<<25, // C-Stick Left (New 3DS only)
KEY_CSTICK_UP = 1u<<26, // C-Stick Up (New 3DS only)
KEY_CSTICK_DOWN = 1u<<27, // C-Stick Down (New 3DS only)
KEY_CPAD_RIGHT = 1u<<28, // Circle Pad Right
KEY_CPAD_LEFT = 1u<<29, // Circle Pad Left
KEY_CPAD_UP = 1u<<30, // Circle Pad Up
KEY_CPAD_DOWN = 1u<<31, // Circle Pad Down
// Generic catch-all directions
KEY_UP = KEY_DUP | KEY_CPAD_UP, // D-Pad Up or Circle Pad Up
KEY_DOWN = KEY_DDOWN | KEY_CPAD_DOWN, // D-Pad Down or Circle Pad Down
KEY_LEFT = KEY_DLEFT | KEY_CPAD_LEFT, // D-Pad Left or Circle Pad Left
KEY_RIGHT = KEY_DRIGHT | KEY_CPAD_RIGHT, // D-Pad Right or Circle Pad Right
// Masks
KEY_DPAD_MASK = KEY_DDOWN | KEY_DUP | KEY_DLEFT | KEY_DRIGHT,
KEY_CSTICK_MASK = KEY_CSTICK_DOWN | KEY_CSTICK_UP | KEY_CSTICK_LEFT | KEY_CSTICK_RIGHT,
KEY_CPAD_MASK = KEY_CPAD_DOWN | KEY_CPAD_UP | KEY_CPAD_LEFT | KEY_CPAD_RIGHT
};
// Extra keys use with hidGetExtraKeys()
enum
{
KEY_POWER = 1u<<0,
KEY_POWER_HELD = 1u<<1,
KEY_HOME = 1u<<2, // Auto clears on release
KEY_WIFI = 1u<<3,
KEY_SHELL = 1u<<4, // Auto clears on open
KEY_BAT_CHARGING = 1u<<5, // Auto clears when charging stops
KEY_VOL_SLIDER = 1u<<6
};
typedef struct
{
u16 x;
u16 y;
} TouchPos;
typedef struct
{
s16 x;
s16 y;
} CpadPos;
void hidInit(void);
void hidScanInput(void);
u32 hidKeysHeld(void);
u32 hidKeysDown(void);
u32 hidKeysUp(void);
const TouchPos* hidGetTouchPosPtr(void);
const CpadPos* hidGetCpadPosPtr(void);
u32 hidGetExtraKeys(u32 clearMask);

View File

@ -1,164 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#define I2C1_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x61000)
#define I2C2_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x44000)
#define I2C3_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x48000)
typedef struct
{
vu8 data; // 0x0
vu8 cnt; // 0x1
vu16 cntex; // 0x2
vu16 scl; // 0x4
} I2cBus;
static_assert(offsetof(I2cBus, scl) == 4, "Error: Member scl of I2cBus is not at offset 4!");
enum
{
I2C_BUS1 = 0u,
I2C_BUS2 = 1u,
I2C_BUS3 = 2u
};
ALWAYS_INLINE I2cBus* getI2cBusRegs(u8 busId)
{
switch(busId)
{
case I2C_BUS1:
return (I2cBus*)I2C1_REGS_BASE;
case I2C_BUS2:
return (I2cBus*)I2C2_REGS_BASE;
case I2C_BUS3:
return (I2cBus*)I2C3_REGS_BASE;
default:
return NULL;
}
}
// REG_I2C_CNT
#define I2C_STOP (1u)
#define I2C_START (1u<<1)
#define I2C_ERROR (1u<<2)
#define I2C_ACK (1u<<4)
#define I2C_DIR_W (0u)
#define I2C_DIR_R (1u<<5)
#define I2C_IRQ_EN (1u<<6)
#define I2C_EN (1u<<7)
// REG_I2C_CNTEX
#define I2C_SCL_STATE (1u) // Read-only SCL line state?
#define I2C_CLK_STRETCH (1u<<1) // Enables clock stretching.
#define I2C_UNK_CNTEX15 (1u<<15) // "LGCY" Legacy related?
// REG_I2C_SCL
#define I2C_DELAYS(high, low) ((high)<<8 | (low)) // "PRD" TODO: How long and when does it delay?
typedef enum
{
I2C_DEV_TWL_MCU = 0u, // DSi mode MCU
I2C_DEV_CAMERA1 = 1u, // Internal self-facing camera
I2C_DEV_CAMERA2 = 2u, // External right camera
I2C_DEV_CTR_MCU = 3u,
I2C_DEV_CAMERA3 = 4u, // External left camera
I2C_DEV_LCD0 = 5u, // Upper LCD
I2C_DEV_LCD1 = 6u, // Lower LCD
I2C_DEV_UNK7 = 7u, // Debug?
I2C_DEV_UNK8 = 8u, // Debug?
I2C_DEV_UNK9 = 9u, // HID debug?
I2C_DEV_GYRO_OLD = 10u, // Old 3DS only?
I2C_DEV_GYRO_NEW = 11u, // New 3DS only?
I2C_DEV_UNK12 = 12u, // HID "DebugPad"?
I2C_DEV_IR = 13u, // Infrared (IrDA)
I2C_DEV_EEPROM = 14u, // Dev unit only?
I2C_DEV_NFC = 15u,
I2C_DEV_QTM = 16u, // IO expander chip (New 3DS only)
I2C_DEV_N3DS_HID = 17u // C-Stick and ZL/ZR buttons
} I2cDevice;
/**
* @brief Initializes the I2C buses. Call this only once.
*/
void I2C_init(void);
/**
* @brief Reads data from a I2C register to a buffer.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
* @param out The output buffer pointer.
* @param[in] size The read size.
*
* @return Returns true on success and false on failure.
*/
bool I2C_readRegBuf(I2cDevice devId, u8 regAddr, u8 *out, u32 size);
/**
* @brief Writes a buffer to a I2C register.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
* @param[in] in The input buffer pointer.
* @param[in] size The write size.
*
* @return Returns true on success and false on failure.
*/
bool I2C_writeRegBuf(I2cDevice devId, u8 regAddr, const u8 *in, u32 size);
/**
* @brief Reads a byte from a I2C register.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
*
* @return Returns the value read on success otherwise 0xFF.
*/
u8 I2C_readReg(I2cDevice devId, u8 regAddr);
/**
* @brief Writes a byte to a I2C register.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
* @param[in] data The data to write.
*
* @return Returns true on success and false on failure.
*/
bool I2C_writeReg(I2cDevice devId, u8 regAddr, u8 data);
/**
* @brief Writes a byte to a I2C register without interrupts.
*
* @param[in] devId The device ID. Use the enum above.
* @param[in] regAddr The register address.
* @param[in] data The data to write.
*
* @return Returns true on success and false on failure.
*/
bool I2C_writeRegIntSafe(I2cDevice devId, u8 regAddr, u8 data);

View File

@ -1,202 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "arm.h"
typedef enum
{
IRQ_IPI0 = 0u,
IRQ_IPI1 = 1u,
IRQ_IPI2 = 2u,
IRQ_IPI3 = 3u,
IRQ_IPI4 = 4u,
IRQ_IPI5 = 5u,
IRQ_IPI6 = 6u,
IRQ_IPI7 = 7u,
IRQ_IPI8 = 8u,
IRQ_IPI9 = 9u,
IRQ_IPI10 = 10u,
IRQ_IPI11 = 11u,
IRQ_IPI12 = 12u,
IRQ_IPI13 = 13u,
IRQ_IPI14 = 14u,
IRQ_IPI15 = 15u,
IRQ_TIMER = 29u, // MPCore timer.
IRQ_WATCHDOG = 30u, // MPCore watchdog.
IRQ_SPI2 = 36u, // SPI bus 2 interrupt status update.
IRQ_UART = 37u, // New3DS-only UART?
IRQ_PSC0 = 40u,
IRQ_PSC1 = 41u,
IRQ_PDC0 = 42u, // PDC0 topscreen H-/VBlank and errors.
IRQ_PDC1 = 43u, // PDC1 bottom screen H-/VBlank and errors.
IRQ_PPF = 44u,
IRQ_P3D = 45u,
IRQ_CDMA_EVENT0 = 48u, // Old3DS CDMA.
IRQ_CDMA_EVENT1 = 49u, // Old3DS CDMA.
IRQ_CDMA_EVENT2 = 50u, // Old3DS CDMA.
IRQ_CDMA_EVENT3 = 51u, // Old3DS CDMA.
IRQ_CDMA_EVENT4 = 52u, // Old3DS CDMA.
IRQ_CDMA_EVENT5 = 53u, // Old3DS CDMA.
IRQ_CDMA_EVENT6 = 54u, // Old3DS CDMA.
IRQ_CDMA_EVENT7 = 55u, // Old3DS CDMA.
IRQ_CDMA_EVENT8 = 56u, // Old3DS CDMA.
IRQ_CDMA_FAULT = 57u, // Old3DS CDMA.
IRQ_CDMA2_EVENT = 58u, // New3DS-only CDMA event 0-31.
IRQ_CDMA2_FAULT = 59u, // New3DS-only CDMA.
IRQ_TOSHSD2 = 64u, // Toshsd 2 SDIO controller (WiFi).
IRQ_TOSHSD2_IRQ = 65u, // Toshsd 2 SDIO IRQ pin (WiFi).
IRQ_TOSHSD3 = 66u, // Toshsd 3 SDIO controller.
IRQ_TOSHSD3_IRQ = 67u, // Toshsd 3 SDIO IRQ pin.
IRQ_NTRCARD = 68u, // NTRCARD controller.
IRQ_L2B1 = 69u, // New3DS-only first L2B converter.
IRQ_L2B2 = 70u, // New3DS-only second L2B converter.
IRQ_CAM1 = 72u, // Camera 1 (DSi).
IRQ_CAM2 = 73u, // Camera 2 (left eye).
IRQ_DSP = 74u,
IRQ_Y2R1 = 75u,
IRQ_LGYFB_BOT = 76u, // Legacy framebuffer bottom screen.
IRQ_LGYFB_TOP = 77u, // Legacy framebuffer top screen.
IRQ_Y2R2 = 78u, // New3DS-only.
IRQ_G1 = 79u, // New3DS-only Hantro G1 decoder.
IRQ_PXI_SYNC = 80u,
IRQ_PXI_SYNC2 = 81u,
IRQ_PXI_NOT_FULL = 82u,
IRQ_PXI_NOT_EMPTY = 83u,
IRQ_I2C1 = 84u,
IRQ_I2C2 = 85u,
IRQ_SPI3 = 86u, // SPI bus 3 interrupt status update.
IRQ_SPI1 = 87u, // SPI bus 1 interrupt status update.
IRQ_PDN = 88u,
IRQ_LGY_SLEEP = 89u, // Triggers if legacy mode enters sleep.
IRQ_MIC = 90u,
IRQ_HID_PADCNT = 91u,
IRQ_I2C3 = 92u,
IRQ_DS_WIFI = 95u,
IRQ_GPIO_1_2_HIGH = 96u,
IRQ_GPIO_1_2_LOW = 98u,
IRQ_GPIO_1_1 = 99u,
IRQ_GPIO_2_0 = 100u,
IRQ_GPIO_2_2 = 102u,
IRQ_GPIO_3_0 = 104u,
IRQ_GPIO_3_1 = 105u,
IRQ_GPIO_3_2 = 106u,
IRQ_GPIO_3_3 = 107u,
IRQ_GPIO_3_4 = 108u,
IRQ_GPIO_3_5 = 109u,
IRQ_GPIO_3_6 = 110u,
IRQ_GPIO_3_7 = 111u,
IRQ_GPIO_3_8 = 112u,
IRQ_GPIO_3_9 = 113u,
IRQ_GPIO_3_10 = 114u,
IRQ_GPIO_3_11 = 115u,
IRQ_GAMECARD_OFF = 116u, // Gamecard poweroff.
IRQ_GAMECARD_INS = 117u, // Gamecard inserted.
IRQ_L2C = 118u, // New3DS-only L2C-310 Level 2 Cache Controller.
IRQ_UNK119 = 119u,
IRQ_PERF_MONITOR0 = 120u, // Core 0 performance monitor. Triggers on any counter overflow.
IRQ_PERF_MONITOR1 = 121u, // Core 1 performance monitor. Triggers on any counter overflow.
IRQ_PERF_MONITOR2 = 122u, // Unconfirmed. Core 2 performance monitor. Triggers on any counter overflow.
IRQ_PERF_MONITOR3 = 123u, // Unconfirmed. Core 3 performance monitor. Triggers on any counter overflow.
// Aliases
IRQ_SHELL_OPENED = IRQ_GPIO_1_2_HIGH,
IRQ_SHELL_CLOSED = IRQ_GPIO_1_2_LOW, // Triggers on GPIO_1_2 low.
IRQ_TOUCHSCREEN = IRQ_GPIO_1_1, // Triggers on touchscreen pen down.
IRQ_HEADPH_JACK = IRQ_GPIO_2_0, // Headphone jack. Triggers on both plugging in and out?
IRQ_CTR_MCU = IRQ_GPIO_3_9 // Various MCU events trigger this. See MCU interrupt mask.
} Interrupt;
// IRQ interrupt service routine type.
// intSource: bit 10-12 CPU source ID (0 except for interrupt ID 0-15),
// bit 0-9 interrupt ID
typedef void (*IrqIsr)(u32 intSource);
/**
* @brief Initializes the generic interrupt controller.
*/
void IRQ_init(void);
/**
* @brief Registers a interrupt service routine and enables the specified interrupt.
*
* @param[in] id The interrupt ID. Must be <128.
* @param[in] prio The priority. 0 = highest, 14 = lowest, 15 = disabled.
* @param[in] cpuMask The CPU mask. Each of the 4 bits stands for 1 core.
* 0 means current CPU.
* @param[in] isr The interrupt service routine to call.
*/
void IRQ_registerIsr(Interrupt id, u8 prio, u8 cpuMask, IrqIsr isr);
/**
* @brief Reenables a previously disabled but registered interrupt.
*
* @param[in] id The interrupt ID. Must be <128.
*/
void IRQ_enable(Interrupt id);
/**
* @brief Disables a previously registered interrupt temporarily.
*
* @param[in] id The interrupt ID. Must be <128.
*/
void IRQ_disable(Interrupt id);
/**
* @brief Triggers a software interrupt for the specified CPUs.
*
* @param[in] id The interrupt ID. Must be <16.
* @param[in] cpuMask The CPU mask. Each of the 4 bits stands for 1 core.
*/
void IRQ_softInterrupt(Interrupt id, u8 cpuMask);
/**
* @brief Sets the priority of an interrupt.
*
* @param[in] id The interrupt ID. Must be <128.
* @param[in] prio The priority. 0 = highest, 14 = lowest, 15 = disabled
*/
void IRQ_setPriority(Interrupt id, u8 prio);
/**
* @brief Unregisters the interrupt service routine and disables the specified interrupt.
*
* @param[in] id The interrupt ID. Must be <128.
*/
void IRQ_unregisterIsr(Interrupt id);
#if !__thumb__
static inline u32 enterCriticalSection(void)
{
const u32 tmp = __getCpsr();
__cpsid(i);
return tmp & PSR_I;
}
static inline void leaveCriticalSection(u32 oldState)
{
__setCpsr_c((__getCpsr() & ~PSR_I) | oldState);
}
#endif

View File

@ -1,151 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "mem_map.h"
#include "arm11/drivers/gx.h"
// LCD/ABL regs.
#define LCD_REGS_BASE (IO_MEM_ARM11_ONLY + 0x2000)
#define REG_LCD_PARALLAX_CNT *((vu32*)(LCD_REGS_BASE + 0x000)) // Controls PWM for the parallax barrier?
#define REG_LCD_PARALLAX_PWM *((vu32*)(LCD_REGS_BASE + 0x004)) // Frequency/other PWM stuff maybe?
#define REG_LCD_UNK00C *((vu32*)(LCD_REGS_BASE + 0x00C)) // Wtf is "FIX"?
#define REG_LCD_RST *((vu32*)(LCD_REGS_BASE + 0x014)) // Reset active low.
#define REG_LCD_ABL0_CNT *((vu32*)(LCD_REGS_BASE + 0x200)) // Bit 0 enables ABL aka power saving mode.
#define REG_LCD_ABL0_FILL *((vu32*)(LCD_REGS_BASE + 0x204))
#define REG_LCD_ABL0_LIGHT *((vu32*)(LCD_REGS_BASE + 0x240))
#define REG_LCD_ABL0_LIGHT_PWM *((vu32*)(LCD_REGS_BASE + 0x244))
#define REG_LCD_ABL1_CNT *((vu32*)(LCD_REGS_BASE + 0xA00)) // Bit 0 enables ABL aka power saving mode.
#define REG_LCD_ABL1_FILL *((vu32*)(LCD_REGS_BASE + 0xA04))
#define REG_LCD_ABL1_LIGHT *((vu32*)(LCD_REGS_BASE + 0xA40))
#define REG_LCD_ABL1_LIGHT_PWM *((vu32*)(LCD_REGS_BASE + 0xA44))
// Technically these regs belong in gx.h but they are used for LCD configuration so...
// Pitfall warning: The 3DS LCDs are physically rotated 90° CCW.
// PDC0 (top screen display controller) regs.
#define REG_LCD_PDC0_HTOTAL *((vu32*)(GX_REGS_BASE + 0x400))
#define REG_LCD_PDC0_VTOTAL *((vu32*)(GX_REGS_BASE + 0x424))
#define REG_LCD_PDC0_HPOS *((const vu32*)(GX_REGS_BASE + 0x450))
#define REG_LCD_PDC0_VPOS *((const vu32*)(GX_REGS_BASE + 0x454))
#define REG_LCD_PDC0_FB_A1 *((vu32*)(GX_REGS_BASE + 0x468))
#define REG_LCD_PDC0_FB_A2 *((vu32*)(GX_REGS_BASE + 0x46C))
#define REG_LCD_PDC0_FMT *((vu32*)(GX_REGS_BASE + 0x470))
#define REG_LCD_PDC0_CNT *((vu32*)(GX_REGS_BASE + 0x474))
#define REG_LCD_PDC0_SWAP *((vu32*)(GX_REGS_BASE + 0x478))
#define REG_LCD_PDC0_STAT *((const vu32*)(GX_REGS_BASE + 0x47C))
#define REG_LCD_PDC0_GTBL_IDX *((vu32*)(GX_REGS_BASE + 0x480)) // Gamma table index.
#define REG_LCD_PDC0_GTBL_FIFO *((vu32*)(GX_REGS_BASE + 0x484)) // Gamma table FIFO.
#define REG_LCD_PDC0_STRIDE *((vu32*)(GX_REGS_BASE + 0x490))
#define REG_LCD_PDC0_FB_B1 *((vu32*)(GX_REGS_BASE + 0x494))
#define REG_LCD_PDC0_FB_B2 *((vu32*)(GX_REGS_BASE + 0x498))
// PDC1 (bottom screen display controller) regs.
#define REG_LCD_PDC1_HTOTAL *((vu32*)(GX_REGS_BASE + 0x500))
#define REG_LCD_PDC1_VTOTAL *((vu32*)(GX_REGS_BASE + 0x524))
#define REG_LCD_PDC1_HPOS *((const vu32*)(GX_REGS_BASE + 0x550))
#define REG_LCD_PDC1_VPOS *((const vu32*)(GX_REGS_BASE + 0x554))
#define REG_LCD_PDC1_FB_A1 *((vu32*)(GX_REGS_BASE + 0x568))
#define REG_LCD_PDC1_FB_A2 *((vu32*)(GX_REGS_BASE + 0x56C))
#define REG_LCD_PDC1_FMT *((vu32*)(GX_REGS_BASE + 0x570))
#define REG_LCD_PDC1_CNT *((vu32*)(GX_REGS_BASE + 0x574))
#define REG_LCD_PDC1_SWAP *((vu32*)(GX_REGS_BASE + 0x578))
#define REG_LCD_PDC1_STAT *((const vu32*)(GX_REGS_BASE + 0x57C))
#define REG_LCD_PDC1_GTBL_IDX *((vu32*)(GX_REGS_BASE + 0x580)) // Gamma table index.
#define REG_LCD_PDC1_GTBL_FIFO *((vu32*)(GX_REGS_BASE + 0x584)) // Gamma table FIFO.
#define REG_LCD_PDC1_STRIDE *((vu32*)(GX_REGS_BASE + 0x590))
#define REG_LCD_PDC1_FB_B1 *((vu32*)(GX_REGS_BASE + 0x594))
#define REG_LCD_PDC1_FB_B2 *((vu32*)(GX_REGS_BASE + 0x598))
// REG_LCD_PDC_CNT
#define PDC_CNT_E (1u)
#define PDC_CNT_I_MASK_H (1u<<8) // Disables H(Blank?) IRQs.
#define PDC_CNT_I_MASK_V (1u<<9) // Disables VBlank IRQs.
#define PDC_CNT_I_MASK_ERR (1u<<10) // Disables error IRQs. What kind of errors?
#define PDC_CNT_I_MASK_ALL (PDC_CNT_I_MASK_ERR | PDC_CNT_I_MASK_V | PDC_CNT_I_MASK_H)
#define PDC_CNT_OUT_E (1u<<16) // Output enable?
// REG_LCD_PDC_SWAP
// Masks
#define PDC_SWAP_NEXT (1u) // Next framebuffer.
#define PDC_SWAP_CUR (1u<<4) // Currently displaying framebuffer?
// Bits
#define PDC_SWAP_RST_FIFO (1u<<8) // Which FIFO?
#define PDC_SWAP_I_H (1u<<16) // H(Blank?) IRQ bit.
#define PDC_SWAP_I_V (1u<<17) // VBlank IRQ bit.
#define PDC_SWAP_I_ERR (1u<<18) // Error IRQ bit?
#define PDC_SWAP_I_ALL (PDC_SWAP_I_ERR | PDC_SWAP_I_V | PDC_SWAP_I_H)
// LCD I2C regs.
typedef enum
{
LCD_I2C_REG_POWER = 0x01u,
LCD_I2C_REG_UNK11 = 0x11u,
LCD_I2C_REG_READ_ADDR = 0x40u,
LCD_I2C_REG_HS_SERIAL = 0x50u, // Highspeed serial for upper LCD only.
LCD_I2C_REG_UNK54 = 0x54u, // Checksum on/off?
LCD_I2C_REG_UNK55 = 0x55u, // Checksum status?
LCD_I2C_REG_STATUS = 0x60u, // Initially 0x01.
LCD_I2C_REG_BL_STATUS = 0x62u, // Backlight status.
LCD_I2C_REG_RST_STATUS = 0xFEu, // Reset status. Initially 0x00.
LCD_I2C_REG_REVISION = 0xFFu, // Revision/vendor infos.
} LcdI2cReg;
// LCD_I2C_REG_POWER
#define LCD_REG_POWER_BLACK (0x11u) // Force blackscreen.
#define LCD_REG_POWER_ON (0x10u) // Normal operation.
#define LCD_REG_POWER_OFF (0x00u) // LCD powered off.
// LCD_I2C_REG_UNK11
#define LCD_REG_UNK11_UNK10 (0x10u) // Written on init.
// LCD_I2C_REG_HS_SERIAL
#define LCD_REG_HS_SERIAL_ON (0x01u) // Enable highspeed serial.
// LCD_I2C_REG_UNK54
// LCD_I2C_REG_UNK55
// LCD_I2C_REG_STATUS
#define LCD_REG_STATUS_OK (0x00u)
#define LCD_REG_STATUS_ERR (0x01u)
// LCD_I2C_REG_BL_STATUS
#define LCD_REG_BL_STATUS_OFF (0x00u)
#define LCD_REG_BL_STATUS_ON (0x01u)
// LCD_I2C_REG_RST_STATUS
#define LCD_REG_RST_STATUS_NONE (0xAAu)
#define LCD_REG_RST_STATUS_RST (0x00u)
u8 LCDI2C_readReg(u8 lcd, LcdI2cReg reg);
void LCDI2C_writeReg(u8 lcd, LcdI2cReg reg, u8 data);
void LCDI2C_init(void);
void LCDI2C_waitBacklightsOn(void);
u16 LCDI2C_getRevisions(void);

View File

@ -1,104 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#include "kevent.h"
#define LGYFB_TOP_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x11000)
#define LGYFB_BOT_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x10000)
#define LGYFB_TOP_FIFO *((const vu32*)(0x10311000))
#define LGYFB_BOT_FIFO *((const vu32*)(0x10310000))
typedef struct
{
vu32 len; // 0x00
vu32 patt; // 0x04
u8 _0x8[0x38];
vu32 matrix[6][8]; // 0x40
} LgyFbScaler;
typedef struct
{
vu32 cnt; // 0x000
vu32 size; // 0x004
vu32 stat; // 0x008
vu32 irq; // 0x00C
vu32 flush; // 0x010 Write 0 to flush LgyFb FIFO.
u8 _0x14[0xc];
vu32 alpha; // 0x020 8 bit alpha for all pixels.
u8 _0x24[0xcc];
vu32 unkF0; // 0x0F0
u8 _0xf4[0xc];
vu32 dithpatt0[2]; // 0x100 2 u32 regs with 4x2 pattern bits (mask 0xCCCC) each.
vu32 dithpatt1[2]; // 0x108 2 u32 regs with 4x2 pattern bits (mask 0xCCCC) each.
u8 _0x110[0xf0];
LgyFbScaler v; // 0x200
LgyFbScaler h; // 0x300
} LgyFb;
static_assert(offsetof(LgyFb, h.matrix[5][7]) == 0x3FC, "Error: Member h.matrix[5][7] of LgyFb is not at offset 0x3FC!");
ALWAYS_INLINE LgyFb* getLgyFbRegs(bool top)
{
return (LgyFb*)(top ? LGYFB_TOP_REGS_BASE : LGYFB_BOT_REGS_BASE);
}
// REG_LGYFB_CNT
#define LGYFB_EN (1u)
#define LGYFB_VSCALE_EN (1u<<1)
#define LGYFB_HSCALE_EN (1u<<2)
#define LGYFB_SPATIAL_DITHER_EN (1u<<4) // Unset behaves like weight 0xCCCC in both pattern regs.
#define LGYFB_TEMPORAL_DITHER_EN (1u<<5) // Unset behaves like weight 0xCCCC in both pattern regs.
#define LGYFB_OUT_FMT_8888 (0u)
#define LGYFB_OUT_FMT_8880 (1u<<8)
#define LGYFB_OUT_FMT_5551 (2u<<8)
#define LGYFB_OUT_FMT_5650 (3u<<8)
#define LGYFB_ROT_NONE (0u)
#define LGYFB_ROT_90CW (1u<<10)
#define LGYFB_ROT_180CW (2u<<10)
#define LGYFB_ROT_270CW (3u<<10)
#define LGYFB_OUT_SWIZZLE (1u<<12)
#define LGYFB_DMA_EN (1u<<15)
#define LGYFB_IN_FMT (1u<<16) // Use input format but this bit does nothing?
// REG_LGYFB_SIZE width and hight
#define LGYFB_SIZE(w, h) (((h) - 1)<<16 | ((w) - 1))
// REG_LGYFB_STAT and REG_LGYFB_IRQ
#define LGYFB_IRQ_DMA_REQ (1u)
#define LGYFB_IRQ_BUF_ERR (1u<<1) // FIFO overrun?
#define LGYFB_IRQ_VBLANK (1u<<2)
#define LGYFB_IRQ_MASK (LGYFB_IRQ_VBLANK | LGYFB_IRQ_BUF_ERR | LGYFB_IRQ_DMA_REQ)
#define LGYFB_OUT_LINE(reg) ((reg)>>16) // STAT only
void LGYFB_init(KHandle frameReadyEvent, u8 scaler);
void LGYFB_deinit(void);
void LGYFB_stop(void);
void LGYFB_start(void);
#ifndef NDEBUG
void LGYFB_dbgDumpFrame(void);
#endif

View File

@ -1,674 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "arm11/drivers/mcu_regmap.h"
#define DEFAULT_MCU_IRQ_MASK (~(MCU_IRQ_TOP_BL_ON | MCU_IRQ_TOP_BL_OFF | MCU_IRQ_BOT_BL_ON | \
MCU_IRQ_BOT_BL_OFF | MCU_IRQ_LCD_POWER_ON | MCU_IRQ_LCD_POWER_OFF | \
MCU_IRQ_VOL_SLIDER_CHANGE | MCU_IRQ_BATT_CHARGE_START | \
MCU_IRQ_BATT_CHARGE_STOP | MCU_IRQ_ACC_DATA_READY | MCU_IRQ_ACC_RW_DONE | \
MCU_IRQ_WATCHDOG | MCU_IRQ_SHELL_OPEN | MCU_IRQ_SHELL_CLOSE | \
MCU_IRQ_WIFI_PRESS | MCU_IRQ_HOME_RELEASE | MCU_IRQ_HOME_PRESS | \
MCU_IRQ_POWER_HELD | MCU_IRQ_POWER_PRESS))
/*typedef struct
{
// TODO
} PowerLedPattern;*/
/*typedef struct
{
// TODO
} InfoLedPattern;*/
typedef struct
{
u8 s; // Second.
u8 min; // Minute.
u8 h; // Hour.
u8 dow; // Unused day of week.
u8 d; // Day.
u8 mon; // Month.
u8 y; // Year.
} RtcTimeDate;
typedef struct
{
u8 min; // Minute.
u8 h; // Hour.
u8 d; // Day.
u8 mon; // Month.
u8 y; // Year.
} AlarmTimeDate;
typedef struct
{
s16 x;
s16 y;
s16 z;
} AccData;
/*typedef struct
{
// 6 bytes timestamps.
// 336 bytes step counts.
} PedometerHistory;*/
// TODO: For most functions check if the return value on error makes sense.
/**
* @brief Initializes the MCU driver.
*/
void MCU_init(void);
/**
* @brief Reboots the MCU.
*
* @return Returns true on success and false on failure.
*/
//bool MCU_reboot(void);
/**
* @brief { function_description }
*
* @param[in] mask The mask
*
* @return { description_of_the_return_value }
*/
u32 MCU_getIrqs(u32 mask);
/**
* @brief { function_description }
*
* @param[in] mask The mask
*
* @return { description_of_the_return_value }
*/
u32 MCU_waitIrqs(u32 mask);
/**
* @brief Reads the MCU firmware version.
*
* @return Returns the MCU firmware version.
*/
u16 MCU_getFirmwareVersion(void);
/**
* @brief Reads MCU status bits.
*
* @return Returns the MCU status bits.
*/
u8 MCU_getStatus(void);
/**
* @brief { function_description }
*
* @param[in] status The status
*
* @return { description_of_the_return_value }
*/
bool MCU_setStatus(u8 status);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getLcdVcomTop(void);
/**
* @brief { function_description }
*
* @param[in] vcom The vcom
*
* @return { description_of_the_return_value }
*/
bool MCU_setLcdVcomTop(u8 vcom);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getLcdVcomBot(void);
/**
* @brief { function_description }
*
* @param[in] vcom The vcom
*
* @return { description_of_the_return_value }
*/
bool MCU_setLcdVcomBot(u8 vcom);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_get3dSliderPosition(void);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getVolumeSliderPosition(void);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
s8 MCU_getBatteryTemperature(void);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getBatteryLevel(void);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
float MCU_getBatteryVoltage(void);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u16 MCU_getExternalHardwareStatus(void);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u32 MCU_getIrqMask(void);
/**
* @brief { function_description }
*
* @param[in] mask The mask
*
* @return { description_of_the_return_value }
*/
bool MCU_setIrqMask(u32 mask);
// TODO: MCU_setSystemPower()?
void MCU_powerOffSys(void);
void MCU_rebootSys(void);
/**
* @brief { function_description }
*
* @param[in] bits The bits
*
* @return { description_of_the_return_value }
*/
bool MCU_setTwlIrq(u8 bits);
/**
* @brief { function_description }
*
* @param[in] bits The bits
*/
void MCU_setLcdPower(u8 bits);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getPoweroffDelay(void);
/**
* @brief { function_description }
*
* @param[in] delay The delay
*
* @return { description_of_the_return_value }
*/
bool MCU_setPoweroffDelay(u8 delay);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getRegister0x25(void);
/**
* @brief { function_description }
*
* @param[in] data The data
*
* @return { description_of_the_return_value }
*/
bool MCU_setRegister0x25(u8 data);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getRegister0x26(void);
/**
* @brief { function_description }
*
* @param[in] data The data
*
* @return { description_of_the_return_value }
*/
bool MCU_setRegister0x26(u8 data);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getVolumeSliderPositionRaw(void);
/**
* @brief { function_description }
*
* @param[in] data The data
*
* @return { description_of_the_return_value }
*/
bool MCU_setVolumeSliderPositionRaw(u8 data);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getLedMasterBrightness(void);
/**
* @brief { function_description }
*
* @param[in] brightness The brightness
*
* @return { description_of_the_return_value }
*/
bool MCU_setLedMasterBrightness(u8 brightness);
/**
* @brief { function_description }
*
* @param pattern The pattern
*
* @return { description_of_the_return_value }
*/
bool MCU_getPowerLedPattern(u8 pattern[5]); // TODO: Struct.
/**
* @brief { function_description }
*
* @param[in] pattern The pattern
*
* @return { description_of_the_return_value }
*/
bool MCU_setPowerLedPattern(const u8 pattern[5]); // TODO: Struct.
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getWifiLedState(void);
/**
* @brief { function_description }
*
* @param[in] state The state
*
* @return { description_of_the_return_value }
*/
bool MCU_setWifiLedState(u8 state);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getCameraLedState(void);
/**
* @brief { function_description }
*
* @param[in] state The state
*
* @return { description_of_the_return_value }
*/
bool MCU_setCameraLedState(u8 state);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_get3dLedState(void);
/**
* @brief { function_description }
*
* @param[in] state The state
*
* @return { description_of_the_return_value }
*/
bool MCU_set3dLedState(u8 state);
/**
* @brief { function_description }
*
* @param[in] pattern The pattern
*
* @return { description_of_the_return_value }
*/
bool MCU_setInfoLedPattern(const u8 pattern[100]); // TODO: Struct.
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getInfoLedStatus(void);
/**
* @brief { function_description }
*
* @param timeDate The time date
*
* @return { description_of_the_return_value }
*/
bool MCU_getRtcTimeDate(RtcTimeDate *timeDate);
/**
* @brief { function_description }
*
* @param[in] timeDate The time date
*
* @return { description_of_the_return_value }
*/
bool MCU_setRtcTimeDate(const RtcTimeDate *timeDate);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getRtcErrorCorrection(void);
/**
* @brief { function_description }
*
* @param[in] correction The correction
*
* @return { description_of_the_return_value }
*/
bool MCU_setRtcErrorCorrection(u8 correction);
/**
* @brief { function_description }
*
* @param timeDate The time date
*
* @return { description_of_the_return_value }
*/
bool MCU_getAlarmTimeDate(AlarmTimeDate *timeDate);
/**
* @brief { function_description }
*
* @param[in] timeDate The time date
*
* @return { description_of_the_return_value }
*/
bool MCU_setAlarmTimeDate(const AlarmTimeDate *timeDate);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u16 MCU_getRtcTick(void);
/**
* @brief { function_description }
*
* @param[in] data The data
*
* @return { description_of_the_return_value }
*/
bool MCU_setRegister0x3F(u8 data);
/**
* @brief { function_description }
*
* @return The acc configuration.
*/
AccCfg MCU_getAccelerometerConfig(void);
/**
* @brief { function_description }
*
* @param[in] cfg The configuration
*
* @return { description_of_the_return_value }
*/
bool MCU_setAccelerometerConfig(AccCfg cfg);
/**
* @brief { function_description }
*
* @param[in] reg The register
*
* @return { description_of_the_return_value }
*/
u8 MCU_readAccelerometerRegister(u8 reg);
/**
* @brief { function_description }
*
* @param[in] reg The register
* @param[in] data The data
*
* @return { description_of_the_return_value }
*/
bool MCU_writeAccelerometerRegister(u8 reg, u8 data);
/**
* @brief { function_description }
*
* @param samples The samples
*
* @return { description_of_the_return_value }
*/
bool MCU_getAccelerometerSamples(AccData *samples);
/**
* @brief { function_description }
*
* @param[in] steps The steps
*
* @return { description_of_the_return_value }
*/
bool MCU_setPedometerStepCount(u32 steps);
// TODO: Reg 0x4E.
/**
* @brief { function_description }
*
* @param history The history
*
* @return { description_of_the_return_value }
*/
bool MCU_getPedometerHistory(u8 history[6 + 336]); // TODO: Struct.
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getRegister0x50(void);
/**
* @brief { function_description }
*
* @param[in] data The data
*
* @return { description_of_the_return_value }
*/
bool MCU_setRegister0x50(u8 data);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getRegister0x51(void);
/**
* @brief { function_description }
*
* @param[in] data The data
*
* @return { description_of_the_return_value }
*/
bool MCU_setRegister0x51(u8 data);
/**
* @brief { function_description }
*
* @param minMax The minimum maximum
*
* @return { description_of_the_return_value }
*/
bool MCU_getVolumeSliderCalibrationPoints(u8 minMax[2]);
/**
* @brief { function_description }
*
* @param[in] minMax The minimum maximum
*
* @return { description_of_the_return_value }
*/
bool MCU_setVolumeSliderCalibrationPoints(const u8 minMax[2]);
/**
* @brief { function_description }
*
* @param[in] off Off
* @param out The out
* @param[in] size The size
*
* @return { description_of_the_return_value }
*/
bool MCU_getFreeRamData(u8 off, u8 *out, u8 size);
/**
* @brief { function_description }
*
* @param[in] off Off
* @param[in] in { parameter_description }
* @param[in] size The size
*
* @return { description_of_the_return_value }
*/
bool MCU_setFreeRamData(u8 off, const u8 *in, u8 size);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getConsoleType(void);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getSystemModel(void);
/**
* @brief { function_description }
*
* @return { description_of_the_return_value }
*/
u8 MCU_getEarlyButtonsHeld(void);
/**
* @brief Reads a single MCU register.
*
* @param[in] reg The MCU register to read.
*
* @return The MCU register data.
*/
u8 MCU_readReg(McuReg reg);
/**
* @brief Writes a single MCU register.
*
* @param[in] reg The MCU register to write.
* @param[in] data The data to write.
*
* @return Returns true on success and false on failure.
*/
bool MCU_writeReg(McuReg reg, u8 data);
/**
* @brief Reads multiple MCU registers or buffers behind registers.
*
* @param[in] reg The MCU register(s) to read.
* @param out The output data pointer.
* @param[in] size The output buffer size.
*
* @return Returns true on success and false on failure.
*/
bool MCU_readRegBuf(McuReg reg, u8 *out, u32 size);
/**
* @brief Writes multiple MCU registers or buffers behind registers.
*
* @param[in] reg The MCU register(s) to write.
* @param[in] in The input data pointer.
* @param[in] size The input data size.
*
* @return Returns true on success and false on failure.
*/
bool MCU_writeRegBuf(McuReg reg, const u8 *const in, u32 size);

View File

@ -1,145 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2022 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
typedef enum
{
MCU_REG_VERS_MAJOR = 0x00u, // (ro) MCU firmware major version.
MCU_REG_VERS_MINOR = 0x01u, // (ro) MCU firmware minor version.
MCU_REG_STAT = 0x02u, // (rw) Reset status and TWL MCU emulation stuff.
MCU_REG_LCD_VCOM_TOP = 0x03u, // (rw) Top LCD VCOM ("flicker").
MCU_REG_LCD_VCOM_BOT = 0x04u, // (rw) Bottom LCD VCOM ("flicker").
MCU_REG_FW_UPDATE = 0x05u, // (rw) 0x05-0x07 Firmware update magic "jhl" is written here. If we stop the transfer after the magic the MCU will just reset.
MCU_REG_3D_SLIDER = 0x08u, // (ro) Raw 3D slider position (0-0x3F?).
MCU_REG_VOL_SLIDER = 0x09u, // (ro) Volume slider position (0-0x3F).
MCU_REG_BATT_TEMP = 0x0Au, // (ro) Battery temperature in celsius.
MCU_REG_BATT_LEVEL = 0x0Bu, // (ro) Battery percentage (0-100).
MCU_REG_BATT_LEVEL_FRAC = 0x0Cu, // (ro) Battery percentage fractional part (percent/256).
MCU_REG_BATT_VOLT = 0x0Du, // (ro) Battery voltage in 20mV units.
MCU_REG_EX_HW_STAT2 = 0x0Eu, // (ro) More hardware status bits.
MCU_REG_EX_HW_STAT = 0x0Fu, // (ro) Hardware status bits.
MCU_REG_IRQ = 0x10u, // (ro) 0x10-0x13 Interrupt status (clear on read).
// 0x14 ro, 0x15-0x17 rw. All unused.
MCU_REG_IRQ_MASK = 0x18u, // (rw) 0x18-0x1B Interrupt mask (each bit 0=enabled, 1=disabled).
// 0x1C-0x1F rw and unused.
MCU_REG_SYS_POW = 0x20u, // (wo) System power/reset control.
MCU_REG_TWL_IRQ = 0x21u, // (wo) Various TWL MCU status change signals.
MCU_REG_LCD_POW = 0x22u, // (wo) LCD power control.
MCU_REG_RESTART = 0x23u, // (wo) Stubbed (on retail?) MCU restart register.
MCU_REG_PWROFF_DELAY = 0x24u, // (rw) Force power off delay.
MCU_REG_UNK25 = 0x25u, // (rw) Volume related? Volume value for override?
MCU_REG_UNK26 = 0x26u, // (rw) Volume related? Bit 0: Enable/disable MCU reporting slider state to CODEC? Bit 1: Force? Bit 2: Mode? Bit 4: Trigger volume update from slider?
MCU_REG_VOL_SLIDER_RAW = 0x27u, // (rw) Volume slider raw ADC data (0-0x3F?).
MCU_REG_LED_BRIGHTNESS = 0x28u, // (rw) Master brightness of power/Wifi/3D (and camera?) LEDs.
MCU_REG_POWER_LED = 0x29u, // (rw) 5 bytes power LED state + pattern.
MCU_REG_WIFI_LED = 0x2Au, // (rw) WiFi LED state.
MCU_REG_CAM_LED = 0x2Bu, // (rw) Camera LED state.
MCU_REG_3D_LED = 0x2Cu, // (rw) 3D LED state.
MCU_REG_INFO_LED = 0x2Du, // (wo) 100 bytes notification/info LED pattern.
MCU_REG_INFO_LED_STAT = 0x2Eu, // (ro) Info LED status.
// 0x2F wo with stubbed write handler.
MCU_REG_RTC_S = 0x30u, // (rw) RTC second.
MCU_REG_RTC_MIN = 0x31u, // (rw) RTC minute.
MCU_REG_RTC_H = 0x32u, // (rw) RTC hour.
MCU_REG_RTC_DOW = 0x33u, // (rw) RTC day of week (unused)?
MCU_REG_RTC_D = 0x34u, // (rw) RTC day.
MCU_REG_RTC_MON = 0x35u, // (rw) RTC month.
MCU_REG_RTC_Y = 0x36u, // (rw) RTC year.
MCU_REG_RTC_ERR_CORR = 0x37u, // (rw) RTC Watch error correction.
MCU_REG_ALARM_MIN = 0x38u, // (rw) Alarm minute.
MCU_REG_ALARM_H = 0x39u, // (rw) Alarm hour.
MCU_REG_ALARM_D = 0x3Au, // (rw) Alarm day.
MCU_REG_ALARM_MON = 0x3Bu, // (rw) Alarm month.
MCU_REG_ALARM_Y = 0x3Cu, // (rw) Alarm year.
MCU_REG_RTC_TICK_LO = 0x3Du, // (ro) RTC tick counter LSB in 32768 Hz units.
MCU_REG_RTC_TICK_HI = 0x3Eu, // (ro) RTC tick counter MSB.
MCU_REG_UNK3F = 0x3Fu, // (wo) Unknown state/control reg.
MCU_REG_ACC_CFG = 0x40u, // (rw) Accelerometer configuration register.
MCU_REG_ACC_READ_OFF = 0x41u, // (rw) Accelerometer I2C register offset for read (via MCU reg 0x44).
// 0x42 rw unused.
MCU_REG_ACC_WRITE_OFF = 0x43u, // (rw) Accelerometer I2C register offset for write (via MCU reg 0x44).
MCU_REG_ACC_DATA = 0x44u, // (rw) Accelerometer I2C register data.
MCU_REG_ACC_X_LO = 0x45u, // (ro) Accelerometer X sample data LSB.
MCU_REG_ACC_X_HI = 0x46u, // (ro) Accelerometer X sample data MSB.
MCU_REG_ACC_Y_LO = 0x47u, // (ro) Accelerometer Y sample data LSB.
MCU_REG_ACC_Y_HI = 0x48u, // (ro) Accelerometer Y sample data MSB.
MCU_REG_ACC_Z_LO = 0x49u, // (ro) Accelerometer Z sample data LSB.
MCU_REG_ACC_Z_HI = 0x4Au, // (ro) Accelerometer Z sample data MSB.
MCU_REG_PM_COUNT_LO = 0x4Bu, // (rw) Pedometer step count LSB.
MCU_REG_PM_COUNT_MI = 0x4Cu, // (rw) Pedometer step count middle byte.
MCU_REG_PM_COUNT_HI = 0x4Du, // (rw) Pedometer step count MSB.
MCU_REG_PM_HIST_STAT = 0x4Eu, // (rw) Pedometer history state. TODO: Better name.
MCU_REG_PM_HIST = 0x4Fu, // (ro) 6 + 336 bytes pedometer history data.
MCU_REG_UNK50 = 0x50u, // (rw)
MCU_REG_UNK51 = 0x51u, // (rw)
// 0x52-0x57 rw unknown/unused.
MCU_REG_VOL_SLIDER_MIN = 0x58u, // (rw) Volume slider minimum calibration point.
MCU_REG_VOL_SLIDER_MAX = 0x59u, // (rw) Volume slider maximum calibration point.
// 0x5A rw/ro depending on firmware version. Unused.
// 0x5B-0x5F unused.
MCU_REG_FREE_RAM_OFF = 0x60u, // (rw) Free RAM offset for MCU register 0x61.
MCU_REG_FREE_RAM_DATA = 0x61u, // (rw) Free RAM data register.
// 0x62-0x7E unused.
MCU_REG_RAW_STATE = 0x7Fu // (ro) 19 bytes of various raw state.
// 0x80-0xFF unused.
} McuReg;
// MCU_REG_IRQ and MCU_REG_IRQ_MASK.
#define MCU_IRQ_POWER_PRESS (1u) // Power button pressed for 200 ms.
#define MCU_IRQ_POWER_HELD (1u<<1) // Power button held for 3 seconds.
#define MCU_IRQ_HOME_PRESS (1u<<2) // HOME button pressed for 40 ms.
#define MCU_IRQ_HOME_RELEASE (1u<<3) // HOME button released.
#define MCU_IRQ_WIFI_PRESS (1u<<4) // WiFi button pressed for 40 ms.
#define MCU_IRQ_SHELL_CLOSE (1u<<5) // Shell has been closed.
#define MCU_IRQ_SHELL_OPEN (1u<<6) // Shell has been opened.
#define MCU_IRQ_WATCHDOG (1u<<7) // MCU has been reset by the watchdog.
#define MCU_IRQ_CHARGER_UNPLUG (1u<<8) // Charger has been unplugged.
#define MCU_IRQ_CHARGER_PLUG (1u<<9) // Charger has been plugged in.
#define MCU_IRQ_RTC_ALARM (1u<<10) // RTC alarm.
#define MCU_IRQ_ACC_RW_DONE (1u<<11) // Accelerometer I2C read/write done.
#define MCU_IRQ_ACC_DATA_READY (1u<<12) // Accelerometer X/Y/Z sample data ready.
#define MCU_IRQ_LOW_BATT (1u<<13) // Low battery warning IRQ triggered at 10, 5 and 0%. TODO: gbatek says 11, 6 and 1%.
#define MCU_IRQ_BATT_CHARGE_STOP (1u<<14) // Battery charging stopped.
#define MCU_IRQ_BATT_CHARGE_START (1u<<15) // Battery charging started.
#define MCU_IRQ_TWL_RESET (1u<<16) // DS powerman register 0x10 bit 0 = 1 or TWL MCU register 0x11 = 1 (reset).
#define MCU_IRQ_TWL_PWROFF (1u<<17) // DS powerman register 0x10 bit 6 = 1. Poweroff request?
#define MCU_IRQ_TWL_BOT_BL_OFF (1u<<18) // DS powerman register 0x10 bit 2 = 0. Bottom LCD backlight off request?
#define MCU_IRQ_TWL_BOT_BL_ON (1u<<19) // DS powerman register 0x10 bit 2 = 1. Bottom LCD backlight on request?
#define MCU_IRQ_TWL_TOP_BL_OFF (1u<<20) // DS powerman register 0x10 bit 3 = 0. Top LCD backlight off request?
#define MCU_IRQ_TWL_TOP_BL_ON (1u<<21) // DS powerman register 0x10 bit 3 = 1. Top LCD backlight on request?
#define MCU_IRQ_VOL_SLIDER_CHANGE (1u<<22) // Volume slider position changed.
#define MCU_IRQ_TWL_MCU_VER_READ (1u<<23) // TWL MCU version register (0x00) read.
#define MCU_IRQ_LCD_POWER_OFF (1u<<24) // LCDs have been powered off.
#define MCU_IRQ_LCD_POWER_ON (1u<<25) // LCDs have been powered on.
#define MCU_IRQ_BOT_BL_OFF (1u<<26) // Bottom LCD backlight has been powered off.
#define MCU_IRQ_BOT_BL_ON (1u<<27) // Bottom LCD backlight has been powered on.
#define MCU_IRQ_TOP_BL_OFF (1u<<28) // Top LCD backlight has been powered off.
#define MCU_IRQ_TOP_BL_ON (1u<<29) // Top LCD backlight has been powered on.
// MCU_REG_ACC_CFG
typedef enum
{
ACC_CFG_ALL_OFF = 0u, // Accelerometer and pedometer off.
ACC_CFG_ACC_ON_PM_OFF = 1u, // Accelerometer on and pedometer off.
ACC_CFG_ACC_OFF_PM_ON = 2u, // Accelerometer off and pedometer on.
ACC_CFG_ACC_ON_PM_ON = 3u // Accelerometer on and pedometer on.
} AccCfg;

View File

@ -1,151 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#define PDN_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x41000)
typedef struct
{
vu16 cnt; // 0x000
u8 _0x2[6];
vu32 wake_enable; // 0x008
vu32 wake_reason; // 0x00C Write 1 to acknowledge and 0 to clear?
// Some LGY regs are located inbetween. See lgy.h/c.
u8 _0x10[0x1f0];
vu32 gpu_cnt; // 0x200
vu8 vram_cnt; // 0x204 This reg doesn't seem to exist on retail hardware.
u8 _0x205[3];
vu8 lcd_cnt; // 0x208 This reg doesn't seem to exist on retail hardware.
u8 _0x209[7];
vu8 fcram_cnt; // 0x210
u8 _0x211[0xf];
vu8 i2s_cnt; // 0x220
u8 _0x221[3];
vu8 cam_cnt; // 0x224
u8 _0x225[0xb];
vu8 dsp_cnt; // 0x230
u8 _0x231[0xF];
vu8 g1_cnt; // 0x240 Hantro G1 decoder aka MVD.
u8 _0x241[0xbf];
vu16 lgr_socmode; // 0x300
u8 _0x302[2];
vu16 lgr_cnt; // 0x304 Is this reg actually only vu8?
u8 _0x306[0xa];
vu8 lgr_cpu_cnt[4]; // 0x310
} Pdn;
static_assert(offsetof(Pdn, lgr_cpu_cnt[3]) == 0x313, "Error: Member lgr_cpu_cnt[3] of Pdn is not at offset 0x313!");
ALWAYS_INLINE Pdn* getPdnRegs(void)
{
return (Pdn*)PDN_REGS_BASE;
}
// REG_PDN_CNT
#define PDN_CNT_SLEEP (1u) // Set this bit to enter sleep mode.
#define PDN_CNT_VRAM_OFF (1u<<15) // Set when VRAM is powered off.
// REG_PDN_WAKE_ENABLE and REG_PDN_WAKE_REASON
#define PDN_WAKE_PADCNT (1u)
#define PDN_WAKE_SHELL_OPENED (1u<<3)
#define PDN_WAKE_HEADPH_NOT_PLUGGED_IN (1u<<4) // Really?
#define PDN_WAKE_UNK6 (1u<<6) // DSi mode related.
#define PDN_WAKE_SDIO1 (1u<<7)
#define PDN_WAKE_SDIO2 (1u<<8)
#define PDN_WAKE_SDIO3 (1u<<16)
// 17-28 maybe GPIO3 0-11?
#define PDN_WAKE_GAMECARD_INSERT (1u<<29) // ?
#define PDN_WAKE_TOUCHPEN_DOWN (1u<<30)
#define PDN_WAKE_UNK31 (1u<<31) // Also shell related?
// REG_PDN_GPU_CNT
// Note: The resets are active low.
#define PDN_GPU_CNT_NORST_REGS (1u) // And more?
#define PDN_GPU_CNT_NORST_PSC (1u<<1) // ?
#define PDN_GPU_CNT_NORST_GEOSHADER (1u<<2) // ?
#define PDN_GPU_CNT_NORST_RASTERIZER (1u<<3) // ?
#define PDN_GPU_CNT_NORST_PPF (1u<<4)
#define PDN_GPU_CNT_NORST_PDC (1u<<5) // ?
#define PDN_GPU_CNT_NORST_PDC2 (1u<<6) // Maybe pixel pipeline or so?
#define PDN_GPU_CNT_NORST_ALL ((PDN_GPU_CNT_NORST_PDC2<<1) - 1)
#define PDN_GPU_CNT_CLK_EN (1u<<16)
// REG_PDN_VRAM_CNT
#define PDN_VRAM_CNT_CLK_EN (1u)
// REG_PDN_LCD_CNT
#define PDN_LCD_CNT_PWR_MGR_OFF (1u) // Power management off?
// REG_PDN_FCRAM_CNT
// Note: Reset is active low.
#define PDN_FCRAM_CNT_NORST (1u)
#define PDN_FCRAM_CNT_CLK_EN (1u<<1)
#define PDN_FCRAM_CNT_CLK_EN_ACK (1u<<2) // Gets set or unset depending on CLK_E.
// REG_PDN_I2S_CNT
#define PDN_I2S_CNT_I2S_CLK1_EN (1u) // ? Unused?
#define PDN_I2S_CNT_I2S_CLK2_EN (1u<<1)
// REG_PDN_CAM_CNT
#define PDN_CAM_CNT_CLK_EN (1u)
// REG_PDN_DSP_CNT
// Note: Reset is active low.
#define PDN_DSP_CNT_NORST (1u)
#define PDN_DSP_CNT_CLK_EN (1u<<1)
// REG_PDN_G1_CNT
// TODO: Active low or high?
#define PDN_G1_CNT_NORST (1u)
// REG_PDN_LGR_SOCMODE
typedef enum
{
SOCMODE_CTR_268MHZ = 0u,
SOCMODE_LGR2_268MHZ = 1u, // Also enables FCRAM extension.
SOCMODE_LGR1_268MHZ = 2u, // Also enables FCRAM extension?
SOCMODE_LGR1_536MHZ = 3u, // Also enables FCRAM extension?
SOCMODE_LGR2_804MHZ = 5u, // Also enables FCRAM extension.
SOCMODE_MASK = 7u
} PdnSocmode;
#define PDN_LGR_SOCMODE_ACK (1u<<15)
// REG_PDN_LGR_CNT
#define PDN_LGR_CNT_WRAM_EXT_EN (1u) // QTM WRAM enable.
#define PDN_LGR_CNT_L2C_EN (1u<<8) // L2C L2 cache enable.
// REGs_PDN_LGR_CPU_CNT
// Note: Reset is active low.
#define LGR_CPU_CNT_NORST (1u) // Core 2/3 only. Reset and instruction overlay enable.
#define LGR_CPU_CNT_D_OVERL_EN (1u<<1) // Core 2/3 only. Data overlay enable. Also used to signal a core booted.
#define LGR_CPU_CNT_RST_STAT (1u<<4) // Reset status.
#define LGR_CPU_CNT_UNK (1u<<5) // Something ready?
void PDN_core123Init(void);
void PDN_setSocmode(PdnSocmode socmode);
void PDN_poweroffCore23(void);

View File

@ -1,135 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Based on ARM11 MPCore™ Processor Revision: r2p0 Technical Reference Manual (DDI0360F_arm11_mpcore_r2p0_trm.pdf).
#if !__ASSEMBLER__
#include "types.h"
#endif // #if !__ASSEMBLER__
// Performance Monitor Control Register (PMNC).
#define PM_EN (1u) // All three counters enabled.
#define PM_PMN01_RST (1u<<1) // Reset both Count Registers to 0x0.
#define PM_CCNT_RST (1u<<2) // Reset the Cycle Counter Register to 0x0.
#define PM_CCNT_NODIV (0u) // Cycle Counter Register counts every processor clock cycle.
#define PM_CCNT_DIV64 (1u<<3) // Cycle Counter Register counts every 64th processor clock cycle.
#define PM_PMN0_IRQ_EN (1u<<4) // Count Register 0 interrupt enable.
#define PM_PMN1_IRQ_EN (1u<<5) // Count Register 1 interrupt enable.
#define PM_CCNT_IRQ_EN (1u<<6) // Cycle Counter interrupt enable.
#define PM_PMN0_IRQ (1u<<8) // Count Register 0 overflow flag. Write 1 to clear.
#define PM_PMN1_IRQ (1u<<9) // Count Register 1 overflow flag. Write 1 to clear.
#define PM_CCNT_IRQ (1u<<10) // Cycle Counter Register overflow flag. Write 1 to clear.
#define PM_EVT(pmn1, pmn0) ((pmn0)<<20 | (pmn1)<<12) // Set what events PMN0/1 count. See events below.
// Performance monitor events.
#define PM_EVT_ICACHE_MISS (0x00u) // Instruction cache miss to a cachable location requires fetch from external memory.
#define PM_EVT_INST_BUF_STALL (0x01u) // Stall because instruction buffer cannot deliver an instruction. This can indicate an instruction cache miss or an instruction MicroTLB miss. This event occurs every cycle where the condition is present.
#define PM_EVT_DATA_DEP_STALL (0x02u) // Stall because of a data dependency. This event occurs every cycle where the condition is present.
#define PM_EVT_INST_MICROTLB_MISS (0x03u) // Instruction MicroTLB miss.
#define PM_EVT_DATA_MICROTLB_MISS (0x04u) // Data MicroTLB miss.
#define PM_EVT_BRANCH_EXEC (0x05u) // Branch instruction executed, branch might or might not have changed program flow.
#define PM_EVT_BRANCH_NOT_PRED (0x06u) // Branch not predicted.
#define PM_EVT_BRANCH_MISPRED (0x07u) // Branch mispredicted.
#define PM_EVT_INST_EXEC (0x08u) // Instruction executed.
#define PM_EVT_FOLD_INST_EXEC (0x09u) // Folded instruction executed.
#define PM_EVT_DCACHE_RD (0x0Au) // Data cache read access, not including cache operations. This event occurs for each non-sequential access to a cache line.
#define PM_EVT_DCACHE_RD_MISS (0x0Bu) // Data cache read miss, not including cache operations.
#define PM_EVT_DCACHE_WR (0x0Cu) // Data cache write access.
#define PM_EVT_DCACHE_WR_MISS (0x0Du) // Data cache write miss.
#define PM_EVT_DCACHE_LINE_EVICT (0x0Eu) // Data cache line eviction, not including cache operations.
#define PM_EVT_PC_CHANGE_NOT_MODE (0x0Fu) // Software changed the PC and there is not a mode change.
#define PM_EVT_TLB_MISS (0x10u) // Main TLB miss.
#define PM_EVT_EXT_MEM_REQ (0x11u) // External memory request (cache refill, noncachable, write-back).
#define PM_EVT_LD_ST_UNIT_STALL (0x12u) // Stall because of Load Store Unit request queue being full.
#define PM_EVT_ST_BUF_DRAIN (0x13u) // The number of times the Store buffer was drained because of LSU ordering constraints or CP15 operations.
#define PM_EVT_BUF_WR_MERGED (0x14u) // Buffered write merged in a store buffer slot.
#define PM_EVT_CYCLE (0xFFu) // An increment each cycle.
#if !__ASSEMBLER__
// Write Performance Monitor Control Register.
ALWAYS_INLINE void __setPmnc(u32 val)
{
__asm__ volatile("mcr p15, 0, %0, c15, c12, 0" : : "r" (val) : "memory");
}
// Write Cycle Counter Register.
ALWAYS_INLINE void __setCcnt(u32 val)
{
__asm__ volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val) : "memory");
}
// Read Count Register 0.
ALWAYS_INLINE void __setPmn0(u32 val)
{
__asm__ volatile("mcr p15, 0, %0, c15, c12, 2" : : "r" (val) : "memory");
}
// Read Count Register 1.
ALWAYS_INLINE void __setPmn1(u32 val)
{
__asm__ volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val) : "memory");
}
// Read Performance Monitor Control Register.
ALWAYS_INLINE u32 __getPmnc(void)
{
u32 tmp;
__asm__ volatile("mrc p15, 0, %0, c15, c12, 0" : "=r" (tmp) : : "memory");
return tmp;
}
// Read Cycle Counter Register.
ALWAYS_INLINE u32 __getCcnt(void)
{
u32 tmp;
__asm__ volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (tmp) : : "memory");
return tmp;
}
// Write Count Register 0.
ALWAYS_INLINE u32 __getPmn0(void)
{
u32 tmp;
__asm__ volatile("mrc p15, 0, %0, c15, c12, 2" : "=r" (tmp) : : "memory");
return tmp;
}
// Write Count Register 1.
ALWAYS_INLINE u32 __getPmn1(void)
{
u32 tmp;
__asm__ volatile("mrc p15, 0, %0, c15, c12, 3" : "=r" (tmp) : : "memory");
return tmp;
}
// Helpers.
// Note: Make sure the performance monitor is off
// before starting to count cycles to avoid
// misleading counter results.
ALWAYS_INLINE void perfMonitorCountCycles(void)
{
__setPmnc(PM_EVT(PM_EVT_INST_EXEC, PM_EVT_ICACHE_MISS) | PM_CCNT_IRQ | PM_PMN1_IRQ |
PM_PMN0_IRQ | PM_CCNT_NODIV | PM_CCNT_RST | PM_PMN01_RST | PM_EN);
}
#endif // #if !__ASSEMBLER__

View File

@ -1,58 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#define PL301_REGS_BASE (IO_MEM_ARM11_ONLY + 0xF400)
typedef struct
{
struct
{
vu32 qos_tidemark; // 0x000 QoS tidemark.
vu32 qos_acs; // 0x004 QoS access control.
vu32 ar_arb; // 0x008 AR channel arbitration value.
vu32 aw_arb; // 0x00C AW channel arbitration value.
u8 _0x10[0x10];
} mi[64]; // Master interface.
u8 _0x800[0x7c0];
const vu32 primecell_cfg0; // 0xFC0 PrimeCell Configuration Register 0.
const vu32 primecell_cfg1; // 0xFC4 PrimeCell Configuration Register 1.
const vu32 primecell_cfg2; // 0xFC8 PrimeCell Configuration Register 2.
const vu32 primecell_cfg3; // 0xFCC PrimeCell Configuration Register 3.
u8 _0xfd0[0x10];
const vu32 primecell_periph0; // 0xFE0 PrimeCell Peripheral Register 0.
const vu32 primecell_periph1; // 0xFE4 PrimeCell Peripheral Register 1.
const vu32 primecell_periph2; // 0xFE8 PrimeCell Peripheral Register 2.
const vu32 primecell_periph3; // 0xFEC PrimeCell Peripheral Register 3.
const vu32 primecell_id0; // 0xFF0 PrimeCell ID Register 0.
const vu32 primecell_id1; // 0xFF4 PrimeCell ID Register 1.
const vu32 primecell_id2; // 0xFF8 PrimeCell ID Register 2.
const vu32 primecell_id3; // 0xFFC PrimeCell ID Register 3.
} Pl301;
static_assert(offsetof(Pl301, primecell_id3) == 0xFFC, "Error: Member primecell_id3 of Pl301 is not at offset 0xFFC!");
ALWAYS_INLINE Pl301* getPl301Regs(void)
{
return (Pl301*)PL301_REGS_BASE;
}

View File

@ -1,96 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#define SCU_REGS_BASE (MPCORE_PRIV_REG_BASE)
typedef struct
{
vu32 ctrl; // 0x00 SCU Control Register.
const vu32 config; // 0x04 SCU Configuration Register.
vu32 cpu_stat; // 0x08 SCU CPU Status Register.
vu32 inval_all; // 0x0C SCU Invalidate All Register. (write-only)
vu32 pmc; // 0x10 Performance Monitor Control Register.
vu32 pme0; // 0x14 Performance monitor event register 0.
vu32 pme1; // 0x18 Performance monitor event register 1.
vu32 mn0; // 0x1C Count register 0.
vu32 mn1; // 0x20 Count register 1.
vu32 mn2; // 0x24 Count register 2.
vu32 mn3; // 0x28 Count register 3.
vu32 mn4; // 0x2C Count register 4.
vu32 mn5; // 0x30 Count register 5.
vu32 mn6; // 0x34 Count register 6.
vu32 mn7; // 0x38 Count register 7.
} Scu;
static_assert(offsetof(Scu, mn7) == 0x38, "Error: Member mn7 of Scu is not at offset 0x38!");
ALWAYS_INLINE Scu* getScuRegs(void)
{
return (Scu*)SCU_REGS_BASE;
}
// REG_SCU_CTRL
#define SCU_EN (1u) // SCU is enabled, coherency is maintained between MP11 CPUs Level 1 data side caches.
#define SCU_ACS(n) (1u<<((n) + 1)) // CPUn can write to SCU-specific registers.
#define SCU_INT_ALIAS_ACS(n) (1u<<((n) + 5)) // CPUn can access aliased interrupt interface registers in the offset range 0x0200 to 0x050FF of the MPCore private memory region.
#define SCU_TMR_ALIAS_ACS(n) (1u<<((n) + 9)) // CPUn can access aliased timer and watchdog registers in the offset range 0x0700 to 0x0A0FF of the MPCore private memory region.
#define SCU_PARITY_CHK_EN (1u<<13) // SCU parity checking enable bit.
#define SCU_CTRL_RST_VAL (SCU_TMR_ALIAS_ACS(3u) | SCU_TMR_ALIAS_ACS(2u) | \
SCU_TMR_ALIAS_ACS(1u) | SCU_TMR_ALIAS_ACS(0u) | \
SCU_INT_ALIAS_ACS(3u) | SCU_INT_ALIAS_ACS(2u) | \
SCU_INT_ALIAS_ACS(1u) | SCU_INT_ALIAS_ACS(0u) | \
SCU_ACS(3u) | SCU_ACS(2u) | SCU_ACS(1u) | SCU_ACS(0u))
// REG_SCU_CONFIG
#define SCU_CPU_NUM_1 (0u) // 1 MP11 CPU, CPU0.
#define SCU_CPU_NUM_2 (1u) // 2 MP11 CPUs, CPU0-CPU1.
#define SCU_CPU_NUM_3 (2u) // 3 MP11 CPUs, CPU0-CPU2.
#define SCU_CPU_NUM_4 (3u) // 4 MP11 CPUs, CPU0-CPU3.
#define SCU_CPU_NUM_MASK (SCU_CPU_NUM_4)
#define SCU_SMP(n) (1u<<((n) + 4)) // MP11 CPUn is in SMP mode taking part in coherency.
#define SCU_TRAM_16KB_64I(n) (0u) // CPUn 16KB cache, 64 indexes per tag RAM.
#define SCU_TRAM_32KB_128I(n) (1u<<((n) * 2 + 8)) // CPUn 32KB cache, 128 indexes per tag RAM.
#define SCU_TRAM_64KB_256I(n) (2u<<((n) * 2 + 8)) // CPUn 64KB cache, 256 indexes per tag RAM.
// REG_SCU_CPU_STAT
#define SCU_STAT_NORMAL(n) (0u) // CPUn Normal mode (Default).
// 1 reserved.
#define SCU_STAT_DORMANT(n) (2u<<((n) * 2)) // CPUn is about to enter (or is in) dormant mode. No CCB request is sent to the CPU.
#define SCU_STAT_PWROFF(n) (3u<<((n) * 2)) // CPUn is about to enter (or is in) powered-off mode, or is nonpresent. No CCB request is sent to the CPU.
#define SCU_STAT_MASK(n) (SCU_STAT_PWROFF(n))
// REG_SCU_INVAL_ALL
#define SCU_WAY_0(n) (1u<<((n) * 4)) // CPUn invalidate way 0.
#define SCU_WAY_1(n) (2u<<((n) * 4)) // CPUn invalidate way 1.
#define SCU_WAY_2(n) (4u<<((n) * 4)) // CPUn invalidate way 2.
#define SCU_WAY_3(n) (8u<<((n) * 4)) // CPUn invalidate way 3.
#define SCU_WAY_ALL (SCU_WAY_3(3u) | SCU_WAY_2(3u) | SCU_WAY_1(3u) | \
SCU_WAY_0(3u) | SCU_WAY_3(2u) | SCU_WAY_2(2u) | \
SCU_WAY_1(2u) | SCU_WAY_0(2u) | SCU_WAY_3(1u) | \
SCU_WAY_2(1u) | SCU_WAY_1(1u) | SCU_WAY_0(1u) | \
SCU_WAY_3(0u) | SCU_WAY_2(0u) | SCU_WAY_1(0u) | \
SCU_WAY_0(0u))
// TODO: SCU performance monitor bits.

View File

@ -1,178 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#define NSPI1_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x60800)
#define NSPI2_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x42800)
#define NSPI3_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x43800)
typedef struct
{
vu32 cnt; // 0x00
vu8 cs; // 0x04 32 bit but can be accessed as u8.
u8 _0x5[3];
vu32 blklen; // 0x08
vu32 fifo; // 0x0C
vu8 fifo_stat; // 0x10 32 bit but can be accessed as u8.
u8 _0x11[3];
vu32 autopoll; // 0x14
vu32 int_mask; // 0x18
vu32 int_stat; // 0x1C
} NspiBus;
static_assert(offsetof(NspiBus, int_stat) == 0x1C, "Error: Member int_stat of NspiBus is not at offset 0x1C!");
enum
{
SPI_BUS1 = 0u,
SPI_BUS2 = 1u,
SPI_BUS3 = 2u
};
ALWAYS_INLINE NspiBus* getNspiBusRegs(u8 busId)
{
NspiBus *nspiBus;
switch(busId)
{
case SPI_BUS1:
nspiBus = (NspiBus*)NSPI1_REGS_BASE;
break;
case SPI_BUS2:
nspiBus = (NspiBus*)NSPI2_REGS_BASE;
break;
case SPI_BUS3:
nspiBus = (NspiBus*)NSPI3_REGS_BASE;
break;
default:
nspiBus = NULL;
}
return nspiBus;
}
// REG_NSPI_CNT
enum
{
NSPI_CLK_512KHZ = 0u,
NSPI_CLK_1MHZ = 1u,
NSPI_CLK_2MHZ = 2u,
NSPI_CLK_4MHZ = 3u,
NSPI_CLK_8MHZ = 4u,
NSPI_CLK_16MHZ = 5u
};
enum
{
NSPI_CS_0 = 0u<<6,
NSPI_CS_1 = 1u<<6,
NSPI_CS_2 = 2u<<6
};
#define NSPI_BUS_1BIT (0u)
#define NSPI_BUS_4BIT (1u<<12)
#define NSPI_DIR_R (0u) // Direction read.
#define NSPI_DIR_W (1u<<13) // Direction write.
#define NSPI_EN (1u<<15) // Enable.
// REG_NSPI_CS
#define NSPI_CS_HIGH (0u)
// NSPI_FIFO_STAT
#define NSPI_FIFO_BUSY (1u)
// REG_NSPI_AUTOPOLL
// Shifts.
#define NSPI_AP_TMOUT_SHIFT (16u) // Auto poll register timeout shift.
#define NSPI_AP_OFF_SHIFT (24u) // Auto poll register bit offset shift.
#define NSPI_AP_BIT_SHIFT (30u) // Auto poll register compare bit shift.
#define NSPI_AP_START (1u<<31) // Auto poll start.
// REG_NSPI_INT_MASK Bit set = disabled.
// REG_NSPI_INT_STAT Status and acknowledge.
#define NSPI_INT_TRAN_END (1u) // Transfer end. Also fires on each auto poll try.
#define NSPI_INT_AP_MATCH (1u<<1) // Auto poll bit match.
#define NSPI_INT_AP_TMOUT (1u<<2) // Auto poll timeout.
// TODO: Implement old SPI interfaces.
// Old interface clocks.
/*enum
{
SPI_CLK_4MHZ = 0u,
SPI_CLK_2MHZ = 1u,
SPI_CLK_1MHZ = 2u,
SPI_CLK_512KHZ = 3u,
SPI_CLK_8MHZ = 4u // Only in DSi/3DS mode.
};*/
typedef enum
{
NSPI_DEV_POWERMAN = 0u, // DS(i) mode power management.
NSPI_DEV_NVRAM = 1u, // WiFi SPI flash.
NSPI_DEV_TWL_CODEC = 2u, // DSi mode SPI interface.
NSPI_DEV_CTR_CODEC = 3u, // 3DS mode SPI interface.
//NSPI_DEV_UNUSED5 = 4u, // Unused.
//NSPI_DEV_UNUSED6 = 5u, // Unused.
//NSPI_DEV_UNUSED7 = 6u, // Debugger?
// Not a real device. Or with device number
// to set chip select high after transfer.
NSPI_DEV_CS_HIGH = 1u<<7
} SpiDevice;
// cmd Is the command byte to send.
// tmout Is the timeout. Must be 0-15. Tries = 31<<(NspiClk + timeout).
// off Is the bit offset in the response byte. Must be 0-7.
// cmpBit Is the bit to compare (0 or 1).
#define MAKE_AP_PARAMS(cmd, tmout, off, cmpBit) ((u32)(cmpBit)<<30 | (u32)(off)<<24 | (u32)(tmout)<<16 | (cmd))
/**
* @brief Initializes the SPI buses. Call this only once.
*/
void NSPI_init(void);
/**
* @brief Automatically polls a bit of the command response.
*
* @param[in] dev The device ID. See SpiDevice table.
* @param[in] apParams The parameters. Use the MAKE_AP_PARAMS macro.
*
* @return Returns false on timeout and true on bit match.
*/
bool NSPI_autoPollBit(SpiDevice dev, u32 apParams);
/**
* @brief Writes and/or reads data to/from a SPI device.
*
* @param[in] dev The device ID. See SpiDevice table.
* @param[in] in Input data pointer for write.
* @param out Output data pointer for read.
* @param[in] inSize Input size. Must be <= 0x1FFFFF.
* @param[in] outSize Output size. Must be <= 0x1FFFFF.
*/
void NSPI_writeRead(SpiDevice dev, const u32 *in, u32 *out, u32 inSize, u32 outSize);

View File

@ -1,41 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#define SPIFLASH_PP (0x02u) // Page Program (0x100 bytes).
#define SPIFLASH_READ (0x03u) // Read.
#define SPIFLASH_WRDI (0x04u) // Write Disable.
#define SPIFLASH_RDSR (0x05u) // Read Status Register.
#define SPIFLASH_WREN (0x06u) // Write Enable.
#define SPIFLASH_PW (0x0Au) // Page Write (0x100 bytes).
#define SPIFLASH_FAST (0x0Bu) // Fast Read.
#define SPIFLASH_RDP (0xABu) // Release from Deep Power-down.
#define SPIFLASH_DP (0xB9u) // Deep Power-Down.
#define SPIFLASH_SE (0xD8u) // Sector Erase (0x10000 bytes).
#define SPIFLASH_PE (0xDBu) // Page Erase (0x100 bytes).
#define SPIFLASH_RDID (0x9Fu) // Read JEDEC Identification.
// true if spiflash is installed, false otherwise
bool spiflash_get_status(void);
void spiflash_read(u32 offset, u32 size, u32 *buf);

View File

@ -1,116 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#define TIMER_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x600)
typedef struct
{
vu32 load; // 0x00
vu32 counter; // 0x04
vu32 cnt; // 0x08
vu32 int_stat; // 0x0C
u8 _0x10[0x10];
vu32 wd_load; // 0x20
vu32 wd_counter; // 0x24
vu32 wd_cnt; // 0x28
vu32 wd_int_stat; // 0x2C
vu32 wd_reset_stat; // 0x30
vu32 wd_disable; // 0x34
} Timer;
static_assert(offsetof(Timer, wd_disable) == 0x34, "Error: Member wd_disable of Timer is not at offset 0x34!");
ALWAYS_INLINE Timer* getTimerRegs(void)
{
return (Timer*)TIMER_REGS_BASE;
}
// REG_TIMER_CNT/REG_WD_CNT
#define TIMER_EN (1u)
#define TIMER_SINGLE_SHOT (0u)
#define TIMER_AUTO_RELOAD (1u<<1)
#define TIMER_IRQ_EN (1u<<2)
#define WD_TIMER_MODE (0u) // Watchdog only. Watchdog in timer mode.
#define WD_WD_MODE (1u<<3) // Watchdog only. Watchdog in watchdog mode.
#define TIMER_PRESC_SHIFT (8u) // Shift helper for the prescalers.
// REG_WD_DISABLE
#define WD_DISABLE_MAGIC1 (0x12345678u)
#define WD_DISABLE_MAGIC2 (0x87654321u)
#define TIMER_BASE_FREQ (268111856.f)
// p is the prescaler value and n the frequency.
// Note: With highest prescaler and sub-microsecond frequency
// this may give wrong results due to overflows.
#define TIMER_FREQ(p, f) (TIMER_BASE_FREQ / (2 * (p) * (f)))
/**
* @brief Resets/initializes the timer hardware. Should not be called manually.
*/
void TIMER_init(void);
/**
* @brief Starts the timer.
*
* @param[in] prescaler The prescaler (1-256).
* @param[in] ticks The initial number of ticks. This is also the reload
* value in auto reload mode.
* @param[in] params The parameters. See /regs/timer.h "REG_TIMER_CNT" defines.
*/
void TIMER_start(u16 prescaler, u32 ticks, u8 params);
/**
* @brief Returns the current number of ticks of the timer.
*
* @return The number of ticks.
*/
u32 TIMER_getTicks(void);
/**
* @brief Stops the timer and returns the current number of ticks.
*
* @return The number of ticks.
*/
u32 TIMER_stop(void);
/**
* @brief Halts the CPU for the given number of ticks.
* Use the function below for milliseconds.
*
* @param[in] ticks The number of ticks to sleep.
*/
void TIMER_sleepTicks(u32 ticks);
// Sleeps ms milliseconds. ms can be up to 32000.
// TODO: Should this be inline? Generates a bunch of vfp code.
ALWAYS_INLINE void TIMER_sleepMs(u32 ms)
{
TIMER_sleepTicks(TIMER_FREQ(1, 1000) * ms);
}

View File

@ -1,48 +0,0 @@
#pragma once
/*
* This file is part of Luma3DS
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
* * Requiring preservation of specified reasonable legal notices or
* author attributions in that material or in the Appropriate Legal
* Notices displayed by works containing it.
* * Prohibiting misrepresentation of the origin of that material,
* or requiring that modified versions of such material be marked in
* reasonable ways as different from the original version.
*/
#include <stdarg.h>
#include "types.h"
u32 ee_vsnprintf(char *const buf, u32 size, const char *const fmt, va_list arg);
u32 ee_vsprintf(char *const buf, const char *const fmt, va_list arg);
__attribute__ ((format (printf, 2, 3))) u32 ee_sprintf(char *const buf, const char *const fmt, ...);
__attribute__ ((format (printf, 3, 4))) u32 ee_snprintf(char *const buf, u32 size, const char *const fmt, ...);
__attribute__ ((format (printf, 1, 2))) u32 ee_printf(const char *const fmt, ...);
u32 ee_puts(const char *const str);
#ifdef NDEBUG
#define debug_printf(fmt, ...) ((void)0)
#define debug_puts(str) ((void)0)
#else
#define debug_printf(fmt, ...) ee_printf(fmt, ##__VA_ARGS__)
#define debug_puts(str) ee_puts(str)
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,24 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
noreturn void power_off(void);
noreturn void power_reboot(void);

View File

@ -1,45 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
static inline void spinlockLock(u32 *lock)
{
u32 tmp;
__asm__ volatile("1: ldrex %0, [%1]\n"
" teq %0, #0\n"
" wfene\n"
" strexeq %0, %2, [%1]\n"
" teqeq %0, #0\n"
" bne 1b\n"
" mcr p15, 0, %0, c7, c10, 5" // DMB
: "=&r" (tmp) : "r" (lock), "r" (1) : "cc", "memory");
}
static inline void spinlockUnlock(u32 *lock)
{
__asm__ volatile("mcr p15, 0, %0, c7, c10, 5\n" // DMB
"str %0, [%1]\n"
"mcr p15, 0, %0, c7, c10, 4\n" // DSB
"sev"
: : "r" (0), "r" (lock) : "memory");
}

View File

@ -1,26 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
noreturn void _start(void);
void deinitCpu(void);

View File

@ -1,149 +0,0 @@
/**
* @file rbtree.h
* @brief Red-black trees.
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
/// Retrieves an rbtree item.
#define rbtree_item(ptr, type, member) \
((type*)(((char*)ptr) - offsetof(type, member)))
typedef struct rbtree rbtree_t; ///< rbtree type.
typedef struct rbtree_node rbtree_node_t; ///< rbtree node type.
typedef void (*rbtree_node_destructor_t)(rbtree_node_t *Node); ///< rbtree node destructor.
typedef int (*rbtree_node_comparator_t)(const rbtree_node_t *lhs,
const rbtree_node_t *rhs); ///< rbtree node comparator.
/// An rbtree node.
struct rbtree_node
{
uintptr_t parent_color; ///< Parent color.
rbtree_node_t *child[2]; ///< Node children.
};
/// An rbtree.
struct rbtree
{
rbtree_node_t *root; ///< Root node.
rbtree_node_comparator_t comparator; ///< Node comparator.
size_t size; ///< Size.
};
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initializes an rbtree.
* @param tree Pointer to the tree.
* @param comparator Comparator to use.
*/
void
rbtree_init(rbtree_t *tree,
rbtree_node_comparator_t comparator);
/**
* @brief Gets whether an rbtree is empty
* @param tree Pointer to the tree.
* @return A non-zero value if the tree is not empty.
*/
int
rbtree_empty(const rbtree_t *tree);
/**
* @brief Gets the size of an rbtree.
* @param tree Pointer to the tree.
*/
size_t
rbtree_size(const rbtree_t *tree);
/**
* @brief Inserts a node into an rbtree.
* @param tree Pointer to the tree.
* @param node Pointer to the node.
* @return The inserted node.
*/
__attribute__((warn_unused_result))
rbtree_node_t*
rbtree_insert(rbtree_t *tree,
rbtree_node_t *node);
/**
* @brief Inserts multiple nodes into an rbtree.
* @param tree Pointer to the tree.
* @param node Pointer to the nodes.
*/
void
rbtree_insert_multi(rbtree_t *tree,
rbtree_node_t *node);
/**
* @brief Finds a node within an rbtree.
* @param tree Pointer to the tree.
* @param node Pointer to the node.
* @return The located node.
*/
rbtree_node_t*
rbtree_find(const rbtree_t *tree,
const rbtree_node_t *node);
/**
* @brief Gets the minimum node of an rbtree.
* @param tree Pointer to the tree.
* @return The minimum node.
*/
rbtree_node_t*
rbtree_min(const rbtree_t *tree);
/**
* @brief Gets the maximum node of an rbtree.
* @param tree Pointer to the tree.
* @return The maximum node.
*/
rbtree_node_t*
rbtree_max(const rbtree_t *tree);
/**
* @brief Gets the next node from an rbtree node.
* @param node Pointer to the node.
* @return The next node.
*/
rbtree_node_t*
rbtree_node_next(const rbtree_node_t *node);
/**
* @brief Gets the previous node from an rbtree node.
* @param node Pointer to the node.
* @return The previous node.
*/
rbtree_node_t*
rbtree_node_prev(const rbtree_node_t *node);
/**
* @brief Removes a node from an rbtree.
* @param tree Pointer to the tree.
* @param node Pointer to the node.
* @param destructor Destructor to use when removing the node.
* @return The removed node.
*/
rbtree_node_t*
rbtree_remove(rbtree_t *tree,
rbtree_node_t *node,
rbtree_node_destructor_t destructor);
/**
* @brief Clears an rbtree.
* @param tree Pointer to the tree.
* @param destructor Destructor to use when clearing the tree's nodes.
*/
void
rbtree_clear(rbtree_t *tree,
rbtree_node_destructor_t destructor);
#ifdef __cplusplus
}
#endif

View File

@ -1,30 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
noreturn void _a7_overlay_stub(void);
extern const u32 _a7_overlay_stub_size[];
noreturn void _a7_stub_start(void);
extern u16 _a7_stub9_swi[]; // Final ARM9 mem location.
extern const u32 _a7_stub_size[];

View File

@ -1,27 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
noreturn void panic();
noreturn void panicMsg(const char *msg);
//void dumpMem(u8 *mem, u32 size, char *filepath);

View File

@ -1,124 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#define CFG9_REGS_BASE (IO_MEM_ARM9_ONLY)
typedef struct
{
vu8 sysprot9; // 0x00000
vu8 sysprot11; // 0x00001
vu8 unk00002; // 0x00002 Bit 0 bootrom write enable? Cleared immediately in boot9.
u8 _0x3;
vu16 unk00004; // 0x00004 JTAG related?
u8 _0x6[2];
vu8 xdma_req; // 0x00008 Enable requests for XDMA. Each bit 1 = enabled.
u8 _0x9[3];
vu16 cardctl; // 0x0000C
u8 _0xe[2];
vu8 card_power; // 0x00010
u8 _0x11;
vu16 card_insert_delay; // 0x00012 Insert delay in 0x400 cycle units.
vu16 card_pwroff_delay; // 0x00014 Power off delay in 0x400 cycle units.
u8 _0x16[0xa];
vu16 sdmmcctl; // 0x00020
u8 _0x22[0xde];
vu16 unk00100; // 0x00100 Similar to SCFG_EXT regs on DSi?
u8 _0x102[0xfe];
vu8 extmemcnt9; // 0x00200
u8 _0x201[0xdfb];
const vu16 socinfo; // 0x00FFC Same as REG_CFG11_SOCINFO.
u8 _0xffe[0xf002];
vu32 bootenv; // 0x10000
u8 _0x10004[0xc];
const vu8 unitinfo; // 0x10010
u8 _0x10011[3];
vu8 twlunitinfo; // 0x10014 Writable reg for TWL mode.
u8 _0x10015[0xb];
vu8 unk10020; // 0x10020 Bootrom related?
} Cfg9;
static_assert(offsetof(Cfg9, unk10020) == 0x10020, "Error: Member unk10020 of Cfg9 is not at offset 0x10020!");
ALWAYS_INLINE Cfg9* getCfg9Regs(void)
{
return (Cfg9*)CFG9_REGS_BASE;
}
// REG_CFG9_SYSPROT9
#define SYSPROT9_ROM_H2_LOCK (1u) // Disables access to the second half of the ARM9 bootrom. Also enables FCRAM access.
#define SYSPROT9_OTP_LOCK (1u<<1) // Disables access to the OTP.
// REG_CFG9_SYSPROT11
#define SYSPROT11_ROM_H2_LOCK (1u) // Disables access to the second half of the ARM11 bootrom. Also enables FCRAM access.
// REG_CFG9_XDMA_REQ
#define XDMA_REQ_TOSHSD1 (1u) // Toshsd controller 1 (SD card slot/eMMC).
#define XDMA_REQ_TOSHSD3 (1u<<1) // Toshsd controller 3 (SD card slot).
#define XDMA_REQ_AES_IN (1u<<2)
#define XDMA_REQ_AES_OUT (1u<<3)
// REG_CFG9_CARDCTL
#define CARDCTL_NTRCARD (0u) // Controller at 0x10164000.
#define CARDCTL_UNK1 (1u) // Unknown controller/function.
#define CARDCTL_CTRCARD1 (2u) // Controller at 0x10004000.
#define CARDCTL_CTRCARD2 (3u) // Controller at 0x10005000.
#define CARDCTL_SPIC_FIFO_MODE (1u<<4) // TODO: Confirm this. If set use regs at 0x1000D800 otherwise 0x1000D000.
#define CARDCTL_SPIC_SEL (1u<<8) // If set use regs at 0x1000D000/0x1000D800 otherwise regs at 0x10164000.
// REG_CFG9_CARD_POWER
#define CARD_POWER_EJECTED (1u) // No card inserted.
#define CARD_POWER_OFF (0u<<2) // Slot powered off.
#define CARD_POWER_ON_RESET (1u<<2) // Powered on and in reset.
#define CARD_POWER_ON (2u<<2) // Powered on.
#define CARD_POWER_OFF_REQ (3u<<2) // Power off request.
// REG_CFG9_SDMMCCTL
#define SDMMCCTL_CARD_PWR_OFF (1u) // Controller 1/3 port 0 (MMC/SD card slot).
#define SDMMCCTL_eMMC_PWR_OFF (1u<<1) // Controller 1 port 1.
#define SDMMCCTL_WiFi_PWR_OFF (1u<<2) // Controller 2 port 0.
#define SDMMCCTL_UNK_PWR_OFF (1u<<3) // Controller 3 port 1 power off? Set at cold boot.
#define SDMMCCTL_UNK_BIT6 (1u<<6) // Wifi port related? Pull up? Set at cold boot.
#define SDMMCCTL_TOSHSD3_MAP9 (0u) // Controller 3 mapping ARM9 0x10007000.
#define SDMMCCTL_TOSHSD3_MAP11 (1u<<8) // Controller 3 mapping ARM11 0x10100000.
#define SDMMCCTL_CARD_TOSHSD3_SEL (0u) // SD card slot controller select TOSHSD3 0x10007000/0x10100000.
#define SDMMCCTL_CARD_TOSHSD1_SEL (1u<<9) // SD card slot controller select TOSHSD1 0x10006000.
// REG_CFG9_EXTMEMCNT9
#define EXTMEMCNT9_WRAM_EXT_E (1u) // Enables extra WRAM aka. ARM9 mem extension.
// REG_CFG9_SOCINFO
#define SOCINFO_CTR (1u) // Also set on New 3DS.
#define SOCINFO_LGR1 (1u<<1) // Never saw the daylight? Set on retail N3DS (LGR2).
#define SOCINFO_LGR2 (1u<<2) // Set on New 3DS.
// REG_CFG9_BOOTENV
#define BOOTENV_COLD_BOOT (0u)
#define BOOTENV_NATIVE_FIRM (1u)
#define BOOTENV_TWL_FIRM (3u)
#define BOOTENV_AGB_FIRM (7u)
// REG_CFG9_UNITINFO
// TODO: Collect all the possible values for this reg.
#define UNITINFO_RETAIL (0u)

View File

@ -1,34 +0,0 @@
#pragma once
/*
* This code is part of ctrulib (https://github.com/smealum/ctrulib)
*/
#include "types.h"
#define HID_KEY_MASK_ALL ((KEY_Y << 1) - 1)
#define HID_VERBOSE_MODE_BUTTONS (KEY_SELECT | KEY_START)
enum
{
KEY_A = 1u,
KEY_B = 1u<<1,
KEY_SELECT = 1u<<2,
KEY_START = 1u<<3,
KEY_DRIGHT = 1u<<4,
KEY_DLEFT = 1u<<5,
KEY_DUP = 1u<<6,
KEY_DDOWN = 1u<<7,
KEY_R = 1u<<8,
KEY_L = 1u<<9,
KEY_X = 1u<<10,
KEY_Y = 1u<<11
};
void hidScanInput(void);
u32 hidKeysHeld(void);
u32 hidKeysDown(void);
u32 hidKeysUp(void);

View File

@ -1,99 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "arm.h"
#include "types.h"
typedef enum
{
IRQ_DMAC_1_0 = 0u, // DMAC_1 = NDMA
IRQ_DMAC_1_1 = 1u,
IRQ_DMAC_1_2 = 2u,
IRQ_DMAC_1_3 = 3u,
IRQ_DMAC_1_4 = 4u,
IRQ_DMAC_1_5 = 5u,
IRQ_DMAC_1_6 = 6u,
IRQ_DMAC_1_7 = 7u,
IRQ_TIMER_0 = 8u,
IRQ_TIMER_1 = 9u,
IRQ_TIMER_2 = 10u,
IRQ_TIMER_3 = 11u,
IRQ_PXI_SYNC = 12u,
IRQ_PXI_NOT_FULL = 13u,
IRQ_PXI_NOT_EMPTY = 14u,
IRQ_AES = 15u,
IRQ_TOSHSD1 = 16u,
IRQ_TOSHSD1_IRQ = 17u,
IRQ_TOSHSD3 = 18u,
IRQ_TOSHSD3_IRQ = 19u,
IRQ_DEBUG_RECV = 20u,
IRQ_DEBUG_SEND = 21u,
IRQ_RSA = 22u,
IRQ_CTR_CARD_1 = 23u, // SPICARD and CTRCARD too?
IRQ_CTR_CARD_2 = 24u,
IRQ_CGC = 25u,
IRQ_CGC_DET = 26u,
IRQ_DS_CARD = 27u,
IRQ_DMAC_2 = 28u,
IRQ_DMAC_2_ABORT = 29u
} Interrupt;
// IRQ interrupt service routine type.
// id: contains the interrupt ID
typedef void (*IrqIsr)(u32 id);
/**
* @brief Initializes interrupts.
*/
void IRQ_init(void);
/**
* @brief Registers a interrupt service routine and enables the specified interrupt.
*
* @param[in] id The interrupt ID. Must be <32.
* @param[in] isr The interrupt service routine to call.
*/
void IRQ_registerIsr(Interrupt id, IrqIsr isr);
/**
* @brief Unregisters the interrupt service routine and disables the specified interrupt.
*
* @param[in] id The interrupt ID. Must be <32.
*/
void IRQ_unregisterIsr(Interrupt id);
#if !__thumb__
static inline u32 enterCriticalSection(void)
{
u32 tmp;
__setCpsr_c((tmp = __getCpsr()) | PSR_I);
return tmp & PSR_I;
}
static inline void leaveCriticalSection(u32 oldState)
{
__setCpsr_c((__getCpsr() & ~PSR_I) | oldState);
}
#endif

View File

@ -1,148 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#include "util.h"
#define NDMA_REGS_BASE (IO_MEM_ARM9_ONLY + 0x2000)
#define REG_NDMA_GCNT *((vu32*)NDMA_REGS_BASE) // Global control.
// Note: The channel regs are offset by 4 (REG_NDMA_GLOBAL_CNT).
typedef struct
{
vu32 sad; // 0x00 Source address.
vu32 dad; // 0x04 Destination address.
vu32 tcnt; // 0x08 Total repeat length in words.
vu32 wcnt; // 0x0C Logical block size in words.
vu32 bcnt; // 0x10 Block transfer timing/interval.
vu32 fdata; // 0x14 Fill data.
vu32 cnt; // 0x18 Control.
} NdmaCh;
static_assert(offsetof(NdmaCh, cnt) == 0x18, "Error: Member cnt of NdmaCh is not at offset 0x18!");
ALWAYS_INLINE NdmaCh* getNdmaChRegs(u8 c)
{
return &((NdmaCh*)(NDMA_REGS_BASE + 4))[c];
}
// REG_NDMA_GCNT
#define NDMA_REG_READBACK (1u) // Show internal state on REG_NDMAx_SAD/DAD/TCNT/WCNT. 3DS mode only.
#define NDMA_ROUND_ROBIN(n) (1u<<31 | (intLog2(n) + 1)<<16) // DSP DMA/CPU cycles (power of 2). Maximum 16384.
#define NDMA_HIGHEST_PRIO (0u)
// REG_NDMA_BCNT
// TODO: When is the delay happening during transfers?
// TODO: Does NDMA run at 67 MHz in 3DS mode? We will assume so for now.
#define NDMA_CYCLES(n) (n) // Maximum 65535. 0 means no delay/interval.
#define NDMA_PRESCALER_1 (0u) // 67027964 Hz.
#define NDMA_PRESCALER_4 (1u<<16) // 16756991 Hz.
#define NDMA_PRESCALER_16 (2u<<16) // 4189247.75 Hz.
#define NDMA_PRESCALER_64 (3u<<16) // 1047311.9375 Hz.
#define NDMA_FASTEST (NDMA_PRESCALER_1 | NDMA_CYCLES(0)) // Convenience macro.
// REG_NDMA_CNT
#define NDMA_DAD_INC (0u) // Destination address increment.
#define NDMA_DAD_DEC (1u<<10) // Destination address decrement.
#define NDMA_DAD_FIX (2u<<10) // Destination address fixed.
#define NDMA_DAD_RELOAD (1u<<12) // Reload destination address on logical block end (REG_NDMAx_WCNT).
#define NDMA_SAD_INC (0u) // Source address increment.
#define NDMA_SAD_DEC (1u<<13) // Source address decrement.
#define NDMA_SAD_FIX (2u<<13) // Source address fixed.
#define NDMA_SAD_FILL (3u<<13) // Source is REG_NDMAx_FDATA.
#define NDMA_SAD_RELOAD (1u<<15) // Reload source address on logical block end (REG_NDMAx_WCNT).
#define NDMA_BURST_SHIFT (16u)
#define NDMA_BURST(n) (intLog2(n)<<NDMA_BURST_SHIFT) // Burst length is 2ⁿ words. Maximum 32768. Must be power of 2.
#define NDMA_TCNT_MODE (0u) // REG_NDMAx_TCNT mode.
#define NDMA_REPEAT_MODE (1u<<29) // Repeat transfer infinitely.
#define NDMA_IRQ_EN (1u<<30) // IRQ enable.
#define NDMA_EN (1u<<31) // Channel enable/active.
enum
{
NDMA_START_TIMER0 = 0u<<24,
NDMA_START_TIMER1 = 1u<<24,
NDMA_START_TIMER2 = 2u<<24,
NDMA_START_TIMER3 = 3u<<24,
NDMA_START_CTRCARD1 = 4u<<24, // And for SPICARD.
NDMA_START_CTRCARD2 = 5u<<24, // And for SPICARD?
NDMA_START_TOSHSD1 = 6u<<24,
NDMA_START_TOSHSD3 = 7u<<24,
NDMA_START_AES_IN = 8u<<24, // AES write fifo.
NDMA_START_AES_OUT = 9u<<24, // AES read fifo.
NDMA_START_SHA_IN = 10u<<24,
NDMA_START_SHA_OUT = 11u<<24, // For chaining.
NDMA_START_NTRCARD = 12u<<24,
// 13 and 14 unused?
NDMA_START_DEV2DEV = 15u<<24, // Needed for below startup modes.
// Direct device to device modes.
NDMA_START_CTRCARD1_AES = NDMA_START_DEV2DEV | 0u, // CTRCARD1 to AES.
NDMA_START_CTRCARD2_AES = NDMA_START_DEV2DEV | 1u, // CTRCARD2 to AES.
NDMA_START_AES_CTRCARD1 = NDMA_START_DEV2DEV | 2u, // AES to CTRCARD1.
NDMA_START_AES_CTRCARD2 = NDMA_START_DEV2DEV | 3u, // AES to CTRCARD2.
NDMA_START_CTRCARD1_SHA = NDMA_START_DEV2DEV | 4u, // CTRCARD1 to SHA.
NDMA_START_CTRCARD2_SHA = NDMA_START_DEV2DEV | 5u, // CTRCARD2 to SHA.
NDMA_START_SHA_CTRCARD1 = NDMA_START_DEV2DEV | 6u, // SHA to CTRCARD1.
NDMA_START_SHA_CTRCARD2 = NDMA_START_DEV2DEV | 7u, // SHA to CTRCARD2.
NDMA_START_TOSHSD1_AES = NDMA_START_DEV2DEV | 8u, // TOSHSD1 to AES.
NDMA_START_TOSHSD3_AES = NDMA_START_DEV2DEV | 9u, // TOSHSD3 to AES.
NDMA_START_AES_TOSHSD1 = NDMA_START_DEV2DEV | 10u, // AES to TOSHSD1.
NDMA_START_AES_TOSHSD3 = NDMA_START_DEV2DEV | 11u, // AES to TOSHSD3.
NDMA_START_TOSHSD1_SHA = NDMA_START_DEV2DEV | 12u, // TOSHSD1 to SHA.
NDMA_START_TOSHSD3_SHA = NDMA_START_DEV2DEV | 13u, // TOSHSD3 to SHA.
NDMA_START_SHA_TOSHSD1 = NDMA_START_DEV2DEV | 14u, // SHA to TOSHSD1.
NDMA_START_SHA_TOSHSD3 = NDMA_START_DEV2DEV | 15u, // SHA to TOSHSD3.
NDMA_START_AES_SHA = NDMA_START_DEV2DEV | 16u, // AES to SHA.
NDMA_START_SHA_AES = NDMA_START_DEV2DEV | 17u, // SHA to AES.
// 18-31 unused?
// This bit is technically not part of the startup modes.
NDMA_START_IMMEDIATE = 16u<<24
};
/**
* @brief Initializes all NDMA channels.
*/
void NDMA_init(void);
/**
* @brief Copies data using the NDMA engine.
*
* @param dst Pointer to destination memory. Must be 4 bytes aligned.
* @param src Pointer to source data. Must be 4 bytes aligned.
* @param[in] size The size of the data. Must be multiple of 4.
*/
void NDMA_copy(u32 *const dst, const u32 *const src, u32 size);
/**
* @brief Fills memory with the given value using the NDMA engine.
*
* @param dst Pointer to destination memory. Must be 4 bytes aligned.
* @param[in] value The value each 32-bit word will be set to.
* @param[in] size The size of the memory to fill. Must be multiple of 4.
*/
void NDMA_fill(u32 *const dst, const u32 value, u32 size);

View File

@ -1,123 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#define SPICARD_REGS_BASE (IO_MEM_ARM9_ONLY + 0xD800)
typedef struct
{
vu32 cnt; // 0x00
vu8 cs; // 0x04 32 bit but can be accessed as u8.
u8 _0x5[3];
vu32 blklen; // 0x08
vu32 fifo; // 0x0C
vu8 fifo_stat; // 0x10 32 bit but can be accessed as u8.
u8 _0x11[3];
vu32 autopoll; // 0x14
vu32 int_mask; // 0x18
vu32 int_stat; // 0x1C
} Spic;
static_assert(offsetof(Spic, int_stat) == 0x1C, "Error: Member int_stat of Spic is not at offset 0x1C!");
ALWAYS_INLINE Spic* getSpicRegs(void)
{
return (Spic*)SPICARD_REGS_BASE;
}
// REG_SPIC_CNT
typedef enum
{
SPIC_CLK_512KHz = 0u,
SPIC_CLK_1MHz = 1u,
SPIC_CLK_2MHz = 2u,
SPIC_CLK_4MHz = 3u,
SPIC_CLK_8MHz = 4u,
SPIC_CLK_16MHz = 5u,
// Not a real clock setting. Or with clock
// to set chip select high after transfer.
SPIC_CLK_CS_HIGH = 1u<<3
} SpicClk;
#define SPIC_BUS_1BIT (0u)
#define SPIC_BUS_4BIT (1u<<12)
#define SPIC_DIR_R (0u) // Direction read.
#define SPIC_DIR_W (1u<<13) // Direction write.
#define SPIC_EN (1u<<15) // Enable.
// REG_SPIC_CS
#define SPIC_CS_HIGH (0u)
// SPIC_FIFO_STAT
#define SPIC_FIFO_BUSY (1u)
// REG_SPIC_AUTOPOLL
// Shifts.
#define SPIC_AP_TMOUT_SHIFT (16u) // Auto poll register timeout shift.
#define SPIC_AP_OFF_SHIFT (24u) // Auto poll register bit offset shift.
#define SPIC_AP_BIT_SHIFT (30u) // Auto poll register compare bit shift.
#define SPIC_AP_START (1u<<31) // Auto poll start.
// REG_SPIC_INT_MASK Bit set = disabled.
// REG_SPIC_INT_STAT Status and acknowledge.
#define SPIC_INT_TRAN_END (1u) // Transfer end. Also fires on each auto poll try.
#define SPIC_INT_AP_MATCH (1u<<1) // Auto poll bit match.
#define SPIC_INT_AP_TMOUT (1u<<2) // Auto poll timeout.
// cmd Is the command byte to send.
// tmout Is the timeout. Must be 0-15. Tries = 31<<(SpicClk + timeout).
// off Is the bit offset in the response byte. Must be 0-7.
// cmpBit Is the bit to compare (0 or 1).
#define MAKE_AP_PARAMS(cmd, tmout, off, cmpBit) ((u32)(cmpBit)<<30 | (u32)(off)<<24 | (u32)(tmout)<<16 | (cmd))
/**
* @brief Initializes the SPI bus. Call this only once.
*/
void SPICARD_init(void);
/**
* @brief Automatically polls a bit of the command response.
*
* @param[in] clk The clock frequency to use.
* @param[in] apParams The parameters. Use the MAKE_AP_PARAMS macro.
*
* @return Returns false on timeout and true on bit match.
*/
bool SPICARD_autoPollBit(SpicClk clk, u32 apParams);
/**
* @brief Writes and/or reads data to/from a SPI device.
*
* @param[in] clk The clock frequency to use.
* @param[in] in Input data pointer for write.
* @param out Output data pointer for read.
* @param[in] inSize Input size. Must be <= 0x1FFFFF.
* @param[in] outSize Output size. Must be <= 0x1FFFFF.
*/
void SPICARD_writeRead(SpicClk clk, const u32 *in, u32 *out, u32 inSize, u32 outSize);

View File

@ -1,98 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#define TIMER_REGS_BASE (IO_MEM_ARM9_ONLY + 0x3000)
typedef struct
{
vu16 val; // 0x0
vu16 cnt; // 0x2
} Timer;
static_assert(offsetof(Timer, cnt) == 2, "Error: Member cnt of Timer is not at offset 2!");
ALWAYS_INLINE Timer* getTimerRegs(u8 timer)
{
return &((Timer*)TIMER_REGS_BASE)[timer];
}
#define TIMER_BASE_FREQ (67027964)
// REG_TIMER_CNT
#define TIMER_PRESC_1 (0u)
#define TIMER_PRESC_64 (1u)
#define TIMER_PRESC_256 (2u)
#define TIMER_PRESC_1024 (3u)
#define TIMER_COUNT_UP (1u<<2) // For cascading at least 2 timers.
#define TIMER_IRQ_EN (1u<<6)
#define TIMER_EN (1u<<7)
// Convenience macros for calculating the ticks. Based on libnds.
#define TIMER_FREQ(n) (-TIMER_BASE_FREQ / (n))
#define TIMER_FREQ_64(n) (-(TIMER_BASE_FREQ / 64) / (n))
#define TIMER_FREQ_256(n) (-(TIMER_BASE_FREQ / 256) / (n))
#define TIMER_FREQ_1024(n) (-(TIMER_BASE_FREQ / 1024) / (n))
/**
* @brief Resets/initializes the timer hardware. Should not be called manually.
*/
void TIMER_init(void);
/**
* @brief Starts a timer.
*
* @param[in] tmr The timer to start (0-3). Timer 3 is reserved.
* @param[in] ticks The initial number of ticks. This is also the reload
* value on overflow.
* @param[in] params The parameters. See REG_TIMER_CNT defines above.
*/
void TIMER_start(u8 tmr, u16 ticks, u8 params);
/**
* @brief Returns the current number of ticks of the timer.
*
* @param[in] tmr The timer get the ticks from (0-3). Timer 3 is reserved.
*
* @return The number of ticks.
*/
u16 TIMER_getTicks(u8 tmr);
/**
* @brief Stops a timer and returns the current number of ticks.
*
* @param[in] tmr The timer to stop (0-3). Timer 3 is reserved.
*
* @return The number of ticks.
*/
u16 TIMER_stop(u8 tmr);
/**
* @brief Halts the CPU for the given number of milliseconds.
*
* @param[in] ms The number of milliseconds to sleep.
*/
void TIMER_sleepMs(u32 ms);

View File

@ -1,25 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
void deinitCpu(void);

View File

@ -1,265 +0,0 @@
#pragma once
// Based on: https://github.com/ARM-software/CMSIS_5/blob/master/CMSIS/Core/Include/cmsis_gcc.h
#include "types.h"
// u32 result, u32 op1.
#define MAKE_INTR_U32_1OP(isVolatile, inst) \
ALWAYS_INLINE u32 __##inst(u32 op1) \
{ \
u32 res; \
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1" : "=r" (res) : "r" (op1) : ); \
else \
__asm__(#inst " %0, %1" : "=r" (res) : "r" (op1) : ); \
return res; \
}
// u32 result, u32 op1, u32 op2.
#define MAKE_INTR_U32_2OPS(isVolatile, inst) \
ALWAYS_INLINE u32 __##inst(u32 op1, u32 op2) \
{ \
u32 res; \
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1, %2" : "=r" (res) : "r" (op1), "r" (op2) : ); \
else \
__asm__(#inst " %0, %1, %2" : "=r" (res) : "r" (op1), "r" (op2) : ); \
return res; \
}
// s32 result, s32 op1, s32 op2.
#define MAKE_INTR_S32_2OPS(isVolatile, inst) \
ALWAYS_INLINE s32 __##inst(s32 op1, s32 op2) \
{ \
s32 res; \
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1, %2" : "=r" (res) : "r" (op1), "r" (op2) : ); \
else \
__asm__(#inst " %0, %1, %2" : "=r" (res) : "r" (op1), "r" (op2) : ); \
return res; \
}
// u32 result, u32 op1, u32 op2, u32 op3.
#define MAKE_INTR_U32_3OPS(isVolatile, inst) \
ALWAYS_INLINE u32 __##inst(u32 op1, u32 op2, u32 op3) \
{ \
u32 res; \
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1, %2, %3" : "=r" (res) : "r" (op1), "r" (op2), "r" (op3) : ); \
else \
__asm__(#inst " %0, %1, %2, %3" : "=r" (res) : "r" (op1), "r" (op2), "r" (op3) : ); \
return res; \
}
// s32 result, s32 op1, s32 op2, s32 op3.
#define MAKE_INTR_S32_3OPS(isVolatile, inst) \
ALWAYS_INLINE s32 __##inst(s32 op1, s32 op2, s32 op3) \
{ \
s32 res; \
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1, %2, %3" : "=r" (res) : "r" (op1), "r" (op2), "r" (op3) : ); \
else \
__asm__(#inst " %0, %1, %2, %3" : "=r" (res) : "r" (op1), "r" (op2), "r" (op3) : ); \
return res; \
}
#ifndef __ARMEB__ // Little endian
// Special instruction with shared u64 input and output.
// u64 result, u32 op1, u32 op2, u64 acc.
#define MAKE_INTR_U64_U32_U32_U64(isVolatile, inst) \
ALWAYS_INLINE u64 __##inst(u32 op1, u32 op2, u64 acc) \
{ \
union \
{ \
u32 r32[2]; \
u64 r64; \
} r; \
r.r64 = acc; \
\
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1, %2, %3" : "=r" (r.r32[0]), "=r" (r.r32[1]) : "r" (op1), "r" (op2), "0" (r.r32[0]), "1" (r.r32[1]) : ); \
else \
__asm__(#inst " %0, %1, %2, %3" : "=r" (r.r32[0]), "=r" (r.r32[1]) : "r" (op1), "r" (op2), "0" (r.r32[0]), "1" (r.r32[1]) : ); \
\
return r.r64; \
}
#else // Big endian
// Special instruction with shared u64 input and output.
// u64 result, u32 op1, u32 op2, u64 acc.
#define MAKE_INTR_U64_U32_U32_U64(isVolatile, inst) \
ALWAYS_INLINE u64 __##inst(u32 op1, u32 op2, u64 acc) \
{ \
union \
{ \
u32 r32[2]; \
u64 r64; \
} r; \
r.r64 = acc; \
\
if(isVolatile == 1) \
__asm__ volatile(#inst " %0, %1, %2, %3" : "=r" (r.r32[1]), "=r" (r.r32[0]) : "r" (op1), "r" (op2), "0" (r.r32[1]), "1" (r.r32[0]) : ); \
else \
__asm__(#inst " %0, %1, %2, %3" : "=r" (r.r32[1]), "=r" (r.r32[0]) : "r" (op1), "r" (op2), "0" (r.r32[1]), "1" (r.r32[0]) : ); \
\
return r.r64; \
}
#endif // #ifndef __ARMEB__
// Pack Halfword Bottom Top.
#define __pkhbt(op1, op2, sh) \
({ \
u32 __res; \
__asm__("pkhbt %0, %1, %2, lsl %3" : "=r" (__res) : "r" (op1), "r" (op2), "I" (sh) : ); \
__res; \
})
// Pack Halfword Top Bottom.
#define __pkhtb(op1, op2, sh) \
({ \
u32 __res, __sh = (sh); \
if(__sh == 0) \
__asm__("pkhtb %0, %1, %2" : "=r" (__res) : "r" (op1), "r" (op2) : ); \
else \
__asm__("pkhtb %0, %1, %2, asr %3" : "=r" (__res) : "r" (op1), "r" (op2), "I" (__sh) : ); \
__res; \
})
MAKE_INTR_S32_2OPS(1, qadd) // Signed saturating addition.
MAKE_INTR_U32_2OPS(0, qadd8) // Signed saturating parallel byte-wise addition.
MAKE_INTR_U32_2OPS(0, qadd16) // Signed saturating parallel halfword-wise addition.
MAKE_INTR_U32_2OPS(0, qasx) // Signed saturating parallel add and subtract halfwords with exchange.
MAKE_INTR_S32_2OPS(1, qdadd) // Signed saturating Double and Add.
MAKE_INTR_S32_2OPS(1, qdsub) // Signed saturating Double and Subtract.
MAKE_INTR_U32_2OPS(0, qsax) // Signed saturating parallel subtract and add halfwords with exchange.
MAKE_INTR_S32_2OPS(1, qsub) // Signed saturating Subtract.
MAKE_INTR_U32_2OPS(0, qsub8) // Signed saturating parallel byte-wise subtraction.
MAKE_INTR_U32_2OPS(0, qsub16) // Signed saturating parallel halfword-wise subtraction.
MAKE_INTR_U32_1OP(0, rev) // Reverse the byte order in a word.
MAKE_INTR_U32_1OP(0, rev16) // Reverse the byte order in each halfword independently.
MAKE_INTR_U32_1OP(0, revsh) // Reverse the byte order in the bottom halfword, and sign extend to 32 bits.
MAKE_INTR_U32_2OPS(1, sadd8) // Signed parallel byte-wise addition.
MAKE_INTR_U32_2OPS(1, sadd16) // Signed parallel halfword-wise addition.
MAKE_INTR_U32_2OPS(1, sasx) // Signed parallel add and subtract halfwords with exchange.
MAKE_INTR_U32_2OPS(1, sel) // Select bytes from each operand according to the state of the APSR GE flags.
MAKE_INTR_U32_2OPS(0, shadd8) // Signed halving parallel byte-wise addition.
MAKE_INTR_U32_2OPS(0, shadd16) // Signed halving parallel halfword-wise addition.
MAKE_INTR_U32_2OPS(0, shasx) // Signed halving parallel add and subtract halfwords with exchange.
MAKE_INTR_U32_2OPS(0, shsax) // Signed halving parallel subtract and add halfwords with exchange.
MAKE_INTR_U32_2OPS(0, shsub8) // Signed halving parallel byte-wise subtraction.
MAKE_INTR_U32_2OPS(0, shsub16) // Signed halving parallel halfword-wise subtraction.
MAKE_INTR_U32_3OPS(1, smlabb) // Signed Multiply Accumulate, with 16-bit operands (bottom, bottom) and a 32-bit result and accumulator.
MAKE_INTR_U32_3OPS(1, smlabt) // Signed Multiply Accumulate, with 16-bit operands (bottom, top) and a 32-bit result and accumulator.
MAKE_INTR_U32_3OPS(1, smlatb) // Signed Multiply Accumulate, with 16-bit operands (top, bottom) and a 32-bit result and accumulator.
MAKE_INTR_U32_3OPS(1, smlatt) // Signed Multiply Accumulate, with 16-bit operands (top, top) and a 32-bit result and accumulator.
MAKE_INTR_U32_3OPS(0, smlad) // Dual 16-bit Signed Multiply with Addition of products and 32-bit accumulation.
MAKE_INTR_U32_3OPS(0, smladx) // Dual 16-bit Signed exchange Multiply with Addition of products and 32-bit accumulation.
MAKE_INTR_U64_U32_U32_U64(0, smlal) // Signed Long Multiply, with optional Accumulate, with 32-bit operands, and 64-bit result and accumulator.
MAKE_INTR_U64_U32_U32_U64(0, smlald) // Dual 16-bit Signed Multiply with Addition of products and 64-bit Accumulation.
MAKE_INTR_U64_U32_U32_U64(0, smlaldx) // Dual 16-bit Signed exchange Multiply with Addition of products and 64-bit Accumulation.
MAKE_INTR_U64_U32_U32_U64(0, smlalbb) // Signed Multiply-Accumulate with 16-bit operands (bottom, bottom) and a 64-bit accumulator.
MAKE_INTR_U64_U32_U32_U64(0, smlalbt) // Signed Multiply-Accumulate with 16-bit operands (bottom, top) and a 64-bit accumulator.
MAKE_INTR_U64_U32_U32_U64(0, smlaltb) // Signed Multiply-Accumulate with 16-bit operands (top, bottom) and a 64-bit accumulator.
MAKE_INTR_U64_U32_U32_U64(0, smlaltt) // Signed Multiply-Accumulate with 16-bit operands (top, top) and a 64-bit accumulator.
MAKE_INTR_U32_3OPS(1, smlawb) // Signed Multiply-Accumulate Wide, with one 32-bit operand and one 16-bit operand (bottom half), and a 32-bit accumulate value, providing the top 32 bits of the result.
MAKE_INTR_U32_3OPS(1, smlawt) // Signed Multiply-Accumulate Wide, with one 32-bit operand and one 16-bit operand (top half), and a 32-bit accumulate value, providing the top 32 bits of the result.
MAKE_INTR_U32_3OPS(0, smlsd) // Dual 16-bit Signed Multiply with Subtraction of products and 32-bit accumulation.
MAKE_INTR_U32_3OPS(0, smlsdx) // Dual 16-bit Signed exchange Multiply with Subtraction of products and 32-bit accumulation.
MAKE_INTR_U64_U32_U32_U64(0, smlsld) // Dual 16-bit Signed Multiply with Subtraction of products and 64-bit Accumulation.
MAKE_INTR_U64_U32_U32_U64(0, smlsldx) // Dual 16-bit Signed exchange Multiply with Subtraction of products and 64-bit Accumulation.
MAKE_INTR_S32_3OPS(0, smmla) // Signed Most significant word Multiply with Accumulation.
MAKE_INTR_S32_3OPS(0, smmlar) // Signed Most significant word Multiply with Accumulation and rounding.
MAKE_INTR_S32_3OPS(0, smmls) // Signed Most significant word Multiply with Subtraction.
MAKE_INTR_S32_2OPS(0, smmlsr) // Signed Most significant word Multiply with Subtraction and rounding.
MAKE_INTR_S32_2OPS(0, smmul) // Signed Most significant word Multiply.
MAKE_INTR_S32_2OPS(0, smmulr) // Signed Most significant word Multiply and round.
MAKE_INTR_U32_2OPS(1, smuad) // Dual 16-bit Signed Multiply with Addition of products.
MAKE_INTR_U32_2OPS(1, smuadx) // Dual 16-bit Signed Multiply with Addition of products with exchange.
MAKE_INTR_U32_2OPS(0, smulbb) // Signed Multiply, with 16-bit operands (bottom, bottom) and a 32-bit result.
MAKE_INTR_U32_2OPS(0, smulbt) // Signed Multiply, with 16-bit operands (bottom, top) and a 32-bit result.
MAKE_INTR_U32_2OPS(0, smultb) // Signed Multiply, with 16-bit operands (top, bottom) and a 32-bit result.
MAKE_INTR_U32_2OPS(0, smultt) // Signed Multiply, with 16-bit operands (top, top) and a 32-bit result.
// TODO: smull // Signed Long Multiply, with 32-bit operands and 64-bit result.
MAKE_INTR_U32_2OPS(0, smulwb) // Signed Multiply Wide, with one 32-bit and one 16-bit operand (bottom half), providing the top 32 bits of the result.
MAKE_INTR_U32_2OPS(0, smulwt) // Signed Multiply Wide, with one 32-bit and one 16-bit operand (top half), providing the top 32 bits of the result.
/* Doesn't affect any flags? */ MAKE_INTR_U32_2OPS(0, smusd) // Dual 16-bit Signed Multiply with Subtraction of products.
/* Doesn't affect any flags? */ MAKE_INTR_U32_2OPS(0, smusdx) // Dual 16-bit Signed Multiply with Subtraction of products with exchange.
// Signed Saturate to any bit position, with optional shift before saturating.
#define __ssat(op1, op2) \
({ \
s32 __res; \
__asm__ volatile("ssat %0, %1, %2" : "=r" (__res) : "I" (op1), "r" (op2) : "cc"); \
__res; \
})
// Parallel halfword Saturate.
#define __ssat16(op1, op2) \
({ \
u32 __res; \
__asm__ volatile("ssat16 %0, %1, %2" : "=r" (__res) : "I" (op1), "r" (op2) : "cc"); \
__res; \
})
MAKE_INTR_U32_2OPS(1, ssax) // Signed parallel subtract and add halfwords with exchange.
MAKE_INTR_U32_2OPS(1, ssub8) // Signed parallel byte-wise subtraction.
MAKE_INTR_U32_2OPS(1, ssub16) // Signed parallel halfword-wise subtraction.
MAKE_INTR_U32_2OPS(0, sxtab) // Sign extend Byte with Add, to extend an 8-bit value to a 32-bit value.
MAKE_INTR_U32_2OPS(0, sxtab16) // Sign extend two Bytes with Add, to extend two 8-bit values to two 16-bit values.
MAKE_INTR_U32_2OPS(0, sxtah) // Sign extend Halfword with Add, to extend a 16-bit value to a 32-bit value.
MAKE_INTR_U32_1OP(0, sxtb) // Sign extend Byte, to extend an 8-bit value to a 32-bit value.
MAKE_INTR_U32_1OP(0, sxtb16) // Sign extend two bytes.
MAKE_INTR_U32_1OP(0, sxth) // Sign extend Halfword.
MAKE_INTR_U32_2OPS(1, uadd8) // Unsigned parallel byte-wise addition.
MAKE_INTR_U32_2OPS(1, uadd16) // Unsigned parallel halfword-wise addition.
MAKE_INTR_U32_2OPS(1, uasx) // Unsigned parallel add and subtract halfwords with exchange.
MAKE_INTR_U32_2OPS(0, uhadd8) // Unsigned halving parallel byte-wise addition.
MAKE_INTR_U32_2OPS(0, uhadd16) // Unsigned halving parallel halfword-wise addition.
MAKE_INTR_U32_2OPS(0, uhasx) // Unsigned halving parallel add and subtract halfwords with exchange.
MAKE_INTR_U32_2OPS(0, uhsax) // Unsigned halving parallel subtract and add halfwords with exchange.
MAKE_INTR_U32_2OPS(0, uhsub8) // Unsigned halving parallel byte-wise subtraction.
MAKE_INTR_U32_2OPS(0, uhsub16) // Unsigned halving parallel halfword-wise subtraction.
MAKE_INTR_U32_2OPS(0, uqadd8) // Unsigned saturating parallel byte-wise addition.
MAKE_INTR_U32_2OPS(0, uqadd16) // Unsigned saturating parallel halfword-wise addition.
MAKE_INTR_U32_2OPS(0, uqasx) // Unsigned saturating parallel add and subtract halfwords with exchange.
MAKE_INTR_U32_2OPS(0, uqsax) // Unsigned saturating parallel subtract and add halfwords with exchange.
MAKE_INTR_U32_2OPS(0, uqsub8) // Unsigned saturating parallel byte-wise subtraction.
MAKE_INTR_U32_2OPS(0, uqsub16) // Unsigned saturating parallel halfword-wise subtraction.
MAKE_INTR_U32_2OPS(0, usad8) // Unsigned Sum of Absolute Differences.
MAKE_INTR_U32_3OPS(0, usada8) // Unsigned Sum of Absolute Differences and Accumulate.
// Unsigned Saturate to any bit position, with optional shift before saturating.
#define __usat(op1, op2) \
({ \
u32 __res; \
__asm__ volatile("usat %0, %1, %2" : "=r" (__res) : "I" (op1), "r" (op2) : "cc"); \
__res; \
})
// Parallel halfword Saturate.
#define __usat16(op1, op2) \
({ \
u32 __res; \
__asm__ volatile("usat16 %0, %1, %2" : "=r" (__res) : "I" (op1), "r" (op2) : "cc"); \
__res; \
})
MAKE_INTR_U32_2OPS(1, usax) // Unsigned parallel subtract and add halfwords with exchange.
MAKE_INTR_U32_2OPS(1, usub8) // Unsigned parallel byte-wise subtraction.
MAKE_INTR_U32_2OPS(1, usub16) // Unsigned parallel halfword-wise subtraction.
//MAKE_INTR_U32_2OPS(0, uxtab) // Zero extend Byte and Add.
MAKE_INTR_U32_2OPS(0, uxtab16) // Zero extend two Bytes and Add.
//MAKE_INTR_U32_2OPS(0, uxtah) // Zero extend Halfword and Add.
//MAKE_INTR_U32_1OP(0, uxtb) // Zero extend Byte.
MAKE_INTR_U32_1OP(0, uxtb16) // Zero extend two Bytes.
//MAKE_INTR_U32_1OP(0, uxth) // Zero extend Halfword.
#undef MAKE_INTR_U32_1OP
#undef MAKE_INTR_U32_2OPS
#undef MAKE_INTR_U32_3OPS

View File

@ -1,52 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if !__ASSEMBLER__
#error Only include this in assembly files!
#endif
.macro BEGIN_ASM_FUNC name, section=text, type=arm, linkage=global
.if \section == no_section
@ Section specified elsewhere.
.else
.section .\section\().\name, "ax", %progbits
.endif
.if \type == thumb
.align 1
.thumb
.elseif \type == arm
.align 2
.arm
.else
.error "Invalid code type!"
.endif
.\linkage \name
.type \name, %function
.func \name
.cfi_sections .debug_frame
.cfi_startproc
\name:
.endm
.macro END_ASM_FUNC
.cfi_endproc
.endfunc
.endm

View File

@ -1,32 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
void invalidateICache(void);
void invalidateICacheRange(const void *base, u32 size);
void cleanDCache(void);
void flushDCache(void);
void cleanDCacheRange(const void *base, u32 size);
void flushDCacheRange(const void *base, u32 size);
void invalidateDCache(void);
void invalidateDCacheRange(const void *base, u32 size);

View File

@ -1,228 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
//#define USE_NEW_CDMA 1
#ifdef ARM11
#ifdef USE_NEW_CDMA
#define DMA330_REGS_BASE (IO_MEM_ARM11_ONLY + 0x6000)
#else
#define DMA330_REGS_BASE (IO_MEM_ARM11_ONLY + 0x0000)
#endif // ifdef USE_NEW_CDMA
#elif ARM9
#define DMA330_REGS_BASE (IO_MEM_ARM9_ONLY + 0xC000)
#endif // ifdef ARM11
typedef struct
{
const vu32 dsr; // 0x000 DMA Manager Status Register.
const vu32 dpc; // 0x004 DMA Program Counter Register (manager).
u8 _0x8[0x18];
vu32 inten; // 0x020 Interrupt Enable Register.
const vu32 int_event_ris; // 0x024 Event-Interrupt Raw Status Register.
const vu32 intmis; // 0x028 Interrupt Status Register.
vu32 intclr; // 0x02C Interrupt Clear Register (write-only).
const vu32 fsrd; // 0x030 Fault Status DMA Manager Register.
const vu32 fsrc; // 0x034 Fault Status DMA Channel Register.
const vu32 ftrd; // 0x038 Fault Type DMA Manager Register.
u8 _0x3c[4];
const vu32 ftr[8]; // 0x040 Fault Type DMA Channel Registers.
u8 _0x60[0xa0];
struct // 0x100
{
const vu32 csr; // 0x0 Channel Status Register.
const vu32 cpc; // 0x4 Channel Program Counter Register.
} chStat[8];
u8 _0x140[0x2c0];
struct // 0x400
{
const vu32 sar; // 0x00 Source Address Register.
const vu32 dar; // 0x04 Destination Address Register.
const vu32 ccr; // 0x08 Channel Control Register.
const vu32 lc0; // 0x0C Loop Counter 0 Register.
const vu32 lc1; // 0x10 Loop Counter 1 Register.
u8 chCtrl_0x14[0xc];
} chCtrl[8];
u8 _0x500[0x800];
const vu32 dbgstatus; // 0xD00 Debug Status Register.
vu32 dbgcmd; // 0xD04 Debug Command Register (write-only).
vu32 dbginst0; // 0xD08 Debug Instruction-0 Register (write-only).
vu32 dbginst1; // 0xD0C Debug Instruction-1 Register (write-only).
u8 _0xd10[0xf0];
const vu32 cr0; // 0xE00 Configuration Register 0.
const vu32 cr1; // 0xE04 Configuration Register 1.
const vu32 cr2; // 0xE08 Configuration Register 2.
const vu32 cr3; // 0xE0C Configuration Register 3.
const vu32 cr4; // 0xE10 Configuration Register 4.
const vu32 crd; // 0xE14 DMA Configuration Register.
u8 _0xe18[0x68];
vu32 wd; // 0xE80 Watchdog Register (r1p0 only).
u8 _0xe84[0x15c];
const vu32 periph_id_0; // Peripheral Identification Register 0.
const vu32 periph_id_1; // Peripheral Identification Register 1.
const vu32 periph_id_2; // Peripheral Identification Register 2.
const vu32 periph_id_3; // Peripheral Identification Register 3.
const vu32 pcell_id_0; // Component Identification Register 0.
const vu32 pcell_id_1; // Component Identification Register 1.
const vu32 pcell_id_2; // Component Identification Register 2.
const vu32 pcell_id_3; // Component Identification Register 3.
} Dma330;
static_assert(offsetof(Dma330, pcell_id_3) == 0xFFC, "Error: Member pcell_id_3 of Dma330 is not at offset 0xFFC!");
ALWAYS_INLINE Dma330* getDma330Regs(void)
{
return (Dma330*)DMA330_REGS_BASE;
}
// REG_DMA330_DSR
#define DSR_WAKE_EVNT_SHIFT (4u)
#define DSR_WAKE_EVNT_MASK (0x1Fu<<DSR_WAKEUP_EVNT_SHIFT)
#define DSR_DNS (1u<<9) // DMA Manager is non-secure.
enum
{
DSR_STAT_STOPPED = 0u,
DSR_STAT_EXECUTING = 1u,
DSR_STAT_CACHE_MISS = 2u,
DSR_STAT_UPDATING_PC = 3u, // Updating program counter.
DSR_STAT_WFE = 4u, // Waiting for event.
DSR_STAT_FAULTING = 15u,
DSR_STAT_MASK = DSR_STAT_FAULTING
};
// REG_DMA330_INTEN
#define INTEN_SEL_IRQ(n) (1u<<(n)) // Select IRQ instead of event.
// REG_DMA330_INT_EVENT_RIS
#define INT_EVENT_RIS_ACTIVE(n) (1u<<(n)) // Interrupt or event N is active.
// REG_DMA330_INTMIS
#define INTMIS_IRQ_ACTIVE(n) (1u<<(n)) // Interrupt N is active.
// REG_DMA330_INTCLR
#define INTCLR_IRQ_CLR(n) (1u<<(n)) // Clear interrupt N.
// REG_DMA330_FSRD
#define FSRD_FAULTING (1u) // DMA manager is in faulting state.
// REG_DMA330_FSRC
#define FSRC_FAULTING(n) (1u<<(n)) // DMA channel is in faulting or faulting completing state.
// REG_DMA330_FTRD
#define FTRD_UNDEF_INSTR (1u)
#define FTRD_OPERAND_INVALID (1u<<1)
#define FTRD_DMAGO_ERR (1u<<4) // Starting a secure channel from a non-secure state.
#define FTRD_MGR_EVNT_ERR (1u<<5) // Waiting for or creating secure events/interrupts in no-secure state.
#define FTRD_INSTR_FETCH_ERR (1u<<16)
#define FTRD_DBG_INSTR (1u<<30) // The erroneous instruction came from the debug interface.
// REG_DMA330_FTR0-7
#define FTR_UNDEF_INSTR (1u)
#define FTR_OPERAND_INVALID (1u<<1)
#define FTR_CH_EVNT_ERR (1u<<5) // Waiting for or creating secure events/interrupts in no-secure state.
#define FTR_CH_PERIPH_ERR (1u<<6) // Accessing secure periphals in non-secure state (DMAWFP, DMALDP, DMASTP, DMAFLUSHP).
#define FTR_CH_RDWR_ERR (1u<<7) // Secure read or write in non-secure state.
#define FTR_CH_MFIFO_ERR (1u<<12) // MFIFO too small to hold or store the data (DMALD, DMAST).
#define FTR_CH_ST_DATA_UNAVAIL (1u<<13) // Not enough data in the MFIFO for DMAST to complete.
#define FTR_INSTR_FETCH_ERR (1u<<16)
#define FTR_DATA_WRITE_ERR (1u<<17)
#define FTR_DATA_READ_ERR (1u<<18)
#define FTR_DBG_INSTR (1u<<30) // The erroneous instruction came from the debug interface.
#define FTR_LOCKUP_ERR (1u<<31) // Channel locked up because of resource starvation.
// REG_DMA330_CSR0-7
#define CSR_WAKE_EVNT_SHIFT (4u)
#define CSR_WAKE_EVNT_MASK (0x1Fu<<CSR_WAKEUP_EVNT_SHIFT)
#define CSR_DMAWFP_B_NS (1u<<14) // DMAWFP executed with burst operand set.
#define CSR_DMAWFP_PERIPH (1u<<15) // DMAWFP executed with periph operand set.
#define CSR_CNS (1u<<21) // DMA channel is non-secure.
enum
{
CSR_STAT_STOPPED = 0u,
CSR_STAT_EXECUTING = 1u,
CSR_STAT_CACHE_MISS = 2u,
CSR_STAT_UPDATING_PC = 3u, // Updating program counter.
CSR_STAT_WFE = 4u, // Waiting for event.
CSR_STAT_AT_BARRIER = 5u,
CSR_STAT_WFP = 7u, // Waiting for periphal.
CSR_STAT_KILLING = 8u,
CSR_STAT_COMPLETING = 9u,
CSR_STAT_FAULTING_COMPLETING = 14u,
CSR_STAT_FAULTING = 15u,
CSR_STAT_MASK = CSR_STAT_FAULTING
};
// REG_DMA330_CCR0-7
#define CCR_SRC_INC (1u)
#define CCR_SRC_BURST_SIZE_SHIFT (1u)
#define CCR_SRC_BURST_SIZE_MASK (0x7u<<CCR_SRC_BURST_SIZE_SHIFT)
#define CCR_SRC_BURST_LEN_SHIFT (4u)
#define CCR_SRC_BURST_LEN_MASK (0xFu<<CCR_SRC_BURST_LEN_SHIFT)
#define CCR_SRC_PROT_CTRL_SHIFT (8u)
#define CCR_SRC_PROT_CTRL_MASK (0x7u<<CCR_SRC_PROT_CTRL_SHIFT)
#define CCR_SRC_CACHE_CTRL_SHIFT (11u)
#define CCR_SRC_CACHE_CTRL_MASK (0x7u<<CCR_SRC_CACHE_CTRL_SHIFT)
#define CCR_DST_INC (1u<<14)
#define CCR_DST_BURST_SIZE_SHIFT (15u)
#define CCR_DST_BURST_SIZE_MASK (0x7u<<CCR_DST_BURST_SIZE_SHIFT)
#define CCR_DST_BURST_LEN_SHIFT (18u)
#define CCR_DST_BURST_LEN_MASK (0xFu<<CCR_DST_BURST_LEN_SHIFT)
#define CCR_DST_PROT_CTRL_SHIFT (22u)
#define CCR_DST_PROT_CTRL_MASK (0x7u<<CCR_DST_PROT_CTRL_SHIFT)
#define CCR_DST_CACHE_CTRL_SHIFT (25u)
#define CCR_DST_CACHE_CTRL_MASK (0x7u<<CCR_DST_CACHE_CTRL_SHIFT)
#define CCR_END_SWP_SIZE_SHIFT (28u) // Endian swap size.
#define CCR_END_SWP_SIZE_MASK (0x7u<<CCR_END_SWP_SIZE_SHIFT)
// REG_DMA330_DBGSTATUS
#define DBGSTATUS_BUSY (1u)
// REG_DMA330_DBGCMD
#define DBGCMD_EXECUTE (0u)
// REG_DMA330_DBGINST0
#define DBGINST0_THR_MGR (0u) // Select DMA manager thread.
#define DBGINST0_THR_CH (1u) // Select DMA channel thread (also needs a channel number).
#define DBGINST0(b10, ch, t) ((b10)<<16 | (ch)<<8 | (t)) // b10 = byte 1 and 0, ch = channel num, t = thread.
// DBGINST1 stores the remaining 4 instruction bytes.
void DMA330_init(void);
u8 DMA330_run(u8 ch, const u8 *const prog);
u8 DMA330_status(u8 ch);
void DMA330_ackIrq(u8 eventIrq);
void DMA330_sev(u8 event);
void DMA330_kill(u8 ch);
#ifdef ARM11
//void DMA330_dbgPrint(void);
#endif // ifdef ARM11

View File

@ -1,126 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mem_map.h"
#include "types.h"
#define SCREEN_TOP (0u)
#define SCREEN_BOT (1u)
#define SCREEN_WIDTH_TOP (400u)
#define SCREEN_HEIGHT_TOP (240u)
#define SCREEN_SIZE_TOP (SCREEN_WIDTH_TOP * SCREEN_HEIGHT_TOP * 2)
#define SCREEN_WIDTH_BOT (320u)
#define SCREEN_HEIGHT_BOT (240u)
#define SCREEN_SIZE_BOT (SCREEN_WIDTH_BOT * SCREEN_HEIGHT_BOT * 2)
// TODO:
// Because we are using a VRAM allocator this may break any time.
#define FRAMEBUF_TOP_A_1 ((void*)VRAM_BASE)
#define FRAMEBUF_BOT_A_1 (FRAMEBUF_TOP_A_1 + SCREEN_SIZE_TOP)
#define FRAMEBUF_TOP_A_2 (FRAMEBUF_BOT_A_1 + SCREEN_SIZE_BOT + SCREEN_SIZE_TOP) // Skip B1
#define FRAMEBUF_BOT_A_2 (FRAMEBUF_TOP_A_2 + SCREEN_SIZE_TOP)
#define DEFAULT_BRIGHTNESS (0x30)
/// Converts packed RGB8 to packed RGB565.
#define RGB8_to_565(r,g,b) (((((r)>>3) & 0x1f)<<11) | ((((g)>>2) & 0x3f)<<5) | (((b)>>3) & 0x1f))
/// Framebuffer format.
typedef enum
{
GFX_RGBA8 = 0, ///< RGBA8. (4 bytes)
GFX_BGR8 = 1, ///< BGR8. (3 bytes)
GFX_RGB565 = 2, ///< RGB565. (2 bytes)
GFX_RGB5A1 = 3, ///< RGB5A1. (2 bytes)
GFX_RGBA4 = 4 ///< RGBA4. (2 bytes)
} GfxFbFmt;
#ifdef ARM11
typedef enum
{
GFX_EVENT_PSC0 = 0u,
GFX_EVENT_PSC1 = 1u,
GFX_EVENT_PDC0 = 2u,
GFX_EVENT_PDC1 = 3u,
GFX_EVENT_PPF = 4u,
GFX_EVENT_P3D = 5u
} GfxEvent;
typedef enum
{
GFX_BLIGHT_BOT = 1u<<2,
GFX_BLIGHT_TOP = 1u<<4,
GFX_BLIGHT_BOTH = GFX_BLIGHT_TOP | GFX_BLIGHT_BOT
} GfxBlight;
void GFX_init(GfxFbFmt fmtTop, GfxFbFmt fmtBot);
static inline void GFX_initDefault(void)
{
GFX_init(GFX_BGR8, GFX_BGR8);
}
void GFX_deinit(void);
void GFX_setFramebufFmt(GfxFbFmt fmtTop, GfxFbFmt fmtBot);
void GFX_powerOnBacklights(GfxBlight mask);
void GFX_powerOffBacklights(GfxBlight mask);
void GFX_setBrightness(u8 top, u8 bot);
void GFX_setForceBlack(bool top, bool bot);
void GFX_setDoubleBuffering(u8 screen, bool dBuf);
void* GFX_getFramebuffer(u8 screen);
void GFX_swapFramebufs(void);
void GFX_waitForEvent(GfxEvent event, bool discard);
// Helpers
#define GFX_waitForPSC0() GFX_waitForEvent(GFX_EVENT_PSC0, false)
#define GFX_waitForPSC1() GFX_waitForEvent(GFX_EVENT_PSC1, false)
#define GFX_waitForVBlank0() GFX_waitForEvent(GFX_EVENT_PDC0, true)
//#define GFX_waitForVBlank1() GFX_waitForEvent(GFX_EVENT_PDC1, true) // Disabled
#define GFX_waitForPPF() GFX_waitForEvent(GFX_EVENT_PPF, false)
#define GFX_waitForP3D() GFX_waitForEvent(GFX_EVENT_P3D, false)
void GX_memoryFill(u32 *buf0a, u32 buf0v, u32 buf0Sz, u32 val0, u32 *buf1a, u32 buf1v, u32 buf1Sz, u32 val1);
void GX_displayTransfer(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 flags);
void GX_textureCopy(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 size);
void GX_processCommandList(u32 size, const u32 *const cmdList);
//void GFX_enterLowPowerState(void);
//void GFX_returnFromLowPowerState(void);
#endif

View File

@ -1,132 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "error_codes.h"
#define MAX_ROM_SIZE (1024u * 1024 * 32)
#define MAX_SAVE_SIZE (1024u * 128)
#define ARM7_STUB_LOC (0x3007E00u)
#define ARM7_STUB_LOC9 (0x80BFE00u)
#define ROM_LOC (0x20000000u)
#define SAVE_LOC (0x8080000u)
// REG_LGY_MODE
#define LGY_MODE_TWL (1u)
#define LGY_MODE_AGB (2u)
#define LGY_MODE_START (1u<<15)
// REG_LGY_GBA_SAVE_TYPE
enum
{
SAVE_TYPE_EEPROM_8k = 0x0u, // "[save] in upper 16Mbyte of ROM area"
SAVE_TYPE_EEPROM_8k_2 = 0x1u, // "[save] in upper 100h byte of ROM area"
SAVE_TYPE_EEPROM_64k = 0x2u, // "[save] in upper 16Mbyte of ROM area"
SAVE_TYPE_EEPROM_64k_2 = 0x3u, // "[save] in upper 100h byte of ROM area"
SAVE_TYPE_FLASH_512k_AML_RTC = 0x4u, // "FLASH ID=3D1Fh, Atmel"
SAVE_TYPE_FLASH_512k_AML = 0x5u, // "FLASH ID=3D1Fh, Atmel"
SAVE_TYPE_FLASH_512k_SST_RTC = 0x6u, // "FLASH ID=D4BFh, SST"
SAVE_TYPE_FLASH_512k_SST = 0x7u, // "FLASH ID=D4BFh, SST"
SAVE_TYPE_FLASH_512k_PSC_RTC = 0x8u, // "FLASH ID=1B32h, Panasonic"
SAVE_TYPE_FLASH_512k_PSC = 0x9u, // "FLASH ID=1B32h, Panasonic"
SAVE_TYPE_FLASH_1m_MRX_RTC = 0xAu, // "FLASH ID=09C2h, Macronix"
SAVE_TYPE_FLASH_1m_MRX = 0xBu, // "FLASH ID=09C2h, Macronix"
SAVE_TYPE_FLASH_1m_SNO_RTC = 0xCu, // "FLASH ID=1362h, Sanyo"
SAVE_TYPE_FLASH_1m_SNO = 0xDu, // "FLASH ID=1362h, Sanyo"
SAVE_TYPE_SRAM_256k = 0xEu,
SAVE_TYPE_NONE = 0xFu,
SAVE_TYPE_MASK = SAVE_TYPE_NONE
};
// REG_LGY_GBA_SAVE_MAP
#define LGY_SAVE_MAP_7 (0u)
#define LGY_SAVE_MAP_9 (1u)
// REG_LGY_GBA_RTC_CNT
#define LGY_RTC_CNT_WR (1u) // Write date and time.
#define LGY_RTC_CNT_RD (1u<<1) // Read date and time.
#define LGY_RTC_CNT_WR_ERR (1u<<14) // Write error (wrong date/time).
#define LGY_RTC_CNT_BUSY (1u<<15)
// REG_LGY_GBA_RTC_BCD_DATE
// Shifts
#define LGY_RTC_BCD_Y_SHIFT (0u)
#define LGY_RTC_BCD_MON_SHIFT (8u)
#define LGY_RTC_BCD_D_SHIFT (16u)
#define LGY_RTC_BCD_W_SHIFT (24u)
// Masks
#define LGY_RTC_BCD_Y_MASK (0xFFu<<LGY_RTC_BCD_Y_SHIFT)
#define LGY_RTC_BCD_MON_MASK (0x1Fu<<LGY_RTC_BCD_M_SHIFT)
#define LGY_RTC_BCD_D_MASK (0x3Fu<<LGY_RTC_BCD_D_SHIFT)
#define LGY_RTC_BCD_W_MASK (0x07u<<LGY_RTC_BCD_W_SHIFT)
// REG_LGY_GBA_RTC_BCD_TIME
// Shifts
#define LGY_RTC_BCD_H_SHIFT (0u)
#define LGY_RTC_BCD_MIN_SHIFT (8u)
#define LGY_RTC_BCD_S_SHIFT (16u)
// Masks
#define LGY_RTC_BCD_H_MASK (0x3Fu<<LGY_RTC_BCD_H_SHIFT)
#define LGY_RTC_BCD_MIN_MASK (0x7Fu<<LGY_RTC_BCD_MIN_SHIFT)
#define LGY_RTC_BCD_S_MASK (0x7Fu<<LGY_RTC_BCD_S_SHIFT)
// All values in BCD.
typedef struct
{
union
{
struct
{
u8 h;
u8 min;
u8 s;
u8 unused;
};
u32 time;
};
union
{
struct
{
u8 y;
u8 mon;
u8 d;
u8 dow; // Day of week.
};
u32 date;
};
} ALIGN(8) GbaRtc; // Workaround: Poor optimization on pass by value.
// REGs_LGY_GBA_SAVE_TIMING
Result LGY_prepareGbaMode(bool directBoot, u16 saveType, const char *const savePath);
Result LGY_setGbaRtc(const GbaRtc rtc);
Result LGY_getGbaRtc(GbaRtc *const out);
Result LGY_backupGbaSave(void);
#ifdef ARM11
void LGY_switchMode(void);
void LGY_handleOverrides(void);
void LGY_deinit(void);
#endif

View File

@ -1,252 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Based on JEDEC eMMC Card Product Standard V4.41.
#include "drivers/toshsd.h"
// Controller specific macros. Add controller specific bits here.
// MMC_CMD_[response type]_[transfer type]
// Transfer type: R = read, W = write.
#define MMC_CMD_NONE(id) (CMD_RESP_NONE | (id))
#define MMC_CMD_R1(id) (CMD_RESP_R1 | (id))
#define MMC_CMD_R1b(id) (CMD_RESP_R1b | (id))
#define MMC_CMD_R2(id) (CMD_RESP_R2 | (id))
#define MMC_CMD_R3(id) (CMD_RESP_R3 | (id))
#define MMC_CMD_R4(id) (CMD_RESP_R4 | (id))
#define MMC_CMD_R5(id) (CMD_RESP_R5 | (id))
#define MMC_CMD_R1_R(id) (CMD_DIR_R | CMD_DT_EN | CMD_RESP_R1 | (id))
#define MMC_CMD_R1_W(id) (CMD_DIR_W | CMD_DT_EN | CMD_RESP_R1 | (id))
// Basic commands and read-stream command (class 0 and class 1).
#define MMC_GO_IDLE_STATE MMC_CMD_NONE(0u) // -, [31:0] 0x00000000 GO_IDLE_STATE, 0xF0F0F0F0 GO_PRE_IDLE_STATE, 0xFFFFFFFA BOOT_INITIATION.
#define MMC_SEND_OP_COND MMC_CMD_R3(1u) // R3, [31:0] OCR with-out busy.
#define MMC_ALL_SEND_CID MMC_CMD_R2(2u) // R2, [31:0] stuff bits.
#define MMC_SET_RELATIVE_ADDR MMC_CMD_R1(3u) // R1, [31:16] RCA [15:0] stuff bits.
#define MMC_SET_DSR MMC_CMD_NONE(4u) // -, [31:16] DSR [15:0] stuff bits.
#define MMC_SLEEP_AWAKE MMC_CMD_R1b(5u) // R1b, [31:16] RCA [15] Sleep/Awake [14:0] stuff bits.
#define MMC_SWITCH MMC_CMD_R1b(6u) // R1b, [31:26] Set to 0 [25:24] Access [23:16] Index [15:8] Value [7:3] Set to 0 [2:0] Cmd Set.
#define MMC_SELECT_CARD MMC_CMD_R1(7u) // R1, [31:16] RCA [15:0] stuff bits.
#define MMC_DESELECT_CARD MMC_CMD_NONE(7u) // -, [31:16] RCA [15:0] stuff bits.
#define MMC_SELECT_CARD_R1b MMC_CMD_R1b(7u) // R1b, [31:16] RCA [15:0] stuff bits.
#define MMC_SEND_EXT_CSD MMC_CMD_R1_R(8u) // R1, [31:0] stuff bits.
#define MMC_SEND_CSD MMC_CMD_R2(9u) // R2, [31:16] RCA [15:0] stuff bits.
#define MMC_SEND_CID MMC_CMD_R2(10u) // R2, [31:16] RCA [15:0] stuff bits.
#define MMC_READ_DAT_UNTIL_STOP MMC_CMD_R1_R(11u) // R1, [31:0] data address.
#define MMC_STOP_TRANSMISSION_R MMC_CMD_R1(12u) // R1, [31:16] RCA [15:1] stuff bits [0] HPI.
#define MMC_STOP_TRANSMISSION_W MMC_CMD_R1b(12u) // R1b, [31:16] RCA [15:1] stuff bits [0] HPI.
#define MMC_SEND_STATUS MMC_CMD_R1(13u) // R1, [31:16] RCA [15:1] stuff bits [0] HPI.
#define MMC_BUSTEST_R MMC_CMD_R1_R(14u) // R1, [31:0] stuff bits.
#define MMC_GO_INACTIVE_STATE MMC_CMD_NONE(15u) // -, [31:16] RCA [15:0] stuff bits.
#define MMC_BUSTEST_W MMC_CMD_R1_W(19u) // R1, [31:0] stuff bits.
// Block-oriented read commands (class 2).
#define MMC_SET_BLOCKLEN MMC_CMD_R1(16u) // R1, [31:0] block length.
#define MMC_READ_SINGLE_BLOCK MMC_CMD_R1_R(17u) // R1, [31:0] data address.
#define MMC_READ_MULTIPLE_BLOCK MMC_CMD_R1_R(18u) // R1, [31:0] data address.
// Stream write commands (class 3).
#define MMC_WRITE_DAT_UNTIL_STOP MMC_CMD_R1_W(20u) // R1, [31:0] data address.
// Block-oriented write commands (class 4).
#define MMC_SET_BLOCK_COUNT MMC_CMD_R1(23u) // R1, [31] Reliable Write Request [30:16] set to 0 [15:0] number of blocks.
#define MMC_WRITE_BLOCK MMC_CMD_R1_W(24u) // R1, [31:0] data address.
#define MMC_WRITE_MULTIPLE_BLOCK MMC_CMD_R1_W(25u) // R1, [31:0] data address.
#define MMC_PROGRAM_CID MMC_CMD_R1_W(26u) // R1, [31:0] stuff bits.
#define MMC_PROGRAM_CSD MMC_CMD_R1_W(27u) // R1, [31:0] stuff bits.
// Block-oriented write protection commands (class 6).
#define MMC_SET_WRITE_PROT MMC_CMD_R1b(28u) // R1b, [31:0] data address.
#define MMC_CLR_WRITE_PROT MMC_CMD_R1b(29u) // R1b, [31:0] data address.
#define MMC_SEND_WRITE_PROT MMC_CMD_R1_R(30u) // R1, [31:0] write protect data address.
#define MMC_SEND_WRITE_PROT_TYPE MMC_CMD_R1_R(31u) // R1, [31:0] write protect data address.
// Erase commands (class 5).
#define MMC_ERASE_GROUP_START MMC_CMD_R1(35u) // R1, [31:0] data address.
#define MMC_ERASE_GROUP_END MMC_CMD_R1(36u) // R1, [31:0] data address.
#define MMC_ERASE MMC_CMD_R1b(38u) // R1b, [31] Secure request [30:16] set to 0 [15] Force Garbage Collect request [14:1] set to 0 [0] Identify Write block for Erase.
// I/O mode commands (class 9).
#define MMC_FAST_IO MMC_CMD_R4(39u) // R4, [31:16] RCA [15:15] register write flag [14:8] register address [7:0] register data.
#define MMC_GO_IRQ_STATE MMC_CMD_R5(40u) // R5, [31:0] stuff bits.
// Lock card commands (class 7).
#define MMC_LOCK_UNLOCK MMC_CMD_R1_W(42u) // R1, [31:0] stuff bits.
// Application-specific commands (class 8).
#define MMC_APP_CMD MMC_CMD_R1(55u) // R1, [31:16] RCA [15:0] stuff bits.
#define MMC_GEN_CMD_R MMC_CMD_R1_R(56u) // R1, [31:1] stuff bits [0] RD/WR = 1.
#define MMC_GEN_CMD_W MMC_CMD_R1_W(56u) // R1, [31:1] stuff bits [0] RD/WR = 0.
// 7.13 Card status.
// Type:
// E: Error bit.
// S: Status bit.
// R: Detected and set for the actual command response.
// X: Detected and set during command execution. The host can get the status by issuing a command with R1 response.
//
// Clear Condition:
// A: These bits are persistent, they are set and cleared in accordance with the card status.
// B: These bits are cleared as soon as the response (reporting the error) is sent out.
#define MMC_R1_APP_CMD (1u<<5) // S R A, The card will expect ACMD, or indication that the command has been interpreted as ACMD.
#define MMC_R1_URGENT_BKOPS (1u<<6) // S R A, If set, device needs to perform backgroundoperations urgently. Host can check EXT_CSD field BKOPS_STATUS for the detailed level.
#define MMC_R1_SWITCH_ERROR (1u<<7) // E X B, If set, the card did not switch to the expected mode as requested by the SWITCH command.
#define MMC_R1_READY_FOR_DATA (1u<<8) // S R A, Corresponds to buffer empty signalling on the bus.
#define MMC_R1_STATE_IDLE (0u<<9) // S R A
#define MMC_R1_STATE_READY (1u<<9) // S R A
#define MMC_R1_STATE_IDENT (2u<<9) // S R A
#define MMC_R1_STATE_STBY (3u<<9) // S R A
#define MMC_R1_STATE_TRAN (4u<<9) // S R A
#define MMC_R1_STATE_DATA (5u<<9) // S R A
#define MMC_R1_STATE_RCV (6u<<9) // S R A
#define MMC_R1_STATE_PRG (7u<<9) // S R A
#define MMC_R1_STATE_DIS (8u<<9) // S R A
#define MMC_R1_STATE_BTST (9u<<9) // S R A
#define MMC_R1_STATE_SLP (10u<<9) // S R A
#define MMC_R1_ERASE_RESET (1u<<13) // E R B, An erase sequence was cleared before executing because an out of erase sequence command was received (commands other than CMD35, CMD36, CMD38 or CMD13.
#define MMC_R1_WP_ERASE_SKIP (1u<<15) // E X B, Only partial address space was erased due to existing write protected blocks.
#define MMC_R1_CXD_OVERWRITE (1u<<16) // E X B, Can be either one of the following errors: - The CID register has been already written and can not be overwritten - The read only section of the CSD does not match the card content. - An attempt to reverse the copy (set as original) or permanent WP (unprotected) bits was made.
#define MMC_R1_OVERRUN (1u<<17) // E X B, The card could not sustain data programming in stream write mode.
#define MMC_R1_UNDERRUN (1u<<18) // E X B, The card could not sustain data transfer in stream read mode.
#define MMC_R1_ERROR (1u<<19) // E X B, (Undefined by the standard) A generic card error related to the (and detected during) execution of the last host command (e.g. read or write failures).
#define MMC_R1_CC_ERROR (1u<<20) // E R B, (Undefined by the standard) A card error occurred, which is not related to the host command.
#define MMC_R1_CARD_ECC_FAILED (1u<<21) // E X B, Card internal ECC was applied but failed to correct the data.
#define MMC_R1_ILLEGAL_COMMAND (1u<<22) // E R B, Command not legal for the card state.
#define MMC_R1_COM_CRC_ERROR (1u<<23) // E R B, The CRC check of the previous command failed.
#define MMC_R1_LOCK_UNLOCK_FAILED (1u<<24) // E X B, Set when a sequence or password error has been detected in lock/unlock card command.
#define MMC_R1_CARD_IS_LOCKED (1u<<25) // S R A, When set, signals that the card is locked by the host.
#define MMC_R1_WP_VIOLATION (1u<<26) // E X B, Attempt to program a write protected block.
#define MMC_R1_ERASE_PARAM (1u<<27) // E X B, An invalid selection of erase groups for erase occurred.
#define MMC_R1_ERASE_SEQ_ERROR (1u<<28) // E R B, An error in the sequence of erase commands occurred.
#define MMC_R1_BLOCK_LEN_ERROR (1u<<29) // E R B, Either the argument of a SET_BLOCKLEN command exceeds the maximum value allowed for the card, or the previously defined block length is illegal for the current command (e.g. the host issues a write command, the current block length is smaller than the cards maximum and write partial blocks is not allowed).
#define MMC_R1_ADDRESS_MISALIGN (1u<<30) // E R/X B, The command s address argument (in accordance with the currently set block length) positions the first data block misaligned to the card physical blocks. A multiple block read/write operation (although started with a valid address/blocklength combination) is attempting to read or write a data block which does not align with the physical blocks of the card.
#define MMC_R1_ADDRESS_OUT_OF_RANGE (1u<<31) // E R/X B, The commands address argument was out of the allowed range for this card. A multiple block or stream read/write operation is (although started in a valid address) attempting to read or write beyond the card capacity.
#define MMC_R1_ERR_ALL (MMC_R1_ADDRESS_OUT_OF_RANGE | MMC_R1_ADDRESS_MISALIGN | \
MMC_R1_BLOCK_LEN_ERROR | MMC_R1_ERASE_SEQ_ERROR | \
MMC_R1_ERASE_PARAM | MMC_R1_WP_VIOLATION | MMC_R1_LOCK_UNLOCK_FAILED | \
MMC_R1_COM_CRC_ERROR | MMC_R1_ILLEGAL_COMMAND | MMC_R1_CARD_ECC_FAILED | \
MMC_R1_CC_ERROR | MMC_R1_ERROR | MMC_R1_UNDERRUN | MMC_R1_OVERRUN | \
MMC_R1_CXD_OVERWRITE | MMC_R1_WP_ERASE_SKIP | MMC_R1_ERASE_RESET | \
MMC_R1_SWITCH_ERROR)
// 8.1 OCR register.
// Same bits for CMD1 argument.
#define MMC_OCR_1_7_1_95V (1u<<7) // 1.701.95V.
#define MMC_OCR_2_0_2_1V (1u<<8) // 2.0-2.1V.
#define MMC_OCR_2_1_2_2V (1u<<9) // 2.1-2.2V.
#define MMC_OCR_2_2_2_3V (1u<<10) // 2.2-2.3V.
#define MMC_OCR_2_3_2_4V (1u<<11) // 2.3-2.4V.
#define MMC_OCR_2_4_2_5V (1u<<12) // 2.4-2.5V.
#define MMC_OCR_2_5_2_6V (1u<<13) // 2.5-2.6V.
#define MMC_OCR_2_6_2_7V (1u<<14) // 2.6-2.7V.
#define MMC_OCR_2_7_2_8V (1u<<15) // 2.7-2.8V.
#define MMC_OCR_2_8_2_9V (1u<<16) // 2.8-2.9V.
#define MMC_OCR_2_9_3_0V (1u<<17) // 2.9-3.0V.
#define MMC_OCR_3_0_3_1V (1u<<18) // 3.0-3.1V.
#define MMC_OCR_3_1_3_2V (1u<<19) // 3.1-3.2V.
#define MMC_OCR_3_2_3_3V (1u<<20) // 3.2-3.3V.
#define MMC_OCR_3_3_3_4V (1u<<21) // 3.3-3.4V.
#define MMC_OCR_3_4_3_5V (1u<<22) // 3.4-3.5V.
#define MMC_OCR_3_5_3_6V (1u<<23) // 3.5-3.6V.
#define MMC_OCR_BYTE_MODE (0u<<29) // Access mode = byte mode.
#define MMC_OCR_SECT_MODE (2u<<29) // Access mode = sector mode.
#define MMC_OCR_READY (1u<<31) // Card power up status bit (busy). 0 = busy.
// 7.6.1 Command sets and extended settings.
#define MMC_SWITCH_ACC_CMD_SET (0u)
#define MMC_SWITCH_ACC_SET_BITS (1u)
#define MMC_SWITCH_ACC_CLR_BITS (2u)
#define MMC_SWITCH_ACC_WR_BYTE (3u)
#define MMC_SWITCH_ARG(acc, idx, val, cmdSet) (((acc)&3u)<<24 | ((idx)&0xFFu)<<16 | ((val)&0xFFu)<<8 | ((cmdSet)&7u))
// 8.4 Extended CSD register.
// size in bytes, access, description.
#define EXT_CSD_SEC_BAD_BLK_MGMNT (134u) // 1, R/W, Bad Block Management mode.
#define EXT_CSD_ENH_START_ADDR (136u) // 4, R/W, Enhanced User Data Start Address.
#define EXT_CSD_ENH_SIZE_MULT (140u) // 3, R/W, Enhanced User Data Area Size.
#define EXT_CSD_GP_SIZE_MULT (143u) // 12, R/W, General Purpose Partition Size.
#define EXT_CSD_PARTITION_SETTING_COMPLETED (155u) // 1, R/W, Paritioning Setting.
#define EXT_CSD_PARTITIONS_ATTRIBUTE (156u) // 1, R/W, Partitions attribute.
#define EXT_CSD_MAX_ENH_SIZE_MULT (157u) // 3, R, Max Enhanced Area Size.
#define EXT_CSD_PARTITIONING_SUPPORT (160u) // 1, R, Partitioning Support.
#define EXT_CSD_HPI_MGMT (161u) // 1, R/W/E_P, HPI management.
#define EXT_CSD_RST_n_FUNCTION (162u) // 1, R/W, H/W reset function.
#define EXT_CSD_BKOPS_EN (163u) // 1, R/W, Enable background operations handshake.
#define EXT_CSD_BKOPS_START (164u) // 1, W/E_P, Manually start background operations.
#define EXT_CSD_WR_REL_PARAM (166u) // 1, R, Write reliability parameter register.
#define EXT_CSD_WR_REL_SET (167u) // 1, R/W, Write reliability setting register.
#define EXT_CSD_RPMB_SIZE_MULT (168u) // 1, R, RPMB Size.
#define EXT_CSD_FW_CONFIG (169u) // 1, R/W, FW configuration.
#define EXT_CSD_USER_WP (171u) // 1, R/W, R/W/C_P & R/W/E_P, User area write protection register.
#define EXT_CSD_BOOT_WP (173u) // 1, R/W & R/W/C_P, Boot area write protection register.
#define EXT_CSD_ERASE_GROUP_DEF (175u) // 1, R/W/E_P, High-density erase group definition.
#define EXT_CSD_BOOT_BUS_WIDTH (177u) // 1, R/W/E, Boot bus width1.
#define EXT_CSD_BOOT_CONFIG_PROT (178u) // 1, R/W & R/W/C_P, Boot config protection.
#define EXT_CSD_PARTITION_CONFIG (179u) // 1, R/W/E & R/W/E_P, Partition configuration.
#define EXT_CSD_ERASED_MEM_CONT (181u) // 1, R, Erased memory content.
#define EXT_CSD_BUS_WIDTH (183u) // 1, W/E_P, Bus width mode.
#define EXT_CSD_HS_TIMING (185u) // 1, R/W/E_P, High-speed interface timing.
#define EXT_CSD_POWER_CLASS (187u) // 1, R/W/E_P, Power class.
#define EXT_CSD_CMD_SET_REV (189u) // 1, R, Command set revision.
#define EXT_CSD_CMD_SET (191u) // 1, R/W/E_P, Command set.
#define EXT_CSD_EXT_CSD_REV (192u) // 1, R, Extended CSD revision.
#define EXT_CSD_CSD_STRUCTURE (194u) // 1, R, CSD structure version.
#define EXT_CSD_CARD_TYPE (196u) // 1, R, Card type.
#define EXT_CSD_OUT_OF_INTERRUPT_TIME (198u) // 1, R, Out-of-interrupt busy timing.
#define EXT_CSD_PARTITION_SWITCH_TIME (199u) // 1, R, Partition switching timing.
#define EXT_CSD_PWR_CL_52_195 (200u) // 1, R, Power class for 52MHz at 1.95V.
#define EXT_CSD_PWR_CL_26_195 (201u) // 1, R, Power class for 26MHz at 1.95V.
#define EXT_CSD_PWR_CL_52_360 (202u) // 1, R, Power class for 52MHz at 3.6V.
#define EXT_CSD_PWR_CL_26_360 (203u) // 1, R, Power class for 26MHz at 3.6V.
#define EXT_CSD_MIN_PERF_R_4_26 (205u) // 1, R, Minimum Read Performance for 4bit at 26MHz.
#define EXT_CSD_MIN_PERF_W_4_26 (206u) // 1, R, Minimum Write Performance for 4bit at 26MHz.
#define EXT_CSD_MIN_PERF_R_8_26_4_52 (207u) // 1, R, Minimum Read Performance for 8bit at 26MHz, for 4bit at 52MHz.
#define EXT_CSD_MIN_PERF_W_8_26_4_52 (208u) // 1, R, Minimum Write Performance for 8bit at 26MHz, for 4bit at 52MHz.
#define EXT_CSD_MIN_PERF_R_8_52 (209u) // 1, R, Minimum Read Performance for 8bit at 52MHz.
#define EXT_CSD_MIN_PERF_W_8_52 (210u) // 1, R, Minimum Write Performance for 8bit at 52MHz.
#define EXT_CSD_SEC_COUNT (212u) // 4, R, Sector Count.
#define EXT_CSD_S_A_TIMEOUT (217u) // 1, R, Sleep/awake timeout.
#define EXT_CSD_S_C_VCCQ (219u) // 1, R, Sleep current (VCCQ).
#define EXT_CSD_S_C_VCC (220u) // 1, R, Sleep current (VCC).
#define EXT_CSD_HC_WP_GRP_SIZE (221u) // 1, R, High-capacity write protect group size.
#define EXT_CSD_REL_WR_SEC_C (222u) // 1, R, Reliable write sector count.
#define EXT_CSD_ERASE_TIMEOUT_MULT (223u) // 1, R, High-capacity erase timeout.
#define EXT_CSD_HC_ERASE_GRP_SIZE (224u) // 1, R, High-capacity erase unit size.
#define EXT_CSD_ACC_SIZE (225u) // 1, R, Access size.
#define EXT_CSD_BOOT_SIZE_MULTI (226u) // 1, R, Boot partition size.
#define EXT_CSD_BOOT_INFO (228u) // 1, R, Boot information.
#define EXT_CSD_SEC_TRIM_MULT (229u) // 1, R, Secure TRIM Multiplier.
#define EXT_CSD_SEC_ERASE_MULT (230u) // 1, R, Secure Erase Multiplier.
#define EXT_CSD_SEC_FEATURE_SUPPORT (231u) // 1, R, Secure Feature support.
#define EXT_CSD_TRIM_MULT (232u) // 1, R, TRIM Multiplier.
#define EXT_CSD_MIN_PERF_DDR_R_8_52 (234u) // 1, R, Minimum Read Performance for 8bit at 52MHz in DDR mode.
#define EXT_CSD_MIN_PERF_DDR_W_8_52 (235u) // 1, R, Minimum Write Performance for 8bit at 52MHz in DDR mode.
#define EXT_CSD_PWR_CL_DDR_52_195 (238u) // 1, R, Power class for 52MHz, DDR at 1.95V.
#define EXT_CSD_PWR_CL_DDR_52_360 (239u) // 1, R, Power class for 52MHz, DDR at 3.6V.
#define EXT_CSD_INI_TIMEOUT_AP (241u) // 1, R, 1st initialization time after partitioning.
#define EXT_CSD_CORRECTLY_PRG_SECTORS_NUM (242u) // 4, R, Number of correctly programmed sectors.
#define EXT_CSD_BKOPS_STATUS (246u) // 1, R, Background operations status.
#define EXT_CSD_BKOPS_SUPPORT (502u) // 1, R, Background operations support.
#define EXT_CSD_HPI_FEATURES (503u) // 1, R, HPI features.
#define EXT_CSD_S_CMD_SET (504u) // 1, R, Supported Command Sets.

View File

@ -1,207 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Based on SD specification version 8.00.
#include "drivers/toshsd.h"
// Controller specific macros. Add controller specific bits here.
// SD_[command type]_[response type]_[transfer type]
// Command type: CMD = regular command, ACMD = Application-Specific Command.
// Transfer type: R = read, W = write.
#define SD_CMD_NONE(id) (CMD_RESP_NONE | (id))
#define SD_CMD_R1(id) (CMD_RESP_R1 | (id))
#define SD_CMD_R1b(id) (CMD_RESP_R1b | (id))
#define SD_CMD_R2(id) (CMD_RESP_R2 | (id))
#define SD_CMD_R6(id) (CMD_RESP_R6 | (id))
#define SD_CMD_R7(id) (CMD_RESP_R7 | (id))
#define SD_CMD_R1_R(id) (CMD_DIR_R | CMD_DT_EN | CMD_RESP_R1 | (id))
#define SD_CMD_R1_W(id) (CMD_DIR_W | CMD_DT_EN | CMD_RESP_R1 | (id))
#define SD_ACMD_R1(id) (CMD_RESP_R1 | CMD_ACMD | (id))
#define SD_ACMD_R3(id) (CMD_RESP_R3 | CMD_ACMD | (id))
#define SD_ACMD_R1_R(id) (CMD_DIR_R | CMD_DT_EN | CMD_RESP_R1 | CMD_ACMD | (id))
// Basic Commands (class 0).
#define SD_GO_IDLE_STATE SD_CMD_NONE(0u) // -, [31:0] stuff bits.
#define SD_ALL_SEND_CID SD_CMD_R2(2u) // R2, [31:0] stuff bits.
#define SD_SEND_RELATIVE_ADDR SD_CMD_R6(3u) // R6, [31:0] stuff bits.
#define SD_SET_DSR SD_CMD_NONE(4u) // -, [31:16] DSR [15:0] stuff bits.
#define SD_SELECT_CARD SD_CMD_R1b(7u) // R1b, [31:16] RCA [15:0] stuff bits.
#define SD_DESELECT_CARD SD_CMD_NONE(7u) // -, [31:16] RCA [15:0] stuff bits.
#define SD_SEND_IF_COND SD_CMD_R7(8u) // R7, [31:12] reserved bits [11:8] supply voltage (VHS) [7:0] check pattern.
#define SD_SEND_CSD SD_CMD_R2(9u) // R2, [31:16] RCA [15:0] stuff bits.
#define SD_SEND_CID SD_CMD_R2(10u) // R2, [31:16] RCA [15:0] stuff bits.
#define SD_VOLTAGE_SWITCH SD_CMD_R1(11u) // R1, [31:0] reserved bits (all 0).
#define SD_STOP_TRANSMISSION SD_CMD_R1b(12u) // R1b, [31:0] stuff bits.
#define SD_SEND_STATUS SD_CMD_R1(13u) // R1, [31:16] RCA [15] Send Task Status Register [14:0] stuff bits.
#define SD_SEND_TASK_STATUS SD_CMD_R1(13u) // R1, [31:16] RCA [15] Send Task Status Register [14:0] stuff bits.
#define SD_GO_INACTIVE_STATE SD_CMD_NONE(15u) // -, [31:16] RCA [15:0] reserved bits.
// Block-Oriented Read Commands (class 2).
#define SD_SET_BLOCKLEN SD_CMD_R1(16u) // R1, [31:0] block length.
#define SD_READ_SINGLE_BLOCK SD_CMD_R1_R(17u) // R1, [31:0] data address.
#define SD_READ_MULTIPLE_BLOCK SD_CMD_R1_R(18u) // R1, [31:0] data address.
#define SD_SEND_TUNING_BLOCK SD_CMD_R1_R(19u) // R1, [31:0] reserved bits (all 0).
#define SD_SPEED_CLASS_CONTROL SD_CMD_R1b(20u) // R1b, [31:28] Speed Class Control [27:0] See command description.
#define SD_ADDRESS_EXTENSION SD_CMD_R1(22u) // R1, [31:6] reserved bits (all 0) [5:0] extended address.
#define SD_SET_BLOCK_COUNT SD_CMD_R1(23u) // R1, [31:0] Block Count.
// Block-Oriented Write Commands (class 4).
// SET_BLOCKLEN
// SPEED_CLASS_CONTROL
// ADDRESS_EXTENSION
// SET_BLOCK_COUNT
#define SD_WRITE_BLOCK SD_CMD_R1_W(24u) // R1, [31:0] data address.
#define SD_WRITE_MULTIPLE_BLOCK SD_CMD_R1_W(25u) // R1, [31:0] data address.
#define SD_PROGRAM_CSD SD_CMD_R1_W(27u) // R1, [31:0] stuff bits.
// Block Oriented Write Protection Commands (class 6).
#define SD_SET_WRITE_PROT SD_CMD_R1b(28u) // R1b, [31:0] data address.
#define SD_CLR_WRITE_PROT SD_CMD_R1b(29u) // R1b, [31:0] data address.
#define SD_SEND_WRITE_PROT SD_CMD_R1_R(30u) // R1, [31:0] write protect data address.
// Erase Commands (class 5).
#define SD_ERASE_WR_BLK_START SD_CMD_R1(32u) // R1, [31:0] data address.
#define SD_ERASE_WR_BLK_END SD_CMD_R1(33u) // R1, [31:0] data address.
#define SD_ERASE SD_CMD_R1b(38u) // R1b, [31:0] Erase Function.
// Lock Card (class 7).
// SET_BLOCKLEN
// Command 40 "Defined by DPS Spec.".
#define SD_LOCK_UNLOCK SD_CMD_R1_W(42u) // R1, [31:0] Reserved bits (Set all 0).
// Application-Specific Commands (class 8).
#define SD_APP_CMD SD_CMD_R1(55u) // R1, [31:16] RCA [15:0] stuff bits.
#define SD_GEN_CMD_R SD_CMD_R1_R(56u) // R1, [31:1] stuff bits. [0]: RD/WR = 1.
#define SD_GEN_CMD_W SD_CMD_R1_W(56u) // R1, [31:1] stuff bits. [0]: RD/WR = 0.
// Application Specific Commands used/reserved by SD Memory Card.
#define SD_APP_SET_BUS_WIDTH SD_ACMD_R1(6u) // R1, [31:2] stuff bits [1:0] bus width.
#define SD_APP_SD_STATUS SD_ACMD_R1_R(13u) // R1, [31:0] stuff bits.
#define SD_APP_SEND_NUM_WR_BLOCKS SD_ACMD_R1_R(22u) // R1, [31:0] stuff bits.
#define SD_APP_SET_WR_BLK_ERASE_COUNT SD_ACMD_R1(23u) // R1, [31:23] stuff bits [22:0] Number of blocks.
#define SD_APP_SD_SEND_OP_COND SD_ACMD_R3(41u) // R3, [31] reserved bit [30] HCS (OCR[30]) [29] reserved for eSD [28] XPC [27:25] reserved bits [24] S18R [23:0] VDD Voltage Window (OCR[23:0]).
#define SD_APP_SET_CLR_CARD_DETECT SD_ACMD_R1(42u) // R1, [31:1] stuff bits [0] set_cd.
#define SD_APP_SEND_SCR SD_ACMD_R1_R(51u) // R1, [31:0] stuff bits.
// Switch Function Commands (class 10).
#define SD_SWITCH_FUNC SD_CMD_R1_R(6u) // R1, [31] Mode 0: Check function 1: Switch function [30:24] reserved (All '0') [23:20] reserved for function group 6 (0h or Fh) [19:16] reserved for function group 5 (0h or Fh) [15:12] function group 4 for PowerLimit [11:8] function group 3 for Drive Strength [7:4] function group 2 for Command System [3:0] function group 1 for Access Mode.
// Function Extension Commands (class 11).
#define SD_READ_EXTR_SINGLE SD_CMD_R1_R(48u) // R1, [31] MIO0: Memory, 1: I/O [30:27] FNO[26] Reserved (=0) [25:9] ADDR [8:0] LEN.
#define SD_WRITE_EXTR_SINGLE SD_CMD_R1_W(49u) // R1, [31] MIO0: Memory, 1: I/O [30:27] FNO [26] MW [25:9] ADDR [8:0] LEN/MASK.
#define SD_READ_EXTR_MULTI SD_CMD_R1_R(58u) // R1, [31] MIO0: Memory, 1: I/O [30:27] FNO [26] BUS0: 512B, 1: 32KB [25:9] ADDR [8:0] BUC.
#define SD_WRITE_EXTR_MULTI SD_CMD_R1_W(59u) // R1, [31] MIO0: Memory, 1: I/O [30:27] FNO [26] BUS0: 512B, 1: 32KB [25:9] ADDR [8:0] BUC.
// Command Queue Function Commands (class 1).
#define SD_Q_MANAGEMENT SD_CMD_R1b(43u) // R1b, [31:21] Reserved [20:16]: Task ID [3:0]: Operation Code (Abort tasks etc.).
#define SD_Q_TASK_INFO_A SD_CMD_R1(44u) // R1, [31] Reserved [30] Direction [29:24] Extended Address [23] Priority [22:21] Reserved [20:16] Task ID [15:0] Number of Blocks.
#define SD_Q_TASK_INFO_B SD_CMD_R1(45u) // R1, [31:0] Start block address.
#define SD_Q_RD_TASK SD_CMD_R1_R(46u) // R1, [31:21] Reserved [20:16] Task ID [15:0] Reserved.
#define SD_Q_WR_TASK SD_CMD_R1_W(47u) // R1, [31:21] Reserved [20:16] Task ID [15:0] Reserved.
// 4.10.1 Card Status.
// Type:
// E: Error bit.
// S: Status bit.
// R: Detected and set for the actual command response.
// X: Detected and set during command execution. The host can get the status by issuing a command with R1 response.
//
// Clear Condition:
// A: According to the card current status.
// B: Always related to the previous command. Reception of a valid command will clear it (with a delay of one command).
// C: Clear by read.
#define SD_R1_AKE_SEQ_ERROR (1u<<3) // E R C, Error in the sequence of the authentication process.
#define SD_R1_APP_CMD (1u<<5) // S R C, The card will expect ACMD, or an indication that the command has been interpreted as ACMD.
#define SD_R1_FX_EVENT (1u<<6) // S X A, ExtensionFunctions may set this bit to get host to deal with events.
#define SD_R1_READY_FOR_DATA (1u<<8) // S X A, Corresponds to buffer empty signaling on the bus.
#define SD_R1_STATE_IDLE (0u<<9) // S X B
#define SD_R1_STATE_READY (1u<<9) // S X B
#define SD_R1_STATE_IDENT (2u<<9) // S X B
#define SD_R1_STATE_STBY (3u<<9) // S X B
#define SD_R1_STATE_TRAN (4u<<9) // S X B
#define SD_R1_STATE_DATA (5u<<9) // S X B
#define SD_R1_STATE_RCV (6u<<9) // S X B
#define SD_R1_STATE_PRG (7u<<9) // S X B
#define SD_R1_STATE_DIS (8u<<9) // S X B
#define SD_R1_ERASE_RESET (1u<<13) // S R C, An erase sequence was cleared before executing because an out of erase sequence command was received.
#define SD_R1_CARD_ECC_DISABLED (1u<<14) // S X A, The command has been executed without using the internal ECC.
#define SD_R1_WP_ERASE_SKIP (1u<<15) // E R X C, Set when only partial address space was erased due to existing write protected blocks or the temporary or permanent write protected cardwas erased.
#define SD_R1_CSD_OVERWRITE (1u<<16) // E R X C, Can be either one of the following errors: -The read only section of the CSD does not match the card content. -An attempt to reverse the copy (set as original) or permanent WP (unprotected) bits was made.
// 17 reserved for DEFERRED_RESPONSE (Refer to eSD Addendum)
#define SD_R1_ERROR (1u<<19) // E R X C, A general or an unknown error occurred during the operation.
#define SD_R1_CC_ERROR (1u<<20) // E R X C, Internal card controller error:
#define SD_R1_CARD_ECC_FAILED (1u<<21) // E R X C, Card internal ECC was applied but failed to correct the data.
#define SD_R1_ILLEGAL_COMMAND (1u<<22) // E R B, Command not legal for the card state.
#define SD_R1_COM_CRC_ERROR (1u<<23) // E R B, The CRC check of the previous command failed.
#define SD_R1_LOCK_UNLOCK_FAILED (1u<<24) // E R X C, Set when a sequence or password error has been detected in lock/unlock card command.
#define SD_R1_CARD_IS_LOCKED (1u<<25) // S X A, When set, signals that the card is locked by the host.
#define SD_R1_WP_VIOLATION (1u<<26) // E R X C, Set when the host attempts to write to a protected block or to thetemporary or permanent write protected card.
#define SD_R1_ERASE_PARAM (1u<<27) // E R X C, An invalid selection of write-blocks for erase occurred.
#define SD_R1_ERASE_SEQ_ERROR (1u<<28) // E R C, An error in the sequence of erase commands occurred.
#define SD_R1_BLOCK_LEN_ERROR (1u<<29) // E R X C, The transferred block length is not allowed for this card, or the number of transferred bytes does not match the block length.
#define SD_R1_ADDRESS_ERROR (1u<<30) // E R X C, A misaligned address which did not match the block length was used in the command.
#define SD_R1_OUT_OF_RANGE (1u<<31) // E R X C, The command's argument was out of the allowed range for this card.
#define SD_R1_ERR_ALL (SD_R1_OUT_OF_RANGE | SD_R1_ADDRESS_ERROR | SD_R1_BLOCK_LEN_ERROR | \
SD_R1_ERASE_SEQ_ERROR | SD_R1_ERASE_PARAM | SD_R1_WP_VIOLATION | \
SD_R1_LOCK_UNLOCK_FAILED | SD_R1_COM_CRC_ERROR | SD_R1_ILLEGAL_COMMAND | \
SD_R1_CARD_ECC_FAILED | SD_R1_CC_ERROR | SD_R1_ERROR | \
SD_R1_CSD_OVERWRITE | SD_R1_WP_ERASE_SKIP | SD_R1_AKE_SEQ_ERROR)
// Argument bits for SEND_IF_COND (CMD8).
#define SD_CMD8_CHK_PATT (0xAAu) // Check pattern.
#define SD_CMD8_VHS_2_7_3_6V (1u<<8) // Voltage supplied (VHS) 2.7-3.6V.
#define SD_CMD8_PCIe (1u<<12) // PCIe Avail-ability.
#define SD_CMD8_PCIe_1_2V (1u<<13) // PCIe 1.2V Support.
// 5.1 OCR register.
#define SD_OCR_2_7_2_8V (1u<<15) // 2.7-2.8V.
#define SD_OCR_2_8_2_9V (1u<<16) // 2.8-2.9V.
#define SD_OCR_2_9_3_0V (1u<<17) // 2.9-3.0V.
#define SD_OCR_3_0_3_1V (1u<<18) // 3.0-3.1V.
#define SD_OCR_3_1_3_2V (1u<<19) // 3.1-3.2V.
#define SD_OCR_3_2_3_3V (1u<<20) // 3.2-3.3V.
#define SD_OCR_3_3_3_4V (1u<<21) // 3.3-3.4V.
#define SD_OCR_3_4_3_5V (1u<<22) // 3.4-3.5V.
#define SD_OCR_3_5_3_6V (1u<<23) // 3.5-3.6V.
#define SD_OCR_S18A (1u<<24) // S18A: Switching to 1.8V Accepted. 0b: Continues current voltage signaling, 1b: Ready for switching signal voltage.
#define SD_OCR_CO2T (1u<<27) // Over 2TB Card. CCS must also be 1 if this is 1.
#define SD_OCR_UHS_II (1u<<29) // UHS-II Card Status. 0b: Non UHS-II Card, 1b: UHS-II Card.
#define SD_OCR_CCS (1u<<30) // Card Capacity Status. 0b: SDSC, 1b: SDHC or SDXC.
#define SD_OCR_READY (1u<<31) // Busy Status. 0b: On Initialization, 1b: Initialization Complete.
// Argument bits for SEND_OP_COND (ACMD41).
// For voltage bits see OCR register above.
#define SD_ACMD41_S18R (1u<<24) // S18R: Switching to 1.8V Request. 0b: Use current signal voltage, 1b: Switch to 1.8V signal voltage.
#define SD_ACMD41_HO2T (1u<<27) // Over 2TB Supported Host. HCS must also be 1 if this is 1.
#define SD_ACMD41_XPC (1u<<28) // SDXC Power Control. 0b: Power Saving, 1b: Maximum Performance.
#define SD_ACMD41_HCS (1u<<30) // Host Capacity Support. 0b: SDSC Only Host, 1b: SDHC or SDXC Supported.
// 4.3.10 Switch Function Command.
// mode: 0 = check function, 1 = set function
// pwr: Function group 4 Power Limit.
// driver: Function group 3 Driver Strength.
// cmd: Function group 2 Command system.
// acc: Function group 1 Access mode.
#define SD_SWITCH_FUNC_ARG(mode, pwr, driver, cmd, acc) ((mode)<<31 | 0xFFu<<16 | ((pwr)&0xFu)<<12 | ((driver)&0xFu)<<8 | ((cmd)&0xFu)<<4 | ((acc)&0xFu))

View File

@ -1,166 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
// Possible error codes for most of the functions below.
enum
{
SDMMC_ERR_NONE = 0u, // No error.
SDMMC_ERR_INVAL_PARAM = 1u, // Invalid parameter.
SDMMC_ERR_INITIALIZED = 2u, // The device is already initialized.
SDMMC_ERR_GO_IDLE_STATE = 3u, // GO_IDLE_STATE CMD error.
SDMMC_ERR_SEND_IF_COND = 4u, // SEND_IF_COND CMD error.
SDMMC_ERR_IF_COND_RESP = 5u, // IF_COND response pattern mismatch or unsupported voltage.
SDMMC_ERR_SEND_OP_COND = 6u, // SEND_OP_COND CMD error.
SDMMC_ERR_OP_COND_TMOUT = 7u, // Card initialization timeout.
SDMMC_ERR_VOLT_SUPPORT = 8u, // Voltage not supported.
SDMMC_ERR_ALL_SEND_CID = 9u, // ALL_SEND_CID CMD error.
SDMMC_ERR_SET_SEND_RCA = 10u, // SET/SEND_RELATIVE_ADDR CMD error.
SDMMC_ERR_SEND_CSD = 11u, // SEND_CSD CMD error.
SDMMC_ERR_SELECT_CARD = 12u, // SELECT_CARD CMD error.
SDMMC_ERR_LOCKED = 13u, // Card is locked with a password.
SDMMC_ERR_SEND_EXT_CSD = 14u, // SEND_EXT_CSD CMD error.
SDMMC_ERR_SWITCH_HS = 15u, // Error on switching to high speed mode.
SDMMC_ERR_SET_CLR_CD = 16u, // SET_CLR_CARD_DETECT CMD error.
SDMMC_ERR_SET_BUS_WIDTH = 17u, // Error on switching to a different bus width.
SDMMC_ERR_SEND_STATUS = 18u, // SEND_STATUS CMD error.
SDMMC_ERR_CARD_STATUS = 19u, // The card returned an error via its status.
SDMMC_ERR_NO_CARD = 20u, // Card unitialized or not inserted.
SDMMC_ERR_SECT_RW = 21u, // Sector read/write error.
SDMMC_ERR_WRITE_PROT = 22u // The card is write protected.
};
// (e)MMC/SD device numbers.
enum
{
SDMMC_DEV_CARD = 0u, // SD card/MMC.
SDMMC_DEV_eMMC = 1u, // Builtin eMMC.
// Alias for internal use only.
SDMMC_MAX_DEV_NUM = SDMMC_DEV_eMMC
};
// Bit definition for SdmmcInfo.wrProt and SDMMC_getWriteProtBits().
// Each bit 1 = protected.
#define SDMMC_WR_PROT_SLIDER (1u) // SD card write protection slider.
#define SDMMC_WR_PROT_TEMP (1u<<1) // Temporary write protection (CSD).
#define SDMMC_WR_PROT_PERM (1u<<2) // Permanent write protection (CSD).
typedef struct
{
u8 type; // 0 = none, 1 = (e)MMC, 2 = High capacity (e)MMC, 3 = SDSC, 4 = SDHC/SDXC, 5 = SDUC.
u8 wrProt; // See SDMMC_WR_PROT_ defines above for details.
u16 rca; // Relative Card Address (RCA).
u32 sectors; // Size in 512 byte units.
u32 clock; // The current clock frequency in Hz.
u32 cid[4]; // Raw CID without the CRC.
u16 ccc; // (e)MMC/SD command class support from CSD. One per bit starting at 0.
u8 busWidth; // The current bus width used to talk to the card.
} SdmmcInfo;
/**
* @brief Initializes a (e)MMC/SD card device.
*
* @param[in] devNum The device to initialize.
*
* @return Returns SDMMC_ERR_NONE on success or
* one of the errors listed above on failure.
*/
u32 SDMMC_init(const u8 devNum);
/**
* @brief Deinitializes a (e)MMC/SD card device.
*
* @param[in] devNum The device to deinitialize.
*
* @return Returns SDMMC_ERR_NONE on success or SDMMC_ERR_INVAL_PARAM on failure.
*/
u32 SDMMC_deinit(const u8 devNum);
/**
* @brief Outputs infos about a (e)MMC/SD card device.
*
* @param[in] devNum The device.
* @param infoOut A pointer to a SdmmcInfo struct.
*
* @return Returns SDMMC_ERR_NONE on success or SDMMC_ERR_INVAL_PARAM on failure.
*/
u32 SDMMC_getDevInfo(const u8 devNum, SdmmcInfo *const infoOut);
/**
* @brief Outputs the CID of a (e)MMC/SD card device.
*
* @param[in] devNum The device.
* @param cidOut A u32[4] pointer for storing the CID.
*
* @return Returns SDMMC_ERR_NONE on success or SDMMC_ERR_INVAL_PARAM on failure.
*/
u32 SDMMC_getCid(const u8 devNum, u32 cidOut[4]);
/**
* @brief Returns the write protection bits of a (e)MMC/SD card device.
*
* @param[in] devNum The device.
*
* @return Returns the write protection bits or 0xFF on failure.
* See SDMMC_WR_PROT_ defines above for details.
*/
u8 SDMMC_getWriteProtBits(const u8 devNum);
/**
* @brief Outputs the number of sectors for a (e)MMC/SD card device.
*
* @param[in] devNum The device.
*
* @return Returns the number of sectors or 0 on failure.
*/
u32 SDMMC_getSectors(const u8 devNum);
/**
* @brief Reads one or more sectors from a (e)MMC/SD card device.
*
* @param[in] devNum The device.
* @param[in] sect The start sector.
* @param buf The output buffer pointer. NULL for DMA.
* @param[in] count The number of sectors to read.
*
* @return Returns SDMMC_ERR_NONE on success or
* one of the errors listed above on failure.
*/
u32 SDMMC_readSectors(const u8 devNum, u32 sect, u32 *const buf, const u16 count);
/**
* @brief Writes one or more sectors to a (e)MMC/SD card device.
*
* @param[in] devNum The device.
* @param[in] sect The start sector.
* @param[in] buf The input buffer pointer. NULL for DMA.
* @param[in] count The count
*
* @return Returns SDMMC_ERR_NONE on success or
* one of the errors listed above on failure.
*/
u32 SDMMC_writeSectors(const u8 devNum, u32 sect, const u32 *const buf, const u16 count);
// TODO: TRIM/erase support.

View File

@ -1,98 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#ifdef ARM9
#define PXI_REGS_BASE (IO_MEM_ARM9_ONLY + 0x8000)
#elif ARM11
#define PXI_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x63000)
#endif // #ifdef ARM9
typedef struct
{
union
{
struct
{
vu8 sync_recvd; // 0x0 Received. Set by remote CPU via SENT.
vu8 sync_sent; // 0x1 Write-only, sent.
u8 _0x2;
vu8 sync_irq; // 0x3
};
vu32 sync; // 0x0
};
vu32 cnt; // 0x4
vu32 send; // 0x8 Send FIFO.
const vu32 recv; // 0xC Receive FIFO.
} Pxi;
static_assert(offsetof(Pxi, recv) == 0xC, "Error: Member recv of Pxi is not at offset 0xC!");
ALWAYS_INLINE Pxi* getPxiRegs(void)
{
return (Pxi*)PXI_REGS_BASE;
}
// REG_PXI_SYNC
// Note: SENT and RECV in REG_PXI_SYNC do not count
// the amount of bytes sent or received through the FIFOs!
// They are simply CPU read-/writable fields.
#define PXI_SYNC_RECVD (REG_PXI_SYNC & 0xFFu)
#define PXI_SYNC_SENT(sent) ((REG_PXI_SYNC & ~(0xFFu<<8)) | (sent)<<8)
#ifdef ARM9
#define PXI_SYNC_IRQ (1u<<29) // Trigger interrupt on ARM11.
#define PXI_SYNC_IRQ2 (1u<<30) // Another, separate interrupt trigger for ARM11.
#elif ARM11
// 29 unused unlike ARM9 side.
#define PXI_SYNC_IRQ (1u<<30) // Trigger interrupt on ARM9.
#endif // #ifdef ARM9
#define PXI_SYNC_IRQ_EN (1u<<31) // Enable interrupt(s) from remote CPU.
// REG_PXI_SYNC_IRQ (byte 3 of REG_PXI_SYNC)
#ifdef ARM9
#define PXI_SYNC_IRQ_IRQ (1u<<5) // Trigger interrupt on ARM11.
#define PXI_SYNC_IRQ_IRQ2 (1u<<6) // Another, separate interrupt trigger for ARM11.
#elif ARM11
// 29 unused unlike ARM9 side.
#define PXI_SYNC_IRQ_IRQ (1u<<6) // Trigger interrupt on ARM9.
#endif // #ifdef ARM9
#define PXI_SYNC_IRQ_IRQ_EN (1u<<7) // Enable interrupt(s) from remote CPU.
// REG_PXI_CNT
// Status bits: 0 = no, 1 = yes.
#define PXI_CNT_SEND_EMPTY (1u<<0) // Send FIFO empty status.
#define PXI_CNT_SEND_FULL (1u<<1) // Send FIFO full status.
#define PXI_CNT_SEND_NOT_FULL_IRQ_EN (1u<<2) // Send FIFO not full interrupt enable. TODO: Test the behavior.
#define PXI_CNT_FLUSH_SEND (1u<<3) // Flush send FIFO.
#define PXI_CNT_RECV_EMPTY (1u<<8) // Receive FIFO empty status.
#define PXI_CNT_RECV_FULL (1u<<9) // Receive FIFO full status.
#define PXI_CNT_RECV_NOT_EMPTY_IRQ_EN (1u<<10) // Receive FIFO not empty interrupt enable. TODO: Test the behavior.
#define PXI_CNT_FIFO_ERROR (1u<<14) // Receive FIFO underrun or send FIFO overrun error flag. Acknowledge by writing 1.
#define PXI_CNT_EN_FIFOS (1u<<15) // Enables REG_PXI_SEND and REG_PXI_RECV FIFOs.
void PXI_init(void);
u32 PXI_sendCmd(u32 cmd, const u32 *buf, u32 words);
void PXI_sendPanicCmd(u32 cmd); // Not intended for normal use!

View File

@ -1,129 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "types.h"
#include "mem_map.h"
#ifdef ARM11
#define SHA_REGS_BASE (IO_MEM_ARM9_ARM11 + 0x1000)
#elif ARM9
#define SHA_REGS_BASE (IO_MEM_ARM9_ONLY + 0xA000)
#endif // #ifdef ARM11
// Vectorizing the FIFO improves code generation at the cost of being slightly slower for small data.
typedef u32 ShaFifo __attribute__((vector_size(64)));
typedef struct
{
vu32 cnt; // 0x00
vu32 blkcnt; // 0x04
u8 _0x8[0x38];
vu32 hash[8]; // 0x40
u8 _0x60[0x20];
volatile ShaFifo fifo; // 0x80 The FIFO is in the DMA region instead on ARM11.
} Sha;
static_assert(offsetof(Sha, fifo) == 0x80, "Error: Member fifo of Sha is not at offset 0x80!");
ALWAYS_INLINE Sha* getShaRegs(void)
{
return (Sha*)SHA_REGS_BASE;
}
ALWAYS_INLINE volatile ShaFifo* getShaFifo(Sha *const regs)
{
#if (_3DS && ARM11)
return (volatile ShaFifo*)((uintptr_t)regs + 0x200000u);
#else
return &regs->fifo;
#endif // #if (_3DS && ARM11)
}
// REG_SHA_CNT
#define SHA_EN (1u) // Also used as busy flag.
#define SHA_FINAL_ROUND (1u<<1) // Final round/add input padding.
#define SHA_I_DMA_EN (1u<<2) // Input DMA enable.
#define SHA_IN_BIG (1u<<3)
#define SHA_IN_LITTLE (0u)
#define SHA_OUT_BIG (SHA_IN_BIG)
#define SHA_OUT_LITTLE (SHA_IN_LITTLE)
#define SHA_256_MODE (0u)
#define SHA_224_MODE (1u<<4)
#define SHA_1_MODE (2u<<4)
#define SHA_MODE_MASK (SHA_1_MODE | SHA_224_MODE | SHA_256_MODE)
#define SHA_RB_MODE (1u<<8) // Readback mode.
#define SHA_RB_FIFO_NE (1u<<9) // Readback mode FIFO not empty status.
#define SHA_O_DMA_EN (1u<<10) // Output DMA enable (readback mode).
/**
* @brief Sets input mode, endianess and starts the hash operation.
*
* @param[in] params Extra parameters like endianess. See REG_SHA_CNT defines above.
*/
void SHA_start(u16 params);
/**
* @brief Hashes the data pointed to.
*
* @param[in] data Pointer to data to hash.
* @param[in] size Size of the data to hash.
*/
void SHA_update(const u32 *data, u32 size);
/**
* @brief Generates the final hash.
*
* @param hash Pointer to memory to copy the hash to.
* @param[in] endianess Endianess bitmask for the hash.
*/
void SHA_finish(u32 *const hash, u16 endianess);
/**
* @brief Returns the current SHA engine state.
*
* @param out Pointer to memory to copy the state to.
*/
void SHA_getState(u32 *const out);
/**
* @brief Hashes a single block of data and outputs the hash.
*
* @param[in] data Pointer to data to hash.
* @param[in] size Size of the data to hash.
* @param hash Pointer to memory to copy the hash to.
* @param[in] params Extra parameters like endianess. See REG_SHA_CNT defines above.
* @param[in] hashEndianess Endianess bitmask for the hash.
*/
void sha(const u32 *data, u32 size, u32 *const hash, u16 params, u16 hashEndianess);
/**
* @brief Hashes a single block of data with DMA and outputs the hash.
*
* @param[in] data Pointer to data to hash.
* @param[in] size Size of the data to hash. Must be 64 bytes aligned.
* @param hash Pointer to memory to copy the hash to.
* @param[in] params Extra parameters like endianess. See REG_SHA_CNT defines above.
* @param[in] hashEndianess Endianess bitmask for the hash.
*/
//void sha_dma(const u32 *data, u32 size, u32 *const hash, u16 params, u16 hashEndianess);

View File

@ -1,420 +0,0 @@
#pragma once
#include <assert.h>
#include "types.h"
// For simplicity we will name the accessible 2 controllers 1 and 2.
// The real controller number is in the comment.
#ifdef _3DS
#ifdef ARM9
#define TOSHSD1_REGS_BASE (0x10006000u) // Controller 1.
#define TOSHSD2_REGS_BASE (0x10007000u) // Controller 3. Remappable.
#elif ARM11
#define TOSHSD1_REGS_BASE (0x10122000u) // Controller 2.
#define TOSHSD2_REGS_BASE (0x10100000u) // Controller 3. Remappable.
#endif // #ifdef ARM9
#define TOSHSD_HCLK (67027964u) // In Hz.
#elif TWL
#define TOSHSD1_REGS_BASE (0x04004800u) // Controller 1.
#define TOSHSD2_REGS_BASE (0x04004A00u) // Controller 2.
#define TOSHSD_HCLK (33513982u) // In Hz.
#endif // #ifdef _3DS
typedef struct
{
vu16 sd_cmd; // 0x000
vu16 sd_portsel; // 0x002
vu32 sd_arg; // 0x004 SD_ARG0 and SD_ARG1 combined.
vu16 sd_stop; // 0x008
vu16 sd_blockcount; // 0x00A
const vu32 sd_resp[4]; // 0x00C SD_RESP0-7 16 bit reg pairs combined.
vu32 sd_status; // 0x01C SD_STATUS1 and SD_STATUS2 combined.
vu32 sd_status_mask; // 0x020 SD_STATUS1_MASK and SD_STATUS2_MASK combined.
vu16 sd_clk_ctrl; // 0x024
vu16 sd_blocklen; // 0x026
vu16 sd_option; // 0x028 Card detect timer, data timeout and bus width.
u8 _0x2a[2];
const vu32 sd_err_status; // 0x02C SD_ERR_STATUS1 and SD_ERR_STATUS2 combined.
vu16 sd_fifo; // 0x030
u8 _0x32[2];
vu16 sdio_mode; // 0x034
vu16 sdio_status; // 0x036
vu16 sdio_status_mask; // 0x038
u8 _0x3a[0x9e];
vu16 dma_ext_mode; // 0x0D8
u8 _0xda[6];
vu16 soft_rst; // 0x0E0
const vu16 revision; // 0x0E2 Controller version/revision?
u8 _0xe4[0xe];
vu16 unkF2; // 0x0F2 Power related? Default 0. Other values do nothing?
vu16 ext_sdio_irq; // 0x0F4 Port 1/2/3 SDIO IRQ control.
const vu16 ext_wrprot; // 0x0F6 Apparently for eMMC.
vu16 ext_cdet; // 0x0F8 Card detect status.
vu16 ext_cdet_dat3; // 0x0FA DAT3 card detect status.
vu16 ext_cdet_mask; // 0x0FC Card detect mask (IRQ).
vu16 ext_cdet_dat3_mask; // 0x0FE DAT3 card detect mask (IRQ).
vu16 sd_fifo32_cnt; // 0x100
u8 _0x102[2];
vu16 sd_blocklen32; // 0x104
u8 _0x106[2];
vu16 sd_blockcount32; // 0x108
u8 _0x10a[2];
vu32 sd_fifo32; // 0x10C Note: This is in the FIFO region on ARM11 (3DS).
} Toshsd;
static_assert(offsetof(Toshsd, sd_fifo32) == 0x10C, "Error: Member sd_fifo32 of Toshsd is not at offset 0x10C!");
ALWAYS_INLINE Toshsd* getToshsdRegs(const u8 controller)
{
return (controller == 0 ? (Toshsd*)TOSHSD1_REGS_BASE : (Toshsd*)TOSHSD2_REGS_BASE);
}
ALWAYS_INLINE vu32* getToshsdFifo(Toshsd *const regs)
{
#if (_3DS && ARM11)
return (vu32*)((uintptr_t)regs + 0x200000); // FIFO is in the DMA region.
#else
return &regs->sd_fifo32;
#endif // #if (_3DS && ARM11)
}
// REG_SD_CMD
// Auto response supported commands:
// CMD0, CMD2, CMD3 (only SD?), CMD7 (only select?), CMD9, CMD10, CMD12, CMD13,
// CMD16, CMD17, CMD18, CMD25, CMD28, CMD55, ACMD6, ACMD23, ACMD42, ACMD51.
//
// When using auto response leave bits 11-13 unset (zero).
// Bit 0-5 command index.
#define CMD_ACMD (1u<<6) // Application command.
#define CMD_RESP_AUTO (0u) // Response type auto. Only works with certain commands.
#define CMD_RESP_NONE (3u<<8) // Response type none.
#define CMD_RESP_R1 (4u<<8) // Response type R1 48 bit.
#define CMD_RESP_R5 (CMD_RESP_R1) // Response type R5 48 bit.
#define CMD_RESP_R6 (CMD_RESP_R1) // Response type R6 48 bit.
#define CMD_RESP_R7 (CMD_RESP_R1) // Response type R7 48 bit.
#define CMD_RESP_R1b (5u<<8) // Response type R1b 48 bit + busy.
#define CMD_RESP_R5b (CMD_RESP_R1b) // Response type R5b 48 bit + busy.
#define CMD_RESP_R2 (6u<<8) // Response type R2 136 bit.
#define CMD_RESP_R3 (7u<<8) // Response type R3 48 bit OCR without CRC.
#define CMD_RESP_R4 (CMD_RESP_R3) // Response type R4 48 bit OCR without CRC.
#define CMD_RESP_MASK (CMD_RESP_R3)
#define CMD_DT_EN (1u<<11) // Data transfer enable.
#define CMD_DIR_R (1u<<12) // Data transfer direction read.
#define CMD_DIR_W (0u) // Data transfer direction write.
#define CMD_MBT (1u<<13) // Multi block transfer (auto STOP_TRANSMISSION).
#define CMD_SEC_SDIO (1u<<14) // Security/SDIO command.
// REG_SD_PORTSEL
#define PORTSEL_P0 (0u) // Controller port 0.
#define PORTSEL_P1 (1u) // Controller port 1.
#define PORTSEL_P2 (2u) // Controller port 2.
#define PORTSEL_P3 (3u) // Controller port 3.
#define PORTSEL_MASK (PORTSEL_P3)
// Bit 8-9 number of supported ports?
#define PORTSEL_UNK10 (1u<<10) // Unknown writable bit 10?
// REG_SD_STOP
#define STOP_STOP (1u) // Abort data transfer and send STOP_TRANSMISSION CMD.
#define STOP_AUTO_STOP (1u<<8) // Automatically send STOP_TRANSMISSION on multi-block transfer end.
// REG_SD_STATUS1/2 Write 0 to acknowledge a bit.
// REG_SD_STATUS1/2_MASK (M) = Maskable bit. 1 = disabled.
// Unmaskable bits act as status only, don't trigger IRQs and can't be acknowledged.
#define STATUS_RESP_END (1u) // (M) Response end.
#define STATUS_DATA_END (1u<<2) // (M) Data transfer end (triggers after last block).
#define STATUS_REMOVE (1u<<3) // (M) Card got removed.
#define STATUS_INSERT (1u<<4) // (M) Card got inserted. Set at the same time as DETECT.
#define STATUS_DETECT (1u<<5) // Card detect status (SD_OPTION detection timer). 1 = inserted.
#define STATUS_NO_WRPROT (1u<<7) // Write protection slider unlocked (low).
#define STATUS_DAT3_REMOVE (1u<<8) // (M) Card DAT3 got removed (low).
#define STATUS_DAT3_INSERT (1u<<9) // (M) Card DAT3 got inserted (high).
#define STATUS_DAT3_DETECT (1u<<10) // Card DAT3 status. 1 = inserted.
#define STATUS_ERR_CMD_IDX (1u<<16) // (M) Bad CMD index in response.
#define STATUS_ERR_CRC (1u<<17) // (M) Bad CRC in response.
#define STATUS_ERR_STOP_BIT (1u<<18) // (M) Stop bit error. Failed to recognize response frame end?
#define STATUS_ERR_DATA_TIMEOUT (1u<<19) // (M) Response data timeout.
#define STATUS_ERR_RX_OVERF (1u<<20) // (M) Receive FIFO overflow.
#define STATUS_ERR_TX_UNDERF (1u<<21) // (M) Send FIFO underflow.
#define STATUS_ERR_CMD_TIMEOUT (1u<<22) // (M) Response start bit timeout.
#define STATUS_SD_BUSY (1u<<23) // SD card signals busy if this bit is 0 (DAT0 held low).
#define STATUS_RX_RDY (1u<<24) // (M) FIFO ready for read.
#define STATUS_TX_REQ (1u<<25) // (M) FIFO write request.
// Bit 27 is maskable. Purpose unknown.
// Bit 29 exists (not maskable). Signals when clock divider changes are allowed?
#define STATUS_CMD_BUSY (1u<<30) // Command register busy.
#define STATUS_ERR_ILL_ACC (1u<<31) // (M) Illegal access error. TODO: What does that mean?
#define STATUS_MASK_ALL (0xFFFFFFFFu)
#define STATUS_MASK_DEFAULT ((1u<<27) | STATUS_TX_REQ | STATUS_RX_RDY | \
STATUS_DAT3_INSERT | STATUS_DAT3_REMOVE)
#define STATUS_MASK_ERR (STATUS_ERR_ILL_ACC | STATUS_ERR_CMD_TIMEOUT | STATUS_ERR_TX_UNDERF | \
STATUS_ERR_RX_OVERF | STATUS_ERR_DATA_TIMEOUT | STATUS_ERR_STOP_BIT | \
STATUS_ERR_CRC | STATUS_ERR_CMD_IDX)
// REG_SD_CLK_CTRL
#define SD_CLK_DIV_2 (0u) // Clock divider 2.
#define SD_CLK_DIV_4 (1u) // Clock divider 4.
#define SD_CLK_DIV_8 (1u<<1) // Clock divider 8.
#define SD_CLK_DIV_16 (1u<<2) // Clock divider 16.
#define SD_CLK_DIV_32 (1u<<3) // Clock divider 32.
#define SD_CLK_DIV_64 (1u<<4) // Clock divider 64.
#define SD_CLK_DIV_128 (1u<<5) // Clock divider 128.
#define SD_CLK_DIV_256 (1u<<6) // Clock divider 256.
#define SD_CLK_DIV_512 (1u<<7) // Clock divider 512.
#define SD_CLK_EN (1u<<8) // Clock enable.
#define SD_CLK_AUTO_OFF (1u<<9) // Disables clock on idle.
// Bit 10 is writable... at least according to gbatek (can't confirm). Purpose unknown.
// Outputs the matching divider for clk.
// Shift the output right by 2 to get the value for REG_SD_CLK_CTRL.
#define TOSHSD_CLK2DIV(clk) \
({ \
u32 __shift = 1; \
while((clk) < TOSHSD_HCLK>>__shift) ++__shift; \
1u<<__shift; \
})
// Clock off by default.
// Nearest possible for 400 kHz is 261.827984375 kHz.
#define SD_CLK_DEFAULT (TOSHSD_CLK2DIV(400000)>>2)
// REG_SD_OPTION
// Note on card detection time:
// The card detection timer starts only on inserting cards (including cold boot with inserted card)
// and when mapping ports between controllers. Card power doesn't have any effect on the timer.
//
// Bit 0-3 card detect timer 0x400<<x HCLKs. 0xF timer test (0x100 HCLKs).
// Bit 4-7 data timeout 0x2000<<x SDCLKs. 0xF timeout test (0x100 SDCLKs).
#define OPTION_UNK14 (1u<<14) // "no C2 module" What the fuck is a C2 module?
#define OPTION_BUS_WIDTH4 (0u) // 4 bit bus width.
#define OPTION_BUS_WIDTH1 (1u<<15) // 1 bit bus width.
#ifdef _3DS
// Card detect time: 0x400<<9 / 67027964 = 0.007821929 seconds.
// Data timeout: 0x2000<<12 / (67027964 / 2) = 1.001206959 seconds.
#define OPTION_DEFAULT_TIMINGS (12u<<4 | 9u)
#elif TWL
// Card detect time: 0x400<<8 / 33513982 = 0.007821929 seconds.
// Data timeout: 0x2000<<11 / (33513982 / 2) = 1.001206959 seconds.
#define OPTION_DEFAULT_TIMINGS (11u<<4 | 8u)
#endif // #ifdef _3DS
// REG_SD_ERR_STATUS1/2 Write 0 to acknowledge a bit.
// TODO: Are all of these actually supported on this controller?
#define ERR_RESP_CMD_IDX (1u) // Manual command index error in response.
#define ERR_RESP_CMD12_IDX (1u<<1) // Auto command index error in response.
#define ERR_RESP_STOP_BIT (1u<<2) // Manual command response stop bit error.
#define ERR_RESP_STOP_BIT_CMD12 (1u<<3) // Auto command response stop bit error.
#define ERR_STOP_BIT_DATA_READ (1u<<4) // Stop bit error in read data.
#define ERR_STOP_BIT_WR_CRC (1u<<5) // Stop bit error for write CRC status. What the hell does that mean?
#define ERR_CMD_RESP_CRC (1u<<8) // Manual command response CRC error.
#define ERR_CMD12_RESP_CRC (1u<<9) // Auto command response CRC error.
#define ERR_DATA_READ_CRC (1u<<10) // CRC error for read data.
#define ERR_WR_CRC_STAT (1u<<11) // "CRC error for Write CRC status for a write command". What the hell does that mean?
// Bit 13 always 1.
#define ERR_CMD_RESP_TMOUT (1u<<16) // Manual command response timeout.
#define ERR_CMD12_RESP_TMOUT (1u<<17) // Auto command response timeout.
// TODO: Add the correct remaining ones.
// REG_SDIO_MODE
#define SDIO_MODE_SDIO_IRQ_EN (1u) // SDIO IRQ enable (DAT1 low).
#define SDIO_MODE_UNK2_EN (1u<<2) // IRQ on "read wait" requests?
#define SDIO_MODE_UNK8 (1u<<8) // Aborts command and data transfer?
#define SDIO_MODE_UNK9 (1u<<9) // Aborts command but not data transfer? CMD52 related.
// REG_SDIO_STATUS Write 0 to acknowledge a bit.
// REG_SDIO_STATUS_MASK (M) = Maskable bit. 1 = disabled.
#define SDIO_STATUS_SDIO_IRQ (1u) // (M) SDIO IRQ (DAT1 low).
#define SDIO_STATUS_UNK1_IRQ (1u<<1) // (M) IRQ once CMD52 can be used after abort?
#define SDIO_STATUS_UNK2_IRQ (1u<<2) // (M) Related to SDIO_MODE_UNK2_EN?
#define SDIO_STATUS_UNK14_IRQ (1u<<14) // (M) Related to SDIO_MODE_UNK9?
#define SDIO_STATUS_UNK15_IRQ (1u<<15) // (M) Related to SDIO_MODE_UNK2_EN?
#define SDIO_STATUS_MASK_ALL (0xFFFFu)
// REG_DMA_EXT_MODE
#define DMA_EXT_CPU_MODE (0u) // Disables DMA requests. Actually also turns off the 32 bit FIFO.
#define DMA_EXT_DMA_MODE (1u<<1) // Enables DMA requests.
#define DMA_EXT_UNK5 (1u<<5) // "Buffer status mode"?
// REG_SOFT_RST
#define SOFT_RST_RST (0u) // Reset.
#define SOFT_RST_NORST (1u) // No reset.
// REG_EXT_SDIO_IRQ
#define EXT_SDIO_IRQ_P1 (1u) // Port 1 SDIO IRQ (DAT1 low). Write 0 to acknowledge.
#define EXT_SDIO_IRQ_P2 (1u<<1) // Port 2 SDIO IRQ (DAT1 low). Write 0 to acknowledge.
#define EXT_SDIO_IRQ_P3 (1u<<2) // Port 3 SDIO IRQ (DAT1 low). Write 0 to acknowledge.
#define EXT_SDIO_IRQ_P1_EN (1u<<4) // Port 1 SDIO IRQ enable (controller).
#define EXT_SDIO_IRQ_P2_EN (1u<<5) // Port 2 SDIO IRQ enable (controller).
#define EXT_SDIO_IRQ_P3_EN (1u<<6) // Port 3 SDIO IRQ enable (controller).
#define EXT_SDIO_IRQ_P1_MASK (1u<<8) // Port 1 SDIO IRQ mask. 1 = disable IRQ (CPU).
#define EXT_SDIO_IRQ_P2_MASK (1u<<9) // Port 2 SDIO IRQ mask. 1 = disable IRQ (CPU).
#define EXT_SDIO_IRQ_P3_MASK (1u<<10) // Port 3 SDIO IRQ mask. 1 = disable IRQ (CPU).
#define EXT_SDIO_IRQ_MASK_ALL (EXT_SDIO_IRQ_P3_MASK | EXT_SDIO_IRQ_P2_MASK | EXT_SDIO_IRQ_P1_MASK)
// REG_EXT_WRPROT Each bit 1 = write protected unlike SD_STATUS.
#define EXT_WRPROT_P1 (1u)
#define EXT_WRPROT_P2 (1u<<1)
#define EXT_WRPROT_P3 (1u<<2)
// REG_EXT_CDET Acknowledgeable?
// REG_EXT_CDET_MASK (M) = Maskable bit. 1 = disabled (no IRQ).
#define EXT_CDET_P1_REMOVE (1u) // (M) Port 1 card got removed.
#define EXT_CDET_P1_INSERT (1u<<1) // (M) Port 1 card got inserted. TODO: With detection timer?
#define EXT_CDET_P1_DETECT (1u<<2) // Port 1 card detect status. 1 = inserted. TODO: With detection timer?
#define EXT_CDET_P2_REMOVE (1u<<3) // (M) Port 2 card got removed.
#define EXT_CDET_P2_INSERT (1u<<4) // (M) Port 2 card got inserted. TODO: With detection timer?
#define EXT_CDET_P2_DETECT (1u<<5) // Port 2 card detect status. 1 = inserted. TODO: With detection timer?
#define EXT_CDET_P3_REMOVE (1u<<6) // (M) Port 3 card got removed.
#define EXT_CDET_P3_INSERT (1u<<7) // (M) Port 3 card got inserted. TODO: With detection timer?
#define EXT_CDET_P3_DETECT (1u<<8) // Port 3 card detect status. 1 = inserted. TODO: With detection timer?
#define EXT_CDET_MASK_ALL (0xFFFFu)
// REG_EXT_CDET_DAT3 Acknowledgeable?
// REG_EXT_CDET_DAT3_MASK (M) = Maskable bit. 1 = disabled (no IRQ).
#define EXT_CDET_DAT3_P1_REMOVE (1u) // (M) Port 1 card DAT3 got removed (low).
#define EXT_CDET_DAT3_P1_INSERT (1u<<1) // (M) Port 1 card DAT3 got inserted (high).
#define EXT_CDET_DAT3_P1_DETECT (1u<<2) // Port 1 card DAT3 status. 1 = inserted.
#define EXT_CDET_DAT3_P2_REMOVE (1u<<3) // (M) Port 2 card DAT3 got removed (low).
#define EXT_CDET_DAT3_P2_INSERT (1u<<4) // (M) Port 2 card DAT3 got inserted (high).
#define EXT_CDET_DAT3_P2_DETECT (1u<<5) // Port 2 card DAT3 status. 1 = inserted.
#define EXT_CDET_DAT3_P3_REMOVE (1u<<6) // (M) Port 3 card DAT3 got removed (low).
#define EXT_CDET_DAT3_P3_INSERT (1u<<7) // (M) Port 3 card DAT3 got inserted (high).
#define EXT_CDET_DAT3_P3_DETECT (1u<<8) // Port 3 card DAT3 status. 1 = inserted.
#define EXT_CDET_DAT3_MASK_ALL (0xFFFFu)
// REG_SD_FIFO32_CNT
// Bit 0 unknown, non-writable.
#define FIFO32_EN (1u<<1) // Enables the 32 bit FIFO.
#define FIFO32_FULL (1u<<8) // FIFO is full.
#define FIFO32_NOT_EMPTY (1u<<9) // FIFO is not empty. Inverted bit. 0 means empty.
#define FIFO32_CLEAR (1u<<10) // Clears the FIFO.
#define FIFO32_FULL_IE (1u<<11) // FIFO full IRQ enable.
#define FIFO32_NOT_EMPTY_IE (1u<<12) // FIFO not empty IRQ enable.
typedef struct
{
u8 portNum;
u16 sd_clk_ctrl;
u16 sd_blocklen; // Also sd_blocklen32.
u16 sd_option;
u32 *buf;
u16 blocks;
u32 resp[4]; // Little endian, MSB first.
} ToshsdPort;
/**
* @brief Initializes the toshsd driver.
*/
void TOSHSD_init(void);
/**
* @brief Deinitializes the toshsd driver.
*/
void TOSHSD_deinit(void);
/**
* @brief Initializes a toshsd port to defaults.
*
* @param port A pointer to the port struct.
* @param[in] portNum The port number.
*/
void TOSHSD_initPort(ToshsdPort *const port, const u8 portNum);
/**
* @brief Checks if a MMC/SD card is inserted.
*
* @return Returns true if a card is inserted.
*/
bool TOSHSD_cardDetected(void);
/**
* @brief Checks if the write protect slider is set to locked.
*
* @return Returns true if the card is unlocked.
*/
bool TOSHSD_cardWritable(void);
/**
* @brief Outputs a continuous clock for initialization.
*
* @param port A pointer to the port struct.
* @param[in] clk The target clock in Hz. Usually 400 kHz.
*/
void TOSHSD_startInitClock(ToshsdPort *const port, const u32 clk);
/**
* @brief Sends a command.
*
* @param port A pointer to the port struct.
* @param[in] cmd The command.
* @param[in] arg The argument for the command.
*
* @return Returns 0 on success otherwise see REG_SD_STATUS1/2 bits.
*/
u32 TOSHSD_sendCommand(ToshsdPort *const port, const u16 cmd, const u32 arg);
/**
* @brief Sets the clock for a toshsd port.
*
* @param port A pointer to the port struct.
* @param[in] clk The target clock in Hz.
*/
ALWAYS_INLINE void TOSHSD_setClock(ToshsdPort *const port, const u32 clk)
{
port->sd_clk_ctrl = SD_CLK_AUTO_OFF | SD_CLK_EN | TOSHSD_CLK2DIV(clk)>>2;
}
/**
* @brief Sets the transfer block length for a toshsd port.
*
* @param port A pointer to the port struct.
* @param[in] blockLen The block length.
*/
ALWAYS_INLINE void TOSHSD_setBlockLen(ToshsdPort *const port, u16 blockLen)
{
if(blockLen > 512) blockLen = 512;
if(blockLen < 16) blockLen = 0; // | Depends on doCpuTransfer() in toshsd.c.
if((blockLen % 16) != 0) blockLen = 0; // |
port->sd_blocklen = blockLen;
}
/**
* @brief Sets the bus width for a toshsd port.
*
* @param port A pointer to the port struct.
* @param[in] width The bus width.
*/
ALWAYS_INLINE void TOSHSD_setBusWidth(ToshsdPort *const port, const u8 width)
{
port->sd_option = (width == 4 ? OPTION_BUS_WIDTH4 : OPTION_BUS_WIDTH1) |
OPTION_UNK14 | OPTION_DEFAULT_TIMINGS;
}
/**
* @brief Sets a transfer buffer for a toshsd port.
*
* @param port A pointer to the port struct.
* @param buf The buffer pointer.
* @param[in] blocks The number of blocks to transfer.
*/
ALWAYS_INLINE void TOSHSD_setBuffer(ToshsdPort *const port, u32 *buf, const u16 blocks)
{
port->buf = buf;
port->blocks = blocks;
}

View File

@ -1,119 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef _3DS
#ifdef ARM9
#include "arm9/drivers/interrupt.h"
#include "arm9/drivers/cfg9.h"
#elif ARM11
#include "arm11/drivers/interrupt.h"
#endif // #ifdef ARM9
#elif TWL
#include <nds.h>
#endif // #ifdef _3DS
// Note on port numbers:
// To make things easier 2 ports are assigned to each controller.
// There are a maximum of 2 controllers mapped at the same time
// and 3 (on DSi 2) controllers in total.
// Also see toshsd.h.
//
// Examples:
// Port 0 is port 0 on controller 1, port 3 is port 1 on controller 2.
#ifdef _3DS
// This define determines whenever the SD slot is accessible on
// ARM9 or ARM11 when TOSHSD_CARD_PORT for ARM9 is set to 2.
#define TOSHSD_C2_MAP (0u) // Controller 2 (physical 3) memory mapping. 0=ARM9 0x10007000 or 1=ARM11 0x10100000.
#ifdef ARM9
#define TOSHSD_CARD_PORT (2u) // Can be on port 0 or 2. 0 always on ARM9.
#define TOSHSD_eMMC_PORT (1u) // Port 1 only. Do not change.
#elif ARM11
#define TOSHSD_CARD_PORT (2u) // Port 2 only. Do not change.
#define TOSHSD_eMMC_PORT (3u) // Placeholder. Do not change. Not connected/accessible.
#endif // #ifdef ARM9
#elif TWL
#define TOSHSD_CARD_PORT (0u)
#define TOSHSD_eMMC_PORT (1u)
#endif // #ifdef _3DS
// Don't modify anything below!
#ifdef _3DS
#ifdef ARM9
#define TOSHSD_MAP_CONTROLLERS() \
{ \
getCfg9Regs()->sdmmcctl = (TOSHSD_CARD_PORT == 2u ? SDMMCCTL_CARD_TOSHSD3_SEL : SDMMCCTL_CARD_TOSHSD1_SEL) | \
(TOSHSD_C2_MAP == 1u ? SDMMCCTL_TOSHSD3_MAP11 : SDMMCCTL_TOSHSD3_MAP9) | \
SDMMCCTL_UNK_BIT6 | SDMMCCTL_UNK_PWR_OFF; \
}
#define TOSHSD_UNMAP_CONTROLLERS() {getCfg9Regs()->sdmmcctl = SDMMCCTL_UNK_BIT6 | SDMMCCTL_UNK_PWR_OFF | SDMMCCTL_CARD_PWR_OFF;}
#define TOSHSD_NUM_CONTROLLERS (TOSHSD_C2_MAP == 0u ? 2u : 1u)
#define TOSHSD_IRQ_ID_CONTROLLER1 (IRQ_TOSHSD1)
#define TOSHSD_REGISTER_ISR(isr) \
{ \
IRQ_registerIsr(IRQ_TOSHSD1, (isr)); \
if(TOSHSD_NUM_CONTROLLERS == 2u) \
IRQ_registerIsr(IRQ_TOSHSD3, (isr)); \
}
#elif ARM11
#define TOSHSD_MAP_CONTROLLERS()
#define TOSHSD_UNMAP_CONTROLLERS()
#define TOSHSD_NUM_CONTROLLERS (TOSHSD_C2_MAP == 1u ? 2u : 1u)
#define TOSHSD_IRQ_ID_CONTROLLER1 (IRQ_TOSHSD2)
#define TOSHSD_REGISTER_ISR(isr) \
{ \
IRQ_registerIsr(IRQ_TOSHSD2, 14, 0, (isr)); \
if(TOSHSD_NUM_CONTROLLERS == 2u) \
IRQ_registerIsr(IRQ_TOSHSD3, 14, 0, (isr)); \
}
#endif // #ifdef ARM9
#define TOSHSD_UNREGISTER_ISR() \
{ \
IRQ_unregisterIsr(TOSHSD_IRQ_ID_CONTROLLER1); \
if(TOSHSD_NUM_CONTROLLERS == 2u) \
IRQ_unregisterIsr(IRQ_TOSHSD3); \
}
#elif TWL
#define TOSHSD_MAP_CONTROLLERS()
#define TOSHSD_UNMAP_CONTROLLERS()
#define TOSHSD_NUM_CONTROLLERS (2u)
#define TOSHSD_IRQ_ID_CONTROLLER1 (IRQ_SDMMC)
#define TOSHSD_REGISTER_ISR(isr) \
{ \
irqSetAUX(TOSHSD_IRQ_ID_CONTROLLER1, (isr)); \
/*irqSetAUX(..., (isr)); // Missing IRQ for controller 2.*/ \
irqEnableAUX(TOSHSD_IRQ_ID_CONTROLLER1); \
/*irqEnableAUX(...); // Missing IRQ for controller 2.*/ \
}
#define TOSHSD_UNREGISTER_ISR() \
{ \
irqClearAUX(TOSHSD_IRQ_ID_CONTROLLER1); \
/*irqClearAUX(...); // Missing IRQ for controller 2.*/ \
}
#endif // #ifdef _3DS

View File

@ -1,76 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#define CUSTOM_ERR_OFFSET (200u)
#define MAKE_CUSTOM_ERR(e) (CUSTOM_ERR_OFFSET + (e))
typedef u32 Result;
// Keep errors in the range of 0-255.
enum
{
// Common errors.
RES_OK = 0u,
RES_SD_CARD_REMOVED = 1u,
RES_DISK_FULL = 2u,
RES_INVALID_ARG = 3u,
RES_OUT_OF_MEM = 4u,
RES_OUT_OF_RANGE = 5u,
RES_NOT_FOUND = 6u,
RES_PATH_TOO_LONG = 7u,
// fatfs errors.
// Caution: Update fres2Res() in fs.c on ARM9 if this changes!
RES_FR_DISK_ERR = 8u, /* (1) A hard error occurred in the low level disk I/O layer */
RES_FR_INT_ERR = 9u, /* (2) Assertion failed */
RES_FR_NOT_READY = 10u, /* (3) The physical drive cannot work */
RES_FR_NO_FILE = 11u, /* (4) Could not find the file */
RES_FR_NO_PATH = 12u, /* (5) Could not find the path */
RES_FR_INVALID_NAME = 13u, /* (6) The path name format is invalid */
RES_FR_DENIED = 14u, /* (7) Access denied due to prohibited access or directory full */
RES_FR_EXIST = 15u, /* (8) Access denied due to prohibited access */
RES_FR_INVALID_OBJECT = 16u, /* (9) The file/directory object is invalid */
RES_FR_WRITE_PROTECTED = 17u, /* (10) The physical drive is write protected */
RES_FR_INVALID_DRIVE = 18u, /* (11) The logical drive number is invalid */
RES_FR_NOT_ENABLED = 19u, /* (12) The volume has no work area */
RES_FR_NO_FILESYSTEM = 20u, /* (13) There is no valid FAT volume */
RES_FR_MKFS_ABORTED = 21u, /* (14) The f_mkfs() aborted due to any problem */
RES_FR_TIMEOUT = 22u, /* (15) Could not get a grant to access the volume within defined period */
RES_FR_LOCKED = 23u, /* (16) The operation is rejected according to the file sharing policy */
RES_FR_NOT_ENOUGH_CORE = 24u, /* (17) LFN working buffer could not be allocated */
RES_FR_TOO_MANY_OPEN_FILES = 25u, /* (18) Number of open files > FF_FS_LOCK */
RES_FR_INVALID_PARAMETER = 26u, /* (19) Given parameter is invalid */
// Custom errors.
RES_ROM_TOO_BIG = MAKE_CUSTOM_ERR(0),
RES_GBA_RTC_ERR = MAKE_CUSTOM_ERR(1)
};
#undef MAKE_CUSTOM_ERR
#ifdef ARM11
void printError(Result res);
void printErrorWaitInput(Result res, u32 waitKeys);
#endif

View File

@ -1,32 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#ifdef NDEBUG
#define fb_assert(c) ((void)0)
#else
#define fb_assert(c) ((c) ? ((void)0) : __fb_assert(#c ", " __FILE__, __LINE__))
#endif
noreturn void __fb_assert(const char *const str, u32 line);

View File

@ -1,64 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "error_codes.h"
#include "fatfs/ff.h"
#define FS_MAX_DRIVES (FF_VOLUMES)
#define FS_DRIVE_NAMES "sdmc:/"
#define FS_MAX_FILES (1u)
#define FS_MAX_DIRS (1u)
typedef enum
{
FS_DRIVE_SDMC = 0u
} FsDrive;
typedef u32 FHandle;
typedef u32 DHandle;
Result fMount(FsDrive drive);
Result fUnmount(FsDrive drive);
Result fGetFree(FsDrive drive, u64 *const size);
Result fOpen(FHandle *const hOut, const char *const path, u8 mode);
Result fRead(FHandle h, void *const buf, u32 size, u32 *const bytesRead);
Result fWrite(FHandle h, const void *const buf, u32 size, u32 *const bytesWritten);
Result fSync(FHandle h);
Result fLseek(FHandle h, u32 off);
u32 fTell(FHandle h);
u32 fSize(FHandle h);
Result fClose(FHandle h);
Result fStat(const char *const path, FILINFO *const fi);
Result fChdir(const char *const path);
Result fOpenDir(DHandle *const hOut, const char *const path);
Result fReadDir(DHandle h, FILINFO *const fi, u32 num, u32 *const entriesRead);
Result fCloseDir(DHandle h);
Result fMkdir(const char *const path);
Result fRename(const char *const old, const char *const _new);
Result fUnlink(const char *const path);
#ifdef ARM9
void fsDeinit(void);
#endif // ifdef ARM9

View File

@ -1,29 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "error_codes.h"
Result fsQuickRead(const char *const path, void *const buf, u32 size);
Result fsQuickWrite(const char *const path, const void *const buf, u32 size);
Result fsMakePath(const char *const path);
Result fsLoadPathFromFile(const char *const path, char outPath[512]);

View File

@ -1,93 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#define IPC_MAX_PARAMS (15)
#define IPC_CMD_RESP_FLAG (1u<<15)
#define IPC_CMD_ID_MASK(cmd) ((cmd)>>8) // Max 127
#define IPC_CMD_SEND_BUFS_MASK(cmd) ((cmd)>>6 & 3u) // Max 3
#define IPC_CMD_RECV_BUFS_MASK(cmd) ((cmd)>>4 & 3u) // Max 3
#define IPC_CMD_PARAMS_MASK(cmd) ((cmd) & 15u) // Max 15
// https://stackoverflow.com/a/52770279
// Note: __COUNTER__ is non standard.
#define MAKE_CMD9(sendBufs, recvBufs, params) ((__COUNTER__ - _CMD9_C_BASE)<<8 | (sendBufs)<<6 | (recvBufs)<<4 | params)
#define MAKE_CMD11(sendBufs, recvBufs, params) ((__COUNTER__ - _CMD11_C_BASE)<<8 | (sendBufs)<<6 | (recvBufs)<<4 | params)
enum {_CMD9_C_BASE = __COUNTER__ + 1}; // Start at 0.
typedef enum
{
// Filesystem API.
IPC_CMD9_FMOUNT = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FUNMOUNT = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FGETFREE = MAKE_CMD9(0, 1, 1),
IPC_CMD9_FOPEN = MAKE_CMD9(1, 1, 1),
IPC_CMD9_FREAD = MAKE_CMD9(0, 2, 1),
IPC_CMD9_FWRITE = MAKE_CMD9(1, 1, 1),
IPC_CMD9_FSYNC = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FLSEEK = MAKE_CMD9(0, 0, 2),
IPC_CMD9_FTELL = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FSIZE = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FCLOSE = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FSTAT = MAKE_CMD9(1, 1, 0),
IPC_CMD9_FCHDIR = MAKE_CMD9(1, 0, 0),
IPC_CMD9_FOPEN_DIR = MAKE_CMD9(1, 1, 0),
IPC_CMD9_FREAD_DIR = MAKE_CMD9(0, 2, 2),
IPC_CMD9_FCLOSE_DIR = MAKE_CMD9(0, 0, 1),
IPC_CMD9_FMKDIR = MAKE_CMD9(1, 0, 0),
IPC_CMD9_FRENAME = MAKE_CMD9(2, 0, 0),
IPC_CMD9_FUNLINK = MAKE_CMD9(1, 0, 0),
// open_agb_firm specific API.
IPC_CMD9_PREPARE_GBA = MAKE_CMD9(1, 0, 2),
IPC_CMD9_SET_GBA_RTC = MAKE_CMD9(0, 0, 2),
IPC_CMD9_GET_GBA_RTC = MAKE_CMD9(0, 1, 0),
IPC_CMD9_BACKUP_GBA_SAVE = MAKE_CMD9(0, 0, 0),
//IPC_CMD9_TEST = MAKE_CMD9(0, 0, 0),
// Miscellaneous API.
IPC_CMD9_PREPARE_POWER = MAKE_CMD9(0, 0, 0) // Also used for panic() and guruMeditation().
} IpcCmd9;
enum {_CMD11_C_BASE = __COUNTER__ + 1}; // Start at 0.
typedef enum
{
// Miscellaneous API.
IPC_CMD11_PRINT_MSG = MAKE_CMD11(0, 0, 0), // Invalid on purpose. Will be decided later.
IPC_CMD11_PANIC = MAKE_CMD11(0, 0, 0),
IPC_CMD11_EXCEPTION = MAKE_CMD11(0, 0, 0)
} IpcCmd11;
#undef MAKE_CMD9
#undef MAKE_CMD11
typedef struct
{
void *ptr;
u32 size;
} IpcBuffer;
u32 IPC_handleCmd(u8 cmdId, u32 sendBufs, u32 recvBufs, const u32 *const buf);

View File

@ -1,153 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef ARM9
/* ITCM */
#define ITCM_BASE (0x00000000)
#define ITCM_KERNEL_MIRROR (0x01FF8000)
#define ITCM_BOOT9_MIRROR (0x07FF8000)
#define ITCM_SIZE (0x00008000) // 32 KiB
#endif
#ifdef ARM11
/* ARM11 bootrom */
#define BOOT11_BASE (0x00000000)
#define BOOT11_MIRROR1 (0x00010000)
#define BOOT11_SIZE (0x00010000) // 64 KiB
#endif
#ifdef ARM9
/* ARM9 RAM */
#define A9_RAM_BASE (0x08000000)
#define A9_RAM_N3DS_EXT_BASE (A9_RAM_BASE + 0x100000)
#define A9_RAM_SIZE (0x00100000) // 1 MiB
#define A9_RAM_N3DS_EXT_SIZE (0x00080000) // 512 KiB
#endif
/* IO mem */
#define IO_MEM_BASE (0x10000000)
#define IO_MEM_ARM9_ONLY (IO_MEM_BASE)
#define IO_MEM_ARM9_ARM11 (IO_MEM_BASE + 0x100000)
#define IO_MEM_ARM11_ONLY (IO_MEM_BASE + 0x200000)
#ifdef ARM11
/* ARM11 MPCore private region */
#define MPCORE_PRIV_REG_BASE (0x17E00000)
#define MPCORE_PRIV_REG_SIZE (0x00002000) // 8 KiB
/* L2C-310 Level 2 Cache Controller */
#define L2_CACHE_CONTR_BASE (0x17E10000)
#define L2_CACHE_CONTR_SIZE (0x00001000) // 4 KiB
#endif
/* VRAM */
#define VRAM_BASE (0x18000000)
#define VRAM_SIZE (0x00600000)
#define VRAM_BANK0 (VRAM_BASE)
#define VRAM_BANK1 (VRAM_BASE + 0x300000)
/* DSP mem */
#define DSP_MEM_BASE (0x1FF00000)
#define DSP_MEM_SIZE (0x00080000) // 512 KiB
/* AXIWRAM */
#define AXIWRAM_BASE (0x1FF80000)
#define AXIWRAM_SIZE (0x00080000) // 512 KiB
/* FCRAM */
#define FCRAM_BASE (0x20000000)
#define FCRAM_N3DS_EXT_BASE (FCRAM_BASE + 0x8000000)
#define FCRAM_SIZE (0x08000000) // 128 MiB
#define FCRAM_N3DS_EXT_SIZE (FCRAM_SIZE)
#ifdef ARM9
/* OTP */
#define OTP_BASE (0x10012000)
#define OTP_SIZE (0x00000100) // 256 bytes
/* DTCM */
#define DTCM_BASE (0xFFF00000)
#define DTCM_SIZE (0x00004000) // 16 KiB
/* ARM9 bootrom */
#define BOOT9_BASE (0xFFFF0000)
#define BOOT9_SIZE (0x00010000) // 64 KiB
#endif
#ifdef ARM11
/* ARM11 bootrom */
#define BOOT11_MIRROR2 (0xFFFF0000)
#endif
/* Custom mappings */
#ifdef ARM9
#define A9_VECTORS_START (A9_RAM_BASE)
#define A9_VECTORS_SIZE (0x40)
#define A9_STUB_ENTRY (ITCM_KERNEL_MIRROR + ITCM_SIZE - 0x200)
#define A9_STUB_SIZE (0x200)
#define A9_HEAP_END (A9_RAM_BASE + A9_RAM_SIZE)
#define A9_STACK_START (DTCM_BASE)
#define A9_STACK_END (DTCM_BASE + DTCM_SIZE - 0x400)
#define A9_IRQ_STACK_START (DTCM_BASE + DTCM_SIZE - 0x400)
#define A9_IRQ_STACK_END (DTCM_BASE + DTCM_SIZE)
#define A9_EXC_STACK_START (ITCM_KERNEL_MIRROR + (ITCM_SIZE / 2))
#define A9_EXC_STACK_END (ITCM_KERNEL_MIRROR + ITCM_SIZE)
#define FIRM_LOAD_ADDR (VRAM_BASE + 0x200000)
#define RAM_FIRM_BOOT_ADDR (FCRAM_BASE + 0x1000)
#endif
#ifdef ARM11
#define A11_C0_STACK_START (AXIWRAM_BASE) // Core 0 stack
#define A11_C0_STACK_END (A11_C0_STACK_START + 0x2000)
#define A11_C1_STACK_START (A11_C0_STACK_END) // Core 1 stack
#define A11_C1_STACK_END (A11_C1_STACK_START + 0x2000)
// WARNING: The stacks for core 2/3 are temporary
#define A11_C2_STACK_START (FCRAM_BASE - 0x600) // Core 2 stack
#define A11_C2_STACK_END (FCRAM_BASE - 0x400)
#define A11_C3_STACK_START (FCRAM_BASE - 0x400) // Core 3 stack
#define A11_C3_STACK_END (FCRAM_BASE - 0x200)
#define A11_EXC_STACK_START (VRAM_BASE + VRAM_SIZE - 0x200000)
#define A11_EXC_STACK_END (VRAM_BASE + VRAM_SIZE - 0x100000)
#define A11_MMU_TABLES_BASE (A11_C1_STACK_END)
#define A11_VECTORS_START (AXIWRAM_BASE + AXIWRAM_SIZE - 0x60)
#define A11_VECTORS_SIZE (0x60)
#define A11_FALLBACK_ENTRY (AXIWRAM_BASE + AXIWRAM_SIZE - 0x4)
#define A11_STUB_ENTRY (AXIWRAM_BASE + AXIWRAM_SIZE - 0x200)
#define A11_STUB_SIZE (0x1A0) // Don't overwrite the vectors
#define A11_HEAP_END (AXIWRAM_BASE + AXIWRAM_SIZE)
#endif

View File

@ -1,28 +0,0 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 Aurora Wright, TuxSH, derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Based on https://github.com/AuroraWright/Luma3DS/blob/master/arm9/source/alignedseqmemcpy.s
#include "types.h"
void iomemcpy(vu32 *restrict dst, const vu32 *restrict src, u32 size);
void iomemset(vu32 *ptr, u32 value, u32 size);

View File

@ -1,26 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
//void WEAK __systemInit(void);
void WEAK __systemDeinit(void);

View File

@ -1,61 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <inttypes.h> // printf()/scanf() macros
#include <stdalign.h> // alignas(alignment_in_bytes)
#include <stdbool.h> // bool, true/false
#include <stddef.h> // size_t, NULL...
#include <stdint.h> // uint8_t, uint16_t...
#include <stdnoreturn.h> // noreturn keyword
#include <unistd.h> // ssize_t
#define ALIGN(a) __attribute__((aligned(a))) // Use alignas() instead.
#define NAKED __attribute__((naked))
#define NOINLINE __attribute__((noinline))
#define ALWAYS_INLINE __attribute__((always_inline)) static inline
#define PACKED __attribute__((packed))
#define TARGET_ARM __attribute__((target("arm")))
#define TARGET_THUMB __attribute__((target("thumb")))
#define UNUSED __attribute__((unused))
#define USED __attribute__((used))
#define WEAK __attribute__((weak))
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
typedef volatile uint8_t vu8;
typedef volatile uint16_t vu16;
typedef volatile uint32_t vu32;
typedef volatile uint64_t vu64;
typedef volatile int8_t vs8;
typedef volatile int16_t vs16;
typedef volatile int32_t vs32;
typedef volatile int64_t vs64;

View File

@ -1,103 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#define min(a,b) ((size_t) (a) <= (size_t) (b) ? (size_t) (a) : (size_t) (b))
#define arrayEntries(array) sizeof(array)/sizeof(*array)
/**
* @brief Waits at least the specified amount of CPU cycles.
*
* @param[in] cycles The cycles to wait.
*/
NAKED void wait_cycles(u32 cycles);
/**
* @brief Safer strcpy with checks.
* The dst string always gets terminated except when num is 0.
* If the src string is too long nothing is copied and dst will be terminated.
* This function is not safe against race conditions!
*
* @param dst The destination pointer.
* @param[in] src The source pointer.
* @param[in] num Maximum number of chars to copy including null terminator.
*
* @return The length of the copied string in bytes including null terminator.
*/
size_t safeStrcpy(char *const dst, const char *const src, size_t num);
/**
* @brief Basic string to float conversion. Limited to 6 decimal places.
* Doesn't support exponents.
*
* @param[in] str The string.
*
* @return The floatingpoint number represented by str.
*/
float str2float(const char *str);
// case insensitive string compare function
int strnicmp(const char *str1, const char *str2, u32 len);
// custom safe strncpy, string is always 0-terminated for buflen > 0
void strncpy_s(char *dest, const char *src, u32 nchars, const u32 buflen);
void memcpy_s(void *dstBuf, size_t dstBufSize, size_t dstBufOffset,
void *srcBuf, size_t srcBufSize, size_t srcBufOffset, bool reverse);
u32 getleu32(const void* ptr);
u32 swap32(u32 val);
static inline u32 intLog2(u32 val)
{
// The result is undefined if __builtin_clzl() is called with 0.
return (val ? 31u - __builtin_clzl(val) : val);
}
// Round up to the next power of 2.
static inline u32 nextPow2(u32 val)
{
// Portable variant:
// https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
/*val--;
val |= val>>1;
val |= val>>2;
val |= val>>4;
val |= val>>8;
val |= val>>16;
val++;
return val;*/
// Warning: Allowed range is 2 - 2147483648.
// Everything else is undefined behavior.
return 1u<<(32u - __builtin_clzl(val - 1));
}
// https://stackoverflow.com/a/42340213
static inline u8 bcd2dec(const u8 bcd)
{
return bcd - 6u * (bcd>>4);
}

View File

@ -1,40 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
// MAX_PRIO_BITS The number of available priorities. Minimum 3. Maximum 32.
#define MAX_PRIO_BITS (4)
/*
* Maximum number of objects we can create (Slabheap).
*/
#define MAX_TASKS (3) // Including main and idle task.
#define MAX_EVENTS (10)
#define MAX_MUTEXES (3)
#define MAX_SEMAPHORES (0)
#define MAX_TIMERS (0)
#define IDLE_STACK_SIZE (0x1000) // Keep in mind this stack is used in interrupt contex! TODO: Change this.
// TODO: More checks. For example slabheap.
#if (MAX_PRIO_BITS < 3 || MAX_PRIO_BITS > 32)
#error "Invalid number of maximum task priorities!"
#endif

View File

@ -1,49 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "kernel.h"
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct
{
u32 r4;
u32 r5;
u32 r6;
u32 r7;
u32 r8;
u32 r9;
u32 r10;
u32 r11;
u32 lr; // pc
} cpuRegs;
KRes switchContext(KRes res, uintptr_t *oldSp, uintptr_t newSp);
#ifdef __cplusplus
}
#endif

View File

@ -1,78 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include "types.h"
#include "internal/list.h"
#include "kernel.h"
#include "arm.h"
typedef enum
{
TASK_STATE_DEAD = 0,
//TASK_STATE_READY = 1,
TASK_STATE_RUNNING = 1,
TASK_STATE_BLOCKED = 2,
TASK_STATE_RUNNING_SHORT = 3 // Continue task as soon as the woken ones are finished.
} TaskState;
struct TaskCb
{
ListNode node;
u8 core; // TODO: Multicore
u8 prio;
u8 id;
KRes res; // Last error code. Also abused for taskArg.
uintptr_t savedSp;
void *stack;
// Name?
// Exit code?
}; // Task context
typedef struct TaskCb TaskCb;
static_assert(offsetof(TaskCb, node) == 0, "Error: Member node of TaskCb is not at offset 0!");
const TaskCb* getCurrentTask(void);
KRes waitQueueBlock(ListNode *waitQueue);
bool waitQueueWakeN(ListNode *waitQueue, u32 wakeCount, KRes res, bool reschedule);
static inline void kernelLock(void)
{
__cpsid(i);
//spinlockLock(&g_lock);
}
static inline void kernelUnlock(void)
{
__cpsie(i);
//spinlockUnlock(&g_lock);
}
// These functions belong in other headers however we
// don't want to make them accessible in the public API.
void _eventSlabInit(void);
void _mutexSlabInit(void);
void _semaphoreSlabInit(void);
void _timerInit(void);

View File

@ -1,35 +0,0 @@
#pragma once
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 Aurora Wright, TuxSH, derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Based on https://github.com/AuroraWright/Luma3DS/blob/master/arm9/source/alignedseqmemcpy.s
#include "types.h"
void kmemcpy(u32 *restrict dst, const u32 *restrict src, u32 size);
// Alias of kmemcpy() with volatile arguments.
void iokmemcpy(vu32 *restrict dst, const vu32 *restrict src, u32 size);
void kmemset(u32 *ptr, u32 value, u32 size);
// Alias of kmemset() with volatile arguments.
void iokmemset(vu32 *ptr, u32 value, u32 size);

View File

@ -1,103 +0,0 @@
#pragma once
// Based on https://github.com/torvalds/linux/blob/master/include/linux/list.h
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#define LIST_INIT_VAL(name) ((ListNode){&(name), &(name)})
#define LIST_ENTRY(ptr, type, member) \
({ \
void *__mptr = (void*)(ptr); \
(type*)(__mptr - (size_t)&((type*)0)->member); \
})
#define LIST_FIRST_ENTRY(ptr, type, member) \
LIST_ENTRY((ptr)->next, type, member)
#define LIST_NEXT_ENTRY(pos, member) \
LIST_ENTRY((pos)->member.next, typeof(*(pos)), member)
#define LIST_FOR_EACH_ENTRY(pos, start, member) \
for(pos = LIST_FIRST_ENTRY(start, typeof(*pos), member); \
&pos->member != (start); \
pos = LIST_NEXT_ENTRY(pos, member))
typedef struct ListNode ListNode;
struct ListNode
{
ListNode *next;
ListNode *prev;
};
//static_assert(offsetof(ListNode, next) == 0, "Error: Member next of ListNode is not at offset 0!");
static inline void listInit(ListNode *start)
{
*start = LIST_INIT_VAL(*start);
}
static inline bool listEmpty(const ListNode *start)
{
return start->next == start;
}
// Internal function. Don't use unless you know what you are doing!
static inline void _listAdd(ListNode *node, ListNode *next, ListNode *prev)
{
node->next = next;
node->prev = prev;
next->prev = node;
prev->next = node;
}
static inline void listAddBefore(ListNode *entry, ListNode *node)
{
_listAdd(node, entry, entry->prev);
}
static inline void listAddAfter(ListNode *entry, ListNode *node)
{
_listAdd(node, entry->next, entry);
}
// Internal function. Don't use unless you know what you are doing!
static inline void _listDelete(ListNode *next, ListNode *prev)
{
next->prev = prev;
prev->next = next;
}
static inline void listDelete(ListNode *entry)
{
_listDelete(entry->next, entry->prev);
}
static inline ListNode* listRemoveTail(ListNode *start)
{
ListNode *const node = start->next;
listDelete(node);
return node;
}
static inline ListNode* listRemoveHead(ListNode *start)
{
ListNode *const node = start->prev;
listDelete(node);
return node;
}
// Some function aliases for queues.
#define listPush(start, node) listAddBefore((start), (node))
#define listPop(start) listRemoveTail((start))
#define listPushTail(start, node) listAddAfter((start), (node))
#define listPopHead(start) listRemoveHead((start))

View File

@ -1,63 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include "internal/list.h"
typedef ListNode SlabHeap;
/**
* @brief Initializes the slabheap.
*
* @param slab SlabHeap object pointer.
* @param[in] objSize The size of the object slots.
* @param[in] num The maximum number of object slots.
*/
void slabInit(SlabHeap *slab, size_t objSize, size_t num);
/**
* @brief Allocates an object slot from the slabheap.
*
* @param slab SlabHeap object pointer.
*
* @return Returns a pointer to the object slot.
*/
void* slabAlloc(SlabHeap *slab);
/**
* @brief Same as slabAlloc() but clears slots.
*
* @param slab SlabHeap object pointer.
* @param[in] clrSize The clear size (passed to memset()).
*
* @return Returns a pointer to the object slot.
*/
void* slabCalloc(SlabHeap *slab, size_t clrSize);
/**
* @brief Deallocates an object slot.
*
* @param slab SlabHeap object pointer.
* @param ptr The object slot pointer.
*/
void slabFree(SlabHeap *slab, void *ptr);

View File

@ -1,45 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
static inline void spinlockLock(u32 *lock)
{
u32 tmp;
__asm__ volatile("1: ldrex %0, [%1]\n"
" teq %0, #0\n"
" wfene\n"
" strexeq %0, %2, [%1]\n"
" teqeq %0, #0\n"
" bne 1b\n"
" mcr p15, 0, %0, c7, c10, 5" // DMB
: "=&r" (tmp) : "r" (lock), "r" (1) : "cc", "memory");
}
static inline void spinlockUnlock(u32 *lock)
{
__asm__ volatile("mcr p15, 0, %0, c7, c10, 5\n" // DMB
"str %0, [%1]\n"
"mcr p15, 0, %0, c7, c10, 4\n" // DSB
"sev"
: : "r" (0), "r" (lock) : "memory");
}

View File

@ -1,23 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define LIKELY(expr) __builtin_expect((expr), true)
#define UNLIKELY(expr) __builtin_expect((expr), false)

View File

@ -1,78 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif
enum
{
KRES_OK = 0, // No error.
KRES_INVALID_HANDLE = 1, // The handle or object doesn't exist.
KRES_HANDLE_DELETED = 2, // The handle has been deleted externally.
//KRES_WAIT_QUEUE_FULL = 3, // The wait queue is full. We can't block on it.
KRES_WOULD_BLOCK = 3, // The function would block. For non-blocking APIs.
KRES_NO_PERMISSIONS = 4 // You have no permissions. Example unlocking a mutex on a different task.
};
typedef uintptr_t KRes; // See createTask() implementation.
typedef uintptr_t KHandle;
typedef void (*TaskFunc)(void*);
/**
* @brief Initializes the kernel. Only call this once.
*
* @param[in] priority The priority of the main task.
*/
void kernelInit(uint8_t priority);
/**
* @brief Creates a new kernel task.
*
* @param[in] stackSize The stack size.
* @param[in] priority The priority.
* @param[in] entry The entry function.
* @param taskArg The task entry function argument.
*
* @return Returns a KHandle for the created task or NULL on error.
*/
KHandle createTask(size_t stackSize, uint8_t priority, TaskFunc entry, void *taskArg);
/**
* @brief Switches to the next task. Use with care.
*/
void yieldTask(void);
/**
* @brief Task exit function. Must be called from the task that exits.
*/
void taskExit(void);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -1,85 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include "kernel.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Creates a new kernel event.
*
* @param[in] oneShot Event fires only once and auto clears if true.
*
* @return The KHandle for the event or NULL on error.
*/
KHandle createEvent(bool oneShot);
/**
* @brief Deletes an kernel event.
*
* @param[in] kevent The KHandle of the event to delete.
*/
void deleteEvent(KHandle const kevent);
/**
* @brief Binds the given kernel event to an interrupt.
*
* @param[in] kevent The KHandle of the event.
* @param[in] id The interrupt id.
* @param[in] prio The interrupt priority.
*/
void bindInterruptToEvent(KHandle const kevent, uint8_t id, uint8_t prio);
void unbindInterruptEvent(uint8_t id);
/**
* @brief Waits for a kernel event to be signaled.
*
* @param[in] kevent The KHandle of the event.
*
* @return Returns the result. See Kres in kernel.h.
*/
KRes waitForEvent(KHandle const kevent);
/**
* @brief Signals an kernel event.
*
* @param[in] kevent The KHandle of the event.
* @param[in] reschedule Set to true to immediately reschedule.
*/
void signalEvent(KHandle const kevent, bool reschedule);
/**
* @brief Clears an kernel event.
*
* @param[in] kevent The KHandle of the event.
*/
void clearEvent(KHandle const kevent);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -1,68 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "kernel.h"
#ifdef __cplusplus
extern "C"
{
#endif
// TODO: Implement this using semaphores?
/**
* @brief Creates a new kernel mutex.
*
* @return The KHandle of the mutex or NULL on error.
*/
KHandle createMutex(void);
/**
* @brief Deletes a kernel mutex.
*
* @param[in] kmutex The KHandle of the mutex.
*/
void deleteMutex(KHandle const kmutex);
/**
* @brief Locks a kernel mutex.
*
* @param[in] kmutex The KHandle of the mutex.
*
* @return Returns the result. See Kres in kernel.h.
*/
KRes lockMutex(KHandle const kmutex);
/**
* @brief Unlocks a kernel mutex.
*
* @param[in] kmutex The KHandle of the mutex.
*
* @return Returns KRES_NO_PERMISSIONS immediately if the current task
* @return is not the owner. Otherwise KRES_OK.
*/
KRes unlockMutex(KHandle const kmutex);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -1,78 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <stdbool.h>
#include "kernel.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Creates a new kernel semaphore.
*
* @param[in] count The initial count of the semaphore.
*
* @return The KHandle of the semaphore or NULL on error.
*/
KHandle createSemaphore(int32_t count);
/**
* @brief Deletes a kernel semaphore.
*
* @param[in] ksema The KHandle of the semaphore.
*/
void deleteSemaphore(KHandle const ksema);
/**
* @brief Polls a kernel semaphore.
*
* @param[in] ksema The KHandle of the semaphore.
*
* @return Returns KRES_OK or KRES_WOULD_BLOCK.
*/
KRes pollSemaphore(KHandle const ksema);
/**
* @brief Decreases the kernel semaphore and blocks if <=0.
*
* @param[in] ksema The KHandle of the semaphore.
*
* @return Returns the result. See Kres in kernel.h.
*/
KRes waitForSemaphore(KHandle const ksema);
/**
* @brief Increases the kernel semaphore and wakes up signalCount waiting tasks if any.
*
* @param[in] ksema The KHandle of the semaphore.
* @param[in] signalCount The number of tasks to wake up..
* @param[in] reschedule Set to true to immediately reschedule.
*/
void signalSemaphore(KHandle const ksema, uint32_t signalCount, bool reschedule);
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -1,43 +0,0 @@
#pragma once
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "kernel.h"
#ifdef __cplusplus
extern "C"
{
#endif
/*KHandle createTimer(bool pulse);
void deleteTimer(KHandle const ktimer);
void startTimer(KHandle const ktimer, uint32_t usec);
void stopTimer(KHandle const ktimer);
KRes waitForTimer(KHandle const ktimer);*/
#ifdef __cplusplus
} // extern "C"
#endif

View File

@ -1,68 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "asm_macros.h"
.syntax unified
.arm
.cpu mpcore
.fpu vfpv2
@ void switchContextNoScratchRegs(u32 *curRegs, const u32 *newRegs)
/*ASM_FUNC switchContextNoScratchRegs
stmia r0!, {r4-r11, sp, lr}
add r0, r0, #20 @ Skip r0-r3, r12
adr r2, switchContextNoScratchRegs_end
mrs r3, cpsr
stmia r0, {r2, r3}
ldmia r1!, {r4-r11, sp, lr}
add r1, r1, #20 @ Skip r0-r3, r12
rfeia r1
switchContextNoScratchRegs_end:
cpsie i
bx lr
@ void switchContextAllRegs(u32 *curRegs, const u32 *newRegs)
ASM_FUNC switchContextAllRegs
stmia r0!, {r4-r11, sp, lr}
add r0, r0, #20 @ Skip r0-r3, r12
adr r2, switchContextAllRegs_end
mrs r3, cpsr
stmia r0, {r2, r3}
ldmia r1!, {r4-r11, sp, lr}
ldr r3, [r1, #24] @ cpsr
cps #19 @ SVC mode
msr spsr_fsxc, r3
ldmia r1, {r0-r3, r12, pc}^
switchContextAllRegs_end:
cpsie i
bx lr*/
@ KRes switchContext(KRes res, uintptr_t *oldSp, uintptr_t newSp);
BEGIN_ASM_FUNC switchContext
stmfd sp!, {r4-r11, lr}
str sp, [r1]
mov sp, r2
ldmfd sp!, {r4-r11, lr}
bx lr
END_ASM_FUNC
.pool

View File

@ -1,276 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdnoreturn.h>
#include <string.h>
#include "types.h"
#include "kernel.h"
#include "internal/config.h"
#include "internal/kernel_private.h"
#include "internal/kmemcpy_set.h"
#include "internal/slabheap.h"
#include "internal/util.h"
#include "internal/list.h"
#include "internal/contextswitch.h"
#include "arm.h"
static TaskCb *g_curTask = NULL;
static u32 g_readyBitmap = 0;
static ListNode g_runQueues[MAX_PRIO_BITS] = {0};
static SlabHeap g_taskSlab = {0};
static u32 g_numTasks = 0;
static TaskCb *g_curDeadTask = NULL; // TODO: Improve dead task handling.
static KRes scheduler(TaskState curTaskState);
noreturn static void kernelIdleTask(void);
static void initKernelState(void)
{
for(int i = 0; i < MAX_PRIO_BITS; i++) listInit(&g_runQueues[i]);
slabInit(&g_taskSlab, sizeof(TaskCb), MAX_TASKS);
_eventSlabInit();
_mutexSlabInit();
_semaphoreSlabInit();
//_timerInit();
}
/*
* Public kernel API.
*/
// TODO: Are KTask handles needed? (for the main task)
// TODO: Thread local storage. Needed?
void kernelInit(uint8_t priority)
{
if(priority > MAX_PRIO_BITS - 1u) return;
// TODO: Split this mess into helper functions.
initKernelState();
TaskCb *const idleT = (TaskCb*)slabAlloc(&g_taskSlab);
void *const iStack = malloc(IDLE_STACK_SIZE);
TaskCb *const mainT = (TaskCb*)slabCalloc(&g_taskSlab, sizeof(TaskCb));
if(idleT == NULL || iStack == NULL || mainT == NULL)
{
slabFree(&g_taskSlab, idleT);
free(iStack);
slabFree(&g_taskSlab, mainT);
return;
}
cpuRegs *const regs = (cpuRegs*)(iStack + IDLE_STACK_SIZE - sizeof(cpuRegs));
regs->lr = (u32)kernelIdleTask;
idleT->prio = 1;
// id is already set to 0.
idleT->savedSp = (uintptr_t)regs;
idleT->stack = iStack;
// Main task already running. Nothing more to setup.
mainT->id = 1;
mainT->prio = priority;
g_curTask = mainT;
g_readyBitmap = 1u<<1; // The idle task has priority 1 and is always ready.
listPush(&g_runQueues[1], &idleT->node);
g_numTasks = 2;
}
KHandle createTask(size_t stackSize, uint8_t priority, TaskFunc entry, void *taskArg)
{
if(priority > MAX_PRIO_BITS - 1u) return 0;
// Make sure the stack is aligned to 8 bytes
stackSize = (stackSize + 7u) & ~7u;
SlabHeap *const taskSlabPtr = &g_taskSlab;
TaskCb *const newT = (TaskCb*)slabAlloc(taskSlabPtr);
void *const stack = malloc(stackSize);
if(newT == NULL || stack == NULL)
{
slabFree(taskSlabPtr, newT);
free(stack);
return 0;
}
cpuRegs *const regs = (cpuRegs*)(stack + stackSize - sizeof(cpuRegs));
kmemset((u32*)regs, 0, sizeof(cpuRegs));
regs->lr = (u32)entry;
newT->prio = priority;
newT->id = g_numTasks; // TODO: Make this more sophisticated.
// TODO: This is kinda hacky abusing the result member to pass the task arg.
// Pass args and stuff on the stack?
newT->res = (KRes)taskArg;
newT->savedSp = (uintptr_t)regs;
newT->stack = stack;
kernelLock();
listPush(&g_runQueues[priority], &newT->node);
g_readyBitmap |= 1u<<priority;
g_numTasks++;
kernelUnlock();
return (uintptr_t)newT;
}
// TODO: setTaskPriority().
void yieldTask(void)
{
kernelLock();
scheduler(TASK_STATE_RUNNING);
}
void taskExit(void)
{
kernelLock();
scheduler(TASK_STATE_DEAD);
while(1); // TODO: panic?
}
/*
* Internal functions.
*/
const TaskCb* getCurrentTask(void)
{
return g_curTask;
}
// The wait queue and scheduler functions automatically unlock the kernel lock
// and expect to be called with locked lock.
KRes waitQueueBlock(ListNode *waitQueue)
{
listPush(waitQueue, &g_curTask->node);
return scheduler(TASK_STATE_BLOCKED);
}
bool waitQueueWakeN(ListNode *waitQueue, u32 wakeCount, KRes res, bool reschedule)
{
if(listEmpty(waitQueue) || !wakeCount)
{
kernelUnlock();
return false;
}
u32 readyBitmap = 0;
ListNode *const runQueues = g_runQueues;
if(LIKELY(reschedule))
{
// Put ourself on top of the list first so we run immediately
// after the woken tasks to finish the work we were doing.
// TODO: Verify if this is a good strategy.
TaskCb *const curTask = g_curTask;
const u8 curPrio = curTask->prio;
listPushTail(&runQueues[curPrio], &curTask->node);
readyBitmap = 1u<<curPrio;
}
do
{
/*
* Edge case:
* 2 tasks, 1 single shot event. Task 2 waits first and then task 1.
* When signaled (by an IRQ) only task 1 will ever run instead of
* alternating between both because task 1 always lands on the
* head (as intended) but on wakeup we take N tasks from the head
* to preserve order.
*
* Workaround:
* Take tasks from the tail instead. This will however punish
* the longest waiting tasks unnecessarily.
*/
//TaskCb *task = LIST_ENTRY(listPopHead(waitQueue), TaskCb, node);
TaskCb *task = LIST_ENTRY(listPop(waitQueue), TaskCb, node);
readyBitmap |= 1u<<task->prio;
task->res = res;
listPushTail(&runQueues[task->prio], &task->node);
} while(!listEmpty(waitQueue) && --wakeCount);
g_readyBitmap |= readyBitmap;
if(LIKELY(reschedule)) scheduler(TASK_STATE_RUNNING_SHORT);
else kernelUnlock();
return true;
}
static KRes scheduler(TaskState curTaskState)
{
#ifndef NDEBUG
if((__getCpsr() & PSR_MODE_MASK) != PSR_SYS_MODE) panic();
#endif
TaskCb *const curDeadTask = g_curDeadTask;
// TODO: Get rid of this and find a better way.
if(UNLIKELY(curDeadTask != NULL))
{
free(curDeadTask->stack);
slabFree(&g_taskSlab, curDeadTask);
g_curDeadTask = NULL;
}
TaskCb *const curTask = g_curTask;
u32 readyBitmap = g_readyBitmap;
ListNode *const runQueues = g_runQueues;
// Warning. The result is undefined if the input of this builtin is 0!
// Edge case: All tasks are sleeping except the (curently running) idle task.
// g_readyBitmap is 0 in this case.
const unsigned int readyPrio = (readyBitmap ? 31u - __builtin_clz(readyBitmap) : 0u);
if(LIKELY(curTaskState == TASK_STATE_RUNNING))
{
const u8 curPrio = curTask->prio;
if(readyPrio < curPrio)
{
kernelUnlock();
return KRES_OK;
}
listPush(&runQueues[curPrio], &curTask->node);
readyBitmap |= 1u<<curPrio;
}
else if(UNLIKELY(curTaskState == TASK_STATE_DEAD))
{
g_curDeadTask = curTask;
g_numTasks--;
}
TaskCb *newTask = LIST_ENTRY(listPop(&runQueues[readyPrio]), TaskCb, node);
if(listEmpty(&runQueues[readyPrio])) readyBitmap &= ~(1u<<readyPrio);
g_readyBitmap = readyBitmap;
TaskCb *oldTask = curTask;
g_curTask = newTask;
const KRes res = newTask->res;
kernelUnlock();
return switchContext(res, &oldTask->savedSp, newTask->savedSp);
}
// TODO: Cleanup deleted tasks in here? Or create a worker task?
noreturn static void kernelIdleTask(void)
{
do
{
__wfi();
kernelLock();
scheduler(TASK_STATE_RUNNING);
} while(1);
}

View File

@ -1,136 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdlib.h>
#include "types.h"
#include "internal/list.h"
#include "arm11/drivers/interrupt.h"
#include "internal/kernel_private.h"
#include "internal/slabheap.h"
#include "internal/config.h"
typedef struct
{
bool signaled;
const bool oneShot;
ListNode waitQueue;
} KEvent;
static SlabHeap g_eventSlab = {0};
static KHandle g_irqEventTable[128 - 32] = {0}; // 128 - 32 private interrupts.
void signalEvent(KHandle const kevent, bool reschedule);
void _eventSlabInit(void)
{
slabInit(&g_eventSlab, sizeof(KEvent), MAX_EVENTS);
}
static void eventIrqHandler(u32 intSource)
{
signalEvent(g_irqEventTable[intSource - 32], false);
}
KHandle createEvent(bool oneShot)
{
KEvent *const event = (KEvent*)slabAlloc(&g_eventSlab);
event->signaled = false;
*(bool*)&event->oneShot = oneShot;
listInit(&event->waitQueue);
return (KHandle)event;
}
void deleteEvent(KHandle const kevent)
{
KEvent *const event = (KEvent*)kevent;
kernelLock();
waitQueueWakeN(&event->waitQueue, (u32)-1, KRES_HANDLE_DELETED, true);
slabFree(&g_eventSlab, event);
}
// TODO: Critical sections needed for bind/unbind?
void bindInterruptToEvent(KHandle const kevent, uint8_t id, uint8_t prio)
{
if(id < 32 || id > 127) return;
g_irqEventTable[id - 32] = kevent;
IRQ_registerIsr(id, prio, 0, eventIrqHandler);
}
void unbindInterruptEvent(uint8_t id)
{
if(id < 32 || id > 127) return;
g_irqEventTable[id - 32] = 0;
IRQ_unregisterIsr(id);
}
// TODO: Timeout.
KRes waitForEvent(KHandle const kevent)
{
KEvent *const event = (KEvent*)kevent;
KRes res;
kernelLock();
if(event->signaled)
{
if(event->oneShot) event->signaled = false;
kernelUnlock();
res = KRES_OK;
}
else res = waitQueueBlock(&event->waitQueue);
return res;
}
void signalEvent(KHandle const kevent, bool reschedule)
{
KEvent *const event = (KEvent*)kevent;
kernelLock();
if(!event->signaled)
{
if(event->oneShot)
{
if(!waitQueueWakeN(&event->waitQueue, 1, KRES_OK, reschedule))
event->signaled = true;
}
else
{
event->signaled = true;
waitQueueWakeN(&event->waitQueue, (u32)-1, KRES_OK, reschedule);
}
}
else kernelUnlock();
}
void clearEvent(KHandle const kevent)
{
kernelLock(); // TODO: Can we do this without locks?
((KEvent*)kevent)->signaled = false;
kernelUnlock();
}

View File

@ -1,102 +0,0 @@
/*
* This file is part of fastboot 3DS
* Copyright (C) 2019 Aurora Wright, TuxSH, derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
@ Based on https://github.com/AuroraWright/Luma3DS/blob/master/arm9/source/alignedseqmemcpy.s
.syntax unified
.arm
.cpu arm946e-s
.fpu softvfp
@ void kmemcpy(u32 *restrict dst, const u32 *restrict src, u32 size);
@ void iokmemcpy(vu32 *restrict dst, const vu32 *restrict src, u32 size);
.section .text.kmemcpy, "ax", %progbits
.global kmemcpy
.global iokmemcpy
.type kmemcpy %function
.type iokmemcpy %function
.align 2
kmemcpy:
iokmemcpy:
bics r12, r2, #31
beq kmemcpy_test_words
stmfd sp!, {r4-r10}
kmemcpy_blocks_lp:
ldmia r1!, {r3-r10}
subs r12, #32
stmia r0!, {r3-r10}
bne kmemcpy_blocks_lp
ldmfd sp!, {r4-r10}
kmemcpy_test_words:
ands r12, r2, #28
beq kmemcpy_halfword_byte
kmemcpy_words_lp:
ldr r3, [r1], #4
subs r12, #4
str r3, [r0], #4
bne kmemcpy_words_lp
kmemcpy_halfword_byte:
tst r2, #2
ldrhne r3, [r1], #2
strhne r3, [r0], #2
tst r2, #1
ldrbne r3, [r1]
strbne r3, [r0]
bx lr
@ void kmemset(u32 *ptr, u32 value, u32 size);
@ void iokmemset(vu32 *ptr, u32 value, u32 size);
.section .text.kmemset, "ax", %progbits
.global kmemset
.global iokmemset
.type kmemset %function
.type iokmemset %function
.align 2
kmemset:
iokmemset:
bics r12, r2, #31
beq kmemset_test_words
stmfd sp!, {r4-r9}
mov r3, r1
mov r4, r1
mov r5, r1
mov r6, r1
mov r7, r1
mov r8, r1
mov r9, r1
kmemset_blocks_lp:
stmia r0!, {r1, r3-r9}
subs r12, #32
bne kmemset_blocks_lp
ldmfd sp!, {r4-r9}
kmemset_test_words:
ands r12, r2, #28
beq kmemset_halfword_byte
kmemset_words_lp:
str r1, [r0], #4
subs r12, #4
bne kmemset_words_lp
kmemset_halfword_byte:
tst r2, #2
strhne r1, [r0], #2
tst r2, #1
strbne r1, [r0]
bx lr

View File

@ -1,109 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include "types.h"
#include "internal/list.h"
#include "internal/kernel_private.h"
#include "internal/util.h"
#include "internal/slabheap.h"
#include "internal/config.h"
typedef struct
{
const TaskCb *owner;
ListNode waitQueue;
} KMutex;
static SlabHeap g_mutexSlab = {0};
void _mutexSlabInit(void)
{
slabInit(&g_mutexSlab, sizeof(KMutex), MAX_MUTEXES);
}
// TODO: Test mutex with multiple cores.
KHandle createMutex(void)
{
KMutex *const kmutex = (KMutex*)slabAlloc(&g_mutexSlab);
kmutex->owner = NULL;
listInit(&kmutex->waitQueue);
return (KHandle)kmutex;
}
void deleteMutex(KHandle const kmutex)
{
KMutex *const mutex = (KMutex*)kmutex;
kernelLock();
waitQueueWakeN(&mutex->waitQueue, (u32)-1, KRES_HANDLE_DELETED, true);
slabFree(&g_mutexSlab, mutex);
}
KRes lockMutex(KHandle const kmutex)
{
KMutex *const mutex = (KMutex*)kmutex;
KRes res;
do
{
kernelLock();
if(UNLIKELY(mutex->owner != NULL))
{
res = waitQueueBlock(&mutex->waitQueue);
if(UNLIKELY(res != KRES_OK)) break;
}
else
{
mutex->owner = getCurrentTask();
kernelUnlock();
res = KRES_OK;
break;
}
} while(1);
return res;
}
// TODO: Test if it works and only unlocks if current task == owner.
KRes unlockMutex(KHandle const kmutex)
{
KMutex *const mutex = (KMutex*)kmutex;
KRes res = KRES_OK;
kernelLock();
if(LIKELY(mutex->owner != NULL))
{
if(LIKELY(mutex->owner == getCurrentTask()))
{
mutex->owner = NULL;
waitQueueWakeN(&mutex->waitQueue, 1, KRES_OK, true);
}
else res = KRES_NO_PERMISSIONS;
}
else kernelUnlock();
return res;
}

View File

@ -1,101 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdbool.h>
#include <stdlib.h>
#include "types.h"
#include "internal/list.h"
#include "internal/kernel_private.h"
#include "internal/util.h"
#include "internal/slabheap.h"
#include "internal/config.h"
typedef struct
{
s32 count;
ListNode waitQueue;
} KSema;
static SlabHeap g_semaSlab = {0};
void _semaphoreSlabInit(void)
{
slabInit(&g_semaSlab, sizeof(KSema), MAX_SEMAPHORES);
}
// TODO: Test semaphore with multiple cores.
KHandle createSemaphore(int32_t count)
{
KSema *const ksema = (KSema*)slabAlloc(&g_semaSlab);
ksema->count = count;
listInit(&ksema->waitQueue);
return (KHandle)ksema;
}
void deleteSemaphore(KHandle const ksema)
{
KSema *const sema = (KSema*)ksema;
kernelLock();
waitQueueWakeN(&sema->waitQueue, (u32)-1, KRES_HANDLE_DELETED, true);
slabFree(&g_semaSlab, sema);
}
KRes pollSemaphore(KHandle const ksema)
{
KSema *const sema = (KSema*)ksema;
KRes res;
// TODO: Plain spinlocks instead?
kernelLock();
if(UNLIKELY(sema->count <= 0)) res = KRES_WOULD_BLOCK;
else {sema->count--; res = KRES_OK;}
kernelUnlock();
return res;
}
KRes waitForSemaphore(KHandle const ksema)
{
KSema *const sema = (KSema*)ksema;
KRes res;
kernelLock();
if(UNLIKELY(--sema->count < 0)) res = waitQueueBlock(&sema->waitQueue);
else {kernelUnlock(); res = KRES_OK;}
return res;
}
void signalSemaphore(KHandle const ksema, uint32_t signalCount, bool reschedule)
{
KSema *const sema = (KSema*)ksema;
kernelLock();
//if(UNLIKELY(++sema->count <= 0))
if(UNLIKELY((sema->count += signalCount) <= 0))
waitQueueWakeN(&sema->waitQueue, signalCount, KRES_OK, reschedule);
else kernelUnlock();
}

View File

@ -1,134 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*#include <stdbool.h>
#include <stdlib.h>
#include "types.h"
#include "ktimer.h"
#include "internal/list.h"
#include "arm11/drivers/interrupt.h"
//#include "arm11/drivers/timer.h"
#include "internal/kernel_private.h"
#include "internal/slabheap.h"
#include "internal/config.h"
//#include "arm11/fmt.h"
typedef struct
{
ListNode node;
u32 delta;
u32 ticks;
const bool pulse;
ListNode waitQueue;
} KTimer;
static SlabHeap g_timerSlab = {0};
static ListNode g_deltaQueue = {0};
static void timerIsr(UNUSED u32 intSource);
static void addToDeltaQueue(KTimer *const timer, u32 ticks);
void _timerInit(void)
{
slabInit(&g_timerSlab, sizeof(KTimer), MAX_TIMERS);
listInit(&g_deltaQueue);
IRQ_registerIsr(IRQ_TIMER, 12, 0, timerIsr);
}
KHandle createTimer(bool pulse)
{
KTimer *const ktimer = (KTimer*)slabAlloc(&g_timerSlab);
*(bool*)&ktimer->pulse = pulse;
listInit(&ktimer->waitQueue);
return (KHandle)ktimer;
}
void deleteTimer(KHandle const ktimer)
{
KTimer *const timer = (KTimer*)ktimer;
kernelLock();
waitQueueWakeN(&timer->waitQueue, (u32)-1, KRES_HANDLE_DELETED, true);
slabFree(&g_timerSlab, timer);
}
static void timerIsr(UNUSED u32 intSource)
{
kernelLock();
//if(listEmpty(&g_deltaQueue)) *((vu32*)4) = 4; // This should never happen
KTimer *ktimer = LIST_ENTRY(listPop(&g_deltaQueue), KTimer, node);
if(ktimer->pulse) addToDeltaQueue(ktimer, ktimer->ticks);
if(!listEmpty(&g_deltaQueue))
{
// Don't use fp math in ISRs.
TIMER_start(1, LIST_FIRST_ENTRY(&g_deltaQueue, KTimer, node)->delta, false, true);
}
waitQueueWakeN(&ktimer->waitQueue, (u32)-1, KRES_OK, false);
}
static void addToDeltaQueue(KTimer *const ktimer, u32 ticks)
{
KTimer *pos;
u32 deltaSum = 0;
LIST_FOR_EACH_ENTRY(pos, &g_deltaQueue, node)
{
deltaSum += pos->delta;
if(deltaSum > ticks)
{
ktimer->delta = ticks - (deltaSum - pos->delta);
listAddBefore(&pos->node, &ktimer->node);
return;
}
}
ktimer->delta = ticks;
listPush(&g_deltaQueue, &ktimer->node);
}
void startTimer(KHandle const ktimer, uint32_t usec)
{
KTimer *const timer = (KTimer*)ktimer;
const u32 ticks = TIMER_FREQ(1, 1000000) * usec;
timer->ticks = ticks;
kernelLock();
const bool firstTimer = listEmpty(&g_deltaQueue);
addToDeltaQueue(timer, ticks);
kernelUnlock();
if(firstTimer) TIMER_start(1, ticks, false, true);
}
void stopTimer(KHandle const ktimer)
{
}
KRes waitForTimer(KHandle const ktimer)
{
KTimer *const timer = (KTimer*)ktimer;
kernelLock();
return waitQueueBlock(&timer->waitQueue);
}*/

View File

@ -1,62 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include <stdlib.h>
#include "internal/slabheap.h"
#include "internal/kmemcpy_set.h"
void slabInit(SlabHeap *slab, size_t objSize, size_t num)
{
if(objSize < sizeof(SlabHeap) || !num) return;
listInit(slab);
void *pool = malloc(objSize * num);
if(!pool) return;
do
{
listPush(slab, (SlabHeap*)pool);
pool += objSize;
} while(--num);
}
void* slabAlloc(SlabHeap *slab)
{
if(!slab || listEmpty(slab)) return NULL;
return listPop(slab);
}
void* slabCalloc(SlabHeap *slab, size_t clrSize)
{
void *const ptr = slabAlloc(slab);
if(ptr) kmemset(ptr, 0, clrSize);
return ptr;
}
void slabFree(SlabHeap *slab, void *ptr)
{
if(!slab || !ptr) return;
// Keep gaps filled by allocating the same mem
// again next time an object is allocated.
listPushTail(slab, (SlabHeap*)ptr);
}

View File

@ -1,48 +0,0 @@
#pragma once
static rbtree_t sAddrMap;
struct addrMapNode
{
rbtree_node node;
MemChunk chunk;
};
#define getAddrMapNode(x) rbtree_item((x), addrMapNode, node)
static int addrMapNodeComparator(const rbtree_node_t* _lhs, const rbtree_node_t* _rhs)
{
auto lhs = getAddrMapNode(_lhs)->chunk.addr;
auto rhs = getAddrMapNode(_rhs)->chunk.addr;
if (lhs < rhs)
return -1;
if (lhs > rhs)
return 1;
return 0;
}
static void addrMapNodeDestructor(rbtree_node_t* a)
{
free(getAddrMapNode(a));
}
static addrMapNode* getNode(void* addr)
{
addrMapNode n;
n.chunk.addr = (u8*)addr;
auto p = rbtree_find(&sAddrMap, &n.node);
return p ? getAddrMapNode(p) : nullptr;
}
static addrMapNode* newNode(const MemChunk& chunk)
{
auto p = (addrMapNode*)malloc(sizeof(addrMapNode));
if (!p) return nullptr;
p->chunk = chunk;
return p;
}
static void delNode(addrMapNode* node)
{
rbtree_remove(&sAddrMap, &node->node, addrMapNodeDestructor);
}

View File

@ -1,154 +0,0 @@
#include "mem_pool.h"
/*
// This method is currently unused
void MemPool::CoalesceLeft(MemBlock* b)
{
auto curPtr = b->base;
for (auto p = b->prev; p; p = p->prev)
{
if ((p->base + p->size) != curPtr) break;
curPtr = p->base;
p->size += b->size;
DelBlock(b);
b = p;
}
}
*/
void MemPool::CoalesceRight(MemBlock* b)
{
auto curPtr = b->base + b->size;
auto next = b->next;
for (auto n = next; n; n = next)
{
next = n->next;
if (n->base != curPtr) break;
b->size += n->size;
curPtr += n->size;
DelBlock(n);
}
}
bool MemPool::Allocate(MemChunk& chunk, u32 size, int align)
{
// Don't shift out of bounds (CERT INT34-C)
if(align >= 32 || align < 0)
return false;
// Alignment must not be 0
if(align == 0)
return false;
u32 alignMask = (1 << align) - 1;
// Check if size doesn't fit neatly in alignment
if(size & alignMask)
{
// Make sure addition won't overflow (CERT INT30-C)
if(size > UINT32_MAX - alignMask)
return false;
// Pad size to next alignment
size = (size + alignMask) &~ alignMask;
}
// Find the first suitable block
for (auto b = first; b; b = b->next)
{
auto addr = b->base;
u32 begWaste = (u32)addr & alignMask;
if (begWaste > 0) begWaste = alignMask + 1 - begWaste;
if (begWaste > b->size) continue;
addr += begWaste;
u32 bSize = b->size - begWaste;
if (bSize < size) continue;
// Found space!
chunk.addr = addr;
chunk.size = size;
// Resize the block
if (!begWaste)
{
b->base += size;
b->size -= size;
if (!b->size)
DelBlock(b);
} else
{
auto nAddr = addr + size;
auto nSize = bSize - size;
b->size = begWaste;
if (nSize)
{
// We need to add the tail chunk that wasn't used to the list
auto n = MemBlock::Create(nAddr, nSize);
if (n) InsertAfter(b, n);
else chunk.size += nSize; // we have no choice but to waste the space.
}
}
return true;
}
return false;
}
void MemPool::Deallocate(const MemChunk& chunk)
{
u8* cAddr = chunk.addr;
auto cSize = chunk.size;
bool done = false;
// Try to merge the chunk somewhere into the list
for (auto b = first; !done && b; b = b->next)
{
auto addr = b->base;
if (addr > cAddr)
{
if ((cAddr + cSize) == addr)
{
// Merge the chunk to the left of the block
b->base = cAddr;
b->size += cSize;
} else
{
// We need to insert a new block
auto c = MemBlock::Create(cAddr, cSize);
if (c) InsertBefore(b, c);
}
done = true;
} else if ((b->base + b->size) == cAddr)
{
// Coalesce to the right
b->size += cSize;
CoalesceRight(b);
done = true;
}
}
if (!done)
{
// Either the list is empty or the chunk address is past the end
// address of the last block -- let's add a new block at the end
auto b = MemBlock::Create(cAddr, cSize);
if (b) AddBlock(b);
}
}
/*
void MemPool::Dump(const char* title)
{
printf("<%s> VRAM Pool Dump\n", title);
for (auto b = first; b; b = b->next)
printf(" - %p (%u bytes)\n", b->base, b->size);
}
*/
u32 MemPool::GetFreeSpace()
{
u32 acc = 0;
for (auto b = first; b; b = b->next)
acc += b->size;
return acc;
}

View File

@ -1,90 +0,0 @@
#pragma once
#include "types.h"
#include <stdlib.h>
struct MemChunk
{
u8* addr;
u32 size;
};
struct MemBlock
{
MemBlock *prev, *next;
u8* base;
u32 size;
static MemBlock* Create(u8* base, u32 size)
{
auto b = (MemBlock*)malloc(sizeof(MemBlock));
if (!b) return nullptr;
b->prev = nullptr;
b->next = nullptr;
b->base = base;
b->size = size;
return b;
}
};
struct MemPool
{
MemBlock *first, *last;
bool Ready() { return first != nullptr; }
void AddBlock(MemBlock* blk)
{
blk->prev = last;
if (last) last->next = blk;
if (!first) first = blk;
last = blk;
}
void DelBlock(MemBlock* b)
{
auto prev = b->prev, &pNext = prev ? prev->next : first;
auto next = b->next, &nPrev = next ? next->prev : last;
pNext = next;
nPrev = prev;
free(b);
}
void InsertBefore(MemBlock* b, MemBlock* p)
{
auto prev = b->prev, &pNext = prev ? prev->next : first;
b->prev = p;
p->next = b;
p->prev = prev;
pNext = p;
}
void InsertAfter(MemBlock* b, MemBlock* n)
{
auto next = b->next, &nPrev = next ? next->prev : last;
b->next = n;
n->prev = b;
n->next = next;
nPrev = n;
}
//void CoalesceLeft(MemBlock* b);
void CoalesceRight(MemBlock* b);
bool Allocate(MemChunk& chunk, u32 size, int align);
void Deallocate(const MemChunk& chunk);
void Destroy()
{
MemBlock* next = nullptr;
for (auto b = first; b; b = next)
{
next = b->next;
free(b);
}
first = nullptr;
last = nullptr;
}
//void Dump(const char* title);
u32 GetFreeSpace();
};

View File

@ -1,95 +0,0 @@
extern "C"
{
#include "types.h"
#include "arm11/allocator/vram.h"
#include "arm11/util/rbtree.h"
}
#include "mem_pool.h"
#include "addrmap.h"
static MemPool sVramPool;
static bool vramInit()
{
auto blk = MemBlock::Create((u8*)0x18000000, 0x00600000);
if (blk)
{
sVramPool.AddBlock(blk);
rbtree_init(&sAddrMap, addrMapNodeComparator);
return true;
}
return false;
}
void* vramMemAlign(size_t size, size_t alignment)
{
// Enforce minimum alignment
if (alignment < 16)
alignment = 16;
// Convert alignment to shift amount
int shift;
for (shift = 4; shift < 32; shift ++)
{
if ((1U<<shift) == alignment)
break;
}
if (shift == 32) // Invalid alignment
return nullptr;
// Initialize the pool if it is not ready
if (!sVramPool.Ready() && !vramInit())
return nullptr;
// Allocate the chunk
MemChunk chunk;
if (!sVramPool.Allocate(chunk, size, shift))
return nullptr;
auto node = newNode(chunk);
if (!node)
{
sVramPool.Deallocate(chunk);
return nullptr;
}
if (rbtree_insert(&sAddrMap, &node->node)) {}
return chunk.addr;
}
void* vramAlloc(size_t size)
{
return vramMemAlign(size, 0x80);
}
void* vramRealloc(void* mem, size_t size)
{
(void)mem;
(void)size;
// TODO
return NULL;
}
size_t vramGetSize(void* mem)
{
auto node = getNode(mem);
return node ? node->chunk.size : 0;
}
void vramFree(void* mem)
{
auto node = getNode(mem);
if (!node) return;
// Free the chunk
sVramPool.Deallocate(node->chunk);
// Free the node
delNode(node);
}
u32 vramSpaceFree()
{
return sVramPool.GetFreeSpace();
}

View File

@ -1,800 +0,0 @@
/*
* This code is part of libctru (https://github.com/devkitPro/libctru)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "types.h"
#include "arm11/fmt.h"
#include "drivers/gfx.h"
#include "util.h"
#include "arm11/console.h"
#include "arm11/font_6x10.h"
//set up the palette for color printing
static u16 colorTable[] = {
RGB8_to_565( 0, 0, 0), // faint black
RGB8_to_565(255, 0, 0), // bright red
RGB8_to_565( 0,255, 0), // bright green
RGB8_to_565(255,255, 0), // bright yellow
RGB8_to_565( 0, 0,255), // bright blue
RGB8_to_565(255, 0,255), // bright magenta
RGB8_to_565( 0,255,255), // bright cyan
RGB8_to_565(255,255,255), // bright white
RGB8_to_565( 64, 64, 64), // almost black
RGB8_to_565(224, 0, 0), // accent red
RGB8_to_565( 64,255, 64), // accent green
RGB8_to_565(255,255, 32), // accent yellow
RGB8_to_565( 64, 64,255), // accent blue
RGB8_to_565(255, 0,255), // bright magenta
RGB8_to_565( 0,255,255), // bright cyan
RGB8_to_565(192,192,192), // almost white
RGB8_to_565(128,128,128), // bright black
RGB8_to_565( 64, 0, 0), // faint red
RGB8_to_565( 0, 64, 0), // faint green
RGB8_to_565( 64, 64, 0), // faint yellow
RGB8_to_565( 0, 0, 64), // faint blue
RGB8_to_565( 64, 0, 64), // faint magenta
RGB8_to_565( 0, 64, 64), // faint cyan
RGB8_to_565( 96, 96, 96), // faint white
};
PrintConsole defaultConsole =
{
//Font:
{
default_font, //font gfx
0, //first ascii character in the set
256 //number of characters in the font set
},
(u16*)NULL,
0,0, //cursorX cursorY
0,0, //prevcursorX prevcursorY
53, //console width
24, //console height
0, //window x
0, //window y
53, //window width
24, //window height
3, //tab size
7, // foreground color
0, // background color
0, // flags
0, //print callback
false //console initialized
};
PrintConsole currentCopy;
PrintConsole* currentConsole = &currentCopy;
PrintConsole* consoleGetDefault(void){return &defaultConsole;}
void consolePrintChar(int c);
void consoleDrawChar(int c);
//---------------------------------------------------------------------------------
static void consoleCls(char mode) {
//---------------------------------------------------------------------------------
int i = 0;
int colTemp,rowTemp;
switch (mode)
{
case '[':
case '0':
{
colTemp = currentConsole->cursorX ;
rowTemp = currentConsole->cursorY ;
while(i++ < ((currentConsole->windowHeight * currentConsole->windowWidth) - (rowTemp * currentConsole->consoleWidth + colTemp)))
consolePrintChar(' ');
currentConsole->cursorX = colTemp;
currentConsole->cursorY = rowTemp;
break;
}
case '1':
{
colTemp = currentConsole->cursorX ;
rowTemp = currentConsole->cursorY ;
currentConsole->cursorY = 0;
currentConsole->cursorX = 0;
while (i++ < (rowTemp * currentConsole->windowWidth + colTemp))
consolePrintChar(' ');
currentConsole->cursorX = colTemp;
currentConsole->cursorY = rowTemp;
break;
}
case '2':
{
currentConsole->cursorY = 0;
currentConsole->cursorX = 0;
while(i++ < currentConsole->windowHeight * currentConsole->windowWidth)
consolePrintChar(' ');
currentConsole->cursorY = 0;
currentConsole->cursorX = 0;
break;
}
default: ;
}
}
//---------------------------------------------------------------------------------
static void consoleClearLine(char mode) {
//---------------------------------------------------------------------------------
int i = 0;
int colTemp;
switch (mode)
{
case '[':
case '0':
{
colTemp = currentConsole->cursorX ;
while(i++ < (currentConsole->windowWidth - colTemp)) {
consolePrintChar(' ');
}
currentConsole->cursorX = colTemp;
break;
}
case '1':
{
colTemp = currentConsole->cursorX ;
currentConsole->cursorX = 0;
while(i++ < ((currentConsole->windowWidth - colTemp)-2)) {
consolePrintChar(' ');
}
currentConsole->cursorX = colTemp;
break;
}
case '2':
{
colTemp = currentConsole->cursorX ;
currentConsole->cursorX = 0;
while(i++ < currentConsole->windowWidth) {
consolePrintChar(' ');
}
currentConsole->cursorX = colTemp;
break;
}
default: ;
}
}
__attribute__ ((format (scanf, 2, 3))) int fb_sscanf(const char *s, const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
int ret = 0;
const char *const oldS = s;
while(*fmt)
{
if(*fmt == '%')
{
bool number = false;
switch(*++fmt)
{
case 'd':
*va_arg(args, int*) = atoi(s);
number = true;
ret++;
break;
case 'c':
*va_arg(args, char*) = *s++;
ret++;
break;
case 'n':
*va_arg(args, int*) = (int)(s - oldS);
break;
default: ;
}
if(number) while(*s >= '0' && *s <= '9') s++;
fmt++;
}
else
{
if(*fmt != *s) break;
fmt++;
s++;
}
}
va_end(args);
return ret;
}
//---------------------------------------------------------------------------------
ssize_t con_write(UNUSED struct _reent *r,UNUSED void *fd,const char *ptr, size_t len) {
//---------------------------------------------------------------------------------
char chr;
int i, count = 0;
const char *tmp = ptr;
if(!tmp || (int)len<=0) return -1;
i = 0;
while(i<(int)len) {
chr = *(tmp++);
i++; count++;
if ( chr == 0x1b && *tmp == '[' ) {
bool escaping = true;
const char *escapeseq = tmp++;
int escapelen = 1;
i++; count++;
do {
chr = *(tmp++);
i++; count++; escapelen++;
int parameter, assigned, consumed;
// make sure parameters are positive values and delimited by semicolon
if((chr >= '0' && chr <= '9') || chr == ';')
continue;
switch (chr) {
//---------------------------------------
// Cursor directional movement
//---------------------------------------
case 'A':
consumed = 0;
assigned = fb_sscanf(escapeseq,"[%dA%n", &parameter, &consumed);
if (assigned==0) parameter = 1;
if (consumed)
currentConsole->cursorY = (currentConsole->cursorY - parameter) < 0 ? 0 : currentConsole->cursorY - parameter;
escaping = false;
break;
case 'B':
consumed = 0;
assigned = fb_sscanf(escapeseq,"[%dB%n", &parameter, &consumed);
if (assigned==0) parameter = 1;
if (consumed)
currentConsole->cursorY = (currentConsole->cursorY + parameter) > currentConsole->windowHeight - 1 ? currentConsole->windowHeight - 1 : currentConsole->cursorY + parameter;
escaping = false;
break;
case 'C':
consumed = 0;
assigned = fb_sscanf(escapeseq,"[%dC%n", &parameter, &consumed);
if (assigned==0) parameter = 1;
if (consumed)
currentConsole->cursorX = (currentConsole->cursorX + parameter) > currentConsole->windowWidth - 1 ? currentConsole->windowWidth - 1 : currentConsole->cursorX + parameter;
escaping = false;
break;
case 'D':
consumed = 0;
assigned = fb_sscanf(escapeseq,"[%dD%n", &parameter, &consumed);
if (assigned==0) parameter = 1;
if (consumed)
currentConsole->cursorX = (currentConsole->cursorX - parameter) < 0 ? 0 : currentConsole->cursorX - parameter;
escaping = false;
break;
//---------------------------------------
// Cursor position movement
//---------------------------------------
case 'H':
case 'f':
{
int x, y;
char c;
if(fb_sscanf(escapeseq,"[%d;%d%c", &y, &x, &c) == 3 && (c == 'f' || c == 'H')) {
currentConsole->cursorX = x;
currentConsole->cursorY = y;
escaping = false;
break;
}
x = y = 1;
if(fb_sscanf(escapeseq,"[%d;%c", &y, &c) == 2 && (c == 'f' || c == 'H')) {
currentConsole->cursorX = x;
currentConsole->cursorY = y;
escaping = false;
break;
}
x = y = 1;
if(fb_sscanf(escapeseq,"[;%d%c", &x, &c) == 2 && (c == 'f' || c == 'H')) {
currentConsole->cursorX = x;
currentConsole->cursorY = y;
escaping = false;
break;
}
x = y = 1;
if(fb_sscanf(escapeseq,"[;%c", &c) == 1 && (c == 'f' || c == 'H')) {
currentConsole->cursorX = x;
currentConsole->cursorY = y;
escaping = false;
break;
}
// invalid format
escaping = false;
break;
}
//---------------------------------------
// Screen clear
//---------------------------------------
case 'J':
if(escapelen <= 3)
consoleCls(escapeseq[escapelen-2]);
escaping = false;
break;
//---------------------------------------
// Line clear
//---------------------------------------
case 'K':
if(escapelen <= 3)
consoleClearLine(escapeseq[escapelen-2]);
escaping = false;
break;
//---------------------------------------
// Save cursor position
//---------------------------------------
case 's':
if(escapelen == 2) {
currentConsole->prevCursorX = currentConsole->cursorX ;
currentConsole->prevCursorY = currentConsole->cursorY ;
}
escaping = false;
break;
//---------------------------------------
// Load cursor position
//---------------------------------------
case 'u':
if(escapelen == 2) {
currentConsole->cursorX = currentConsole->prevCursorX ;
currentConsole->cursorY = currentConsole->prevCursorY ;
}
escaping = false;
break;
//---------------------------------------
// Color scan codes
//---------------------------------------
case 'm':
escapeseq++;
escapelen--;
do {
parameter = 0;
if (escapelen == 1) {
consumed = 1;
} else if (memchr(escapeseq,';',escapelen)) {
fb_sscanf(escapeseq,"%d;%n", &parameter, &consumed);
} else {
fb_sscanf(escapeseq,"%dm%n", &parameter, &consumed);
}
escapeseq += consumed;
escapelen -= consumed;
switch(parameter) {
case 0: // reset
currentConsole->flags = 0;
currentConsole->bg = 0;
currentConsole->fg = 7;
break;
case 1: // bold
currentConsole->flags &= ~CONSOLE_COLOR_FAINT;
currentConsole->flags |= CONSOLE_COLOR_BOLD;
break;
case 2: // faint
currentConsole->flags &= ~CONSOLE_COLOR_BOLD;
currentConsole->flags |= CONSOLE_COLOR_FAINT;
break;
case 3: // italic
currentConsole->flags |= CONSOLE_ITALIC;
break;
case 4: // underline
currentConsole->flags |= CONSOLE_UNDERLINE;
break;
case 5: // blink slow
currentConsole->flags &= ~CONSOLE_BLINK_FAST;
currentConsole->flags |= CONSOLE_BLINK_SLOW;
break;
case 6: // blink fast
currentConsole->flags &= ~CONSOLE_BLINK_SLOW;
currentConsole->flags |= CONSOLE_BLINK_FAST;
break;
case 7: // reverse video
currentConsole->flags |= CONSOLE_COLOR_REVERSE;
break;
case 8: // conceal
currentConsole->flags |= CONSOLE_CONCEAL;
break;
case 9: // crossed-out
currentConsole->flags |= CONSOLE_CROSSED_OUT;
break;
case 21: // bold off
currentConsole->flags &= ~CONSOLE_COLOR_BOLD;
break;
case 22: // normal color
currentConsole->flags &= ~CONSOLE_COLOR_BOLD;
currentConsole->flags &= ~CONSOLE_COLOR_FAINT;
break;
case 23: // italic off
currentConsole->flags &= ~CONSOLE_ITALIC;
break;
case 24: // underline off
currentConsole->flags &= ~CONSOLE_UNDERLINE;
break;
case 25: // blink off
currentConsole->flags &= ~CONSOLE_BLINK_SLOW;
currentConsole->flags &= ~CONSOLE_BLINK_FAST;
break;
case 27: // reverse off
currentConsole->flags &= ~CONSOLE_COLOR_REVERSE;
break;
case 29: // crossed-out off
currentConsole->flags &= ~CONSOLE_CROSSED_OUT;
break;
case 30 ... 37: // writing color
currentConsole->fg = parameter - 30;
break;
case 39: // reset foreground color
currentConsole->fg = 7;
break;
case 40 ... 47: // screen color
currentConsole->bg = parameter - 40;
break;
case 49: // reset background color
currentConsole->fg = 0;
break;
default: ;
}
} while (escapelen > 0);
escaping = false;
break;
default:
// some sort of unsupported escape; just gloss over it
escaping = false;
break;
}
} while (escaping);
continue;
}
consolePrintChar(chr);
}
return count;
}
//---------------------------------------------------------------------------------
PrintConsole* consoleInit(u8 screen, PrintConsole* console) {
//---------------------------------------------------------------------------------
if(console) {
currentConsole = console;
} else {
console = currentConsole;
}
*currentConsole = defaultConsole;
console->consoleInitialised = 1;
//gfxSetScreenFormat(screen,GSP_RGB565_OES);
GFX_setDoubleBuffering(screen, false);
console->frameBuffer = (u16*)GFX_getFramebuffer(screen);
if(screen==SCREEN_TOP) {
console->consoleWidth = 66;
console->windowWidth = 66;
}
consoleCls('2');
return currentConsole;
}
//---------------------------------------------------------------------------------
PrintConsole *consoleSelect(PrintConsole* console){
//---------------------------------------------------------------------------------
PrintConsole *tmp = currentConsole;
currentConsole = console;
return tmp;
}
//---------------------------------------------------------------------------------
PrintConsole *consoleGet(void){
//---------------------------------------------------------------------------------
return currentConsole;
}
//---------------------------------------------------------------------------------
u16 consoleGetFgColor(void){
//---------------------------------------------------------------------------------
return colorTable[currentConsole->fg];
}
//---------------------------------------------------------------------------------
void consoleSetFont(PrintConsole* console, ConsoleFont* font){
//---------------------------------------------------------------------------------
if(!console) console = currentConsole;
console->font = *font;
}
//---------------------------------------------------------------------------------
static void newRow() {
//---------------------------------------------------------------------------------
currentConsole->cursorY ++;
if(currentConsole->cursorY >= currentConsole->windowHeight) {
currentConsole->cursorY --;
u16 *dst = &currentConsole->frameBuffer[(currentConsole->windowX * 6 * 240) + (239 - (currentConsole->windowY * 10))];
u16 *src = dst - 10;
int i,j;
for (i=0; i<currentConsole->windowWidth*6; i++) {
u32 *from = (u32*)((int)src & ~3);
u32 *to = (u32*)((int)dst & ~3);
for (j=0;j<(((currentConsole->windowHeight-1)*10)/2);j++) *(to--) = *(from--);
dst += 240;
src += 240;
}
consoleClearLine('2');
}
}
//---------------------------------------------------------------------------------
void consoleDrawChar(int c) {
//---------------------------------------------------------------------------------
c -= currentConsole->font.asciiOffset;
if ( c < 0 || c > currentConsole->font.numChars ) return;
const u8 *fontdata = currentConsole->font.gfx + (10 * c);
int writingColor = currentConsole->fg;
int screenColor = currentConsole->bg;
if (currentConsole->flags & CONSOLE_COLOR_BOLD) {
writingColor += 8;
} else if (currentConsole->flags & CONSOLE_COLOR_FAINT) {
writingColor += 16;
}
if (currentConsole->flags & CONSOLE_COLOR_REVERSE) {
int tmp = writingColor;
writingColor = screenColor;
screenColor = tmp;
}
u16 bg = colorTable[screenColor];
u16 fg = colorTable[writingColor];
u8 b1 = *(fontdata++);
u8 b2 = *(fontdata++);
u8 b3 = *(fontdata++);
u8 b4 = *(fontdata++);
u8 b5 = *(fontdata++);
u8 b6 = *(fontdata++);
u8 b7 = *(fontdata++);
u8 b8 = *(fontdata++);
u8 b9 = *(fontdata++);
u8 b10 = *(fontdata++);
if (currentConsole->flags & CONSOLE_UNDERLINE) b10 = 0xff;
if (currentConsole->flags & CONSOLE_CROSSED_OUT) b5 = 0xff;
u8 mask = 0x80;
int i;
int x = (currentConsole->cursorX + currentConsole->windowX) * 6;
int y = ((currentConsole->cursorY + currentConsole->windowY) * 10);
u16 *screen = &currentConsole->frameBuffer[(x * 240) + (239 - (y + 9))];
for (i=0;i<6;i++) {
if (b10 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b9 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b8 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b7 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b6 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b5 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b4 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b3 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b2 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
if (b1 & mask) { *(screen++) = fg; }else{ *(screen++) = bg; }
mask >>= 1;
screen += 240 - 10;
}
}
//---------------------------------------------------------------------------------
void consolePrintChar(int c) {
//---------------------------------------------------------------------------------
if (c==0) return;
if(currentConsole->PrintChar)
if(currentConsole->PrintChar(currentConsole, c))
return;
if(currentConsole->cursorX >= currentConsole->windowWidth) {
currentConsole->cursorX = 0;
newRow();
}
switch(c) {
/*
The only special characters we will handle are tab (\t), carriage return (\r), line feed (\n)
and backspace (\b).
Carriage return & line feed will function the same: go to next line and put cursor at the beginning.
For everything else, use VT sequences.
Reason: VT sequences are more specific to the task of cursor placement.
The special escape sequences \b \f & \v are archaic and non-portable.
*/
case 8:
currentConsole->cursorX--;
if(currentConsole->cursorX < 0) {
if(currentConsole->cursorY > 0) {
currentConsole->cursorX = currentConsole->windowX - 1;
currentConsole->cursorY--;
} else {
currentConsole->cursorX = 0;
}
}
consoleDrawChar(' ');
break;
case 9:
currentConsole->cursorX += currentConsole->tabSize - ((currentConsole->cursorX)%(currentConsole->tabSize));
break;
case 10:
newRow();
// falls through
case 13:
currentConsole->cursorX = 0;
break;
default:
consoleDrawChar(c);
++currentConsole->cursorX ;
break;
}
}
//---------------------------------------------------------------------------------
void consoleClear(void) {
//---------------------------------------------------------------------------------
ee_printf("\x1b[2J");
}
//---------------------------------------------------------------------------------
void consoleSetWindow(PrintConsole* console, int x, int y, int width, int height){
//---------------------------------------------------------------------------------
if(!console) console = currentConsole;
console->windowWidth = width;
console->windowHeight = height;
console->windowX = x;
console->windowY = y;
console->cursorX = 0;
console->cursorY = 0;
}
void drawConsoleWindow(PrintConsole* console, int thickness, u8 colorIndex) {
if(colorIndex >= 16) return;
if(!console) console = currentConsole;
int startx = console->windowX * 8 - thickness;
int endx = (console->windowX + console->windowWidth) * 8 + thickness;
int starty = (console->windowY - 1) * 8 - thickness;
int endy = console->windowHeight * 8 + thickness;
u16 color = colorTable[colorIndex];
// upper line
for(int y = starty; y < starty + thickness; y++)
for(int x = startx; x < endx; x++)
{
u16 *screen = &currentConsole->frameBuffer[(x * 240) + (239 - (y + 7))];
*screen = color;
}
// lower line
for(int y = endy; y > endy - thickness; y--)
for(int x = startx; x < endx; x++)
{
u16 *screen = &currentConsole->frameBuffer[(x * 240) + (239 - (y + 7))];
*screen = color;
}
// left and right
for(int y = starty; y < endy; y++)
{
for(int i = 0; i < thickness; i++)
{
u16 *screen = &currentConsole->frameBuffer[((startx + i) * 240) + (239 - (y + 7))];
*screen = color;
screen = &currentConsole->frameBuffer[((endx - thickness + i) * 240) + (239 - (y + 7))];
*screen = color;
}
}
}
void consoleSetCursor(PrintConsole* console, int x, int y) {
console->cursorX = x;
console->cursorY = y;
}
u16 consoleGetRGB565Color(u8 colorIndex) {
if(colorIndex >= arrayEntries(colorTable))
return 0;
return colorTable[colorIndex];
}

View File

@ -1,180 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "types.h"
#include "mem_map.h"
#include "arm11/console.h"
#include "arm11/fmt.h"
#include "drivers/pxi.h"
#include "ipc_handler.h"
#include "arm11/drivers/interrupt.h"
#include "arm.h"
#include "arm11/drivers/mcu.h"
#include "arm11/drivers/hid.h"
NOINLINE noreturn void panic(void)
{
enterCriticalSection();
consoleInit(SCREEN_BOT, NULL);
ee_printf("\x1b[41m\x1b[0J\x1b[15C****PANIC!!!****\n");
PXI_sendPanicCmd(IPC_CMD9_PREPARE_POWER);
// Wait for A/B/X or Y
while(!(REG_HID_PAD & (KEY_A | KEY_B | KEY_X | KEY_Y)));
MCU_powerOffSys();
while(1) __wfi();
}
NOINLINE noreturn void panicMsg(const char *msg)
{
enterCriticalSection();
consoleInit(SCREEN_BOT, NULL);
ee_printf("\x1b[41m\x1b[0J\x1b[15C****PANIC!!!****\n\n");
ee_printf("\nERROR MESSAGE:\n%s\n", msg);
PXI_sendPanicCmd(IPC_CMD9_PREPARE_POWER);
// Wait for A/B/X or Y
while(!(REG_HID_PAD & (KEY_A | KEY_B | KEY_X | KEY_Y)));
MCU_powerOffSys();
while(1) __wfi();
}
// Expects the registers in the exception stack to be in the following order:
// r0-r14, pc (unmodified), CPSR, DFSR, IFSR, FAR, WFAR
NOINLINE noreturn void guruMeditation(u8 type, const u32 *excStack)
{
const char *const typeStr[3] = {"Undefined instruction", "Prefetch abort", "Data abort"};
u32 realPc, instSize = 4;
consoleInit(SCREEN_BOT, NULL);
if(excStack[16] & 0x20) instSize = 2; // Processor was in Thumb mode?
if(type == 2) realPc = excStack[15] - (instSize * 2); // Data abort
else realPc = excStack[15] - instSize; // Other
ee_printf("\x1b[41m\x1b[0J\x1b[15CGuru Meditation Error!\n\n%s:\n", typeStr[type]);
ee_printf("CPSR: 0x%" PRIX32 " DFSR: 0x%" PRIX32 " IFSR: 0x%" PRIX32 "\n"
"r0 = 0x%08" PRIX32 " r6 = 0x%08" PRIX32 " r12 = 0x%08" PRIX32 "\n"
"r1 = 0x%08" PRIX32 " r7 = 0x%08" PRIX32 " sp = 0x%08" PRIX32 "\n"
"r2 = 0x%08" PRIX32 " r8 = 0x%08" PRIX32 " lr = 0x%08" PRIX32 "\n"
"r3 = 0x%08" PRIX32 " r9 = 0x%08" PRIX32 " pc = 0x%08" PRIX32 "\n"
"r4 = 0x%08" PRIX32 " r10 = 0x%08" PRIX32 "\n"
"r5 = 0x%08" PRIX32 " r11 = 0x%08" PRIX32 "\n\n",
excStack[16], excStack[17], excStack[18],
excStack[0], excStack[6], excStack[12],
excStack[1], excStack[7], excStack[13],
excStack[2], excStack[8], excStack[14],
excStack[3], excStack[9], realPc,
excStack[4], excStack[10],
excStack[5], excStack[11]);
ee_puts("Stack dump:");
u32 sp = excStack[13];
if(sp >= AXIWRAM_BASE && sp < AXIWRAM_BASE + AXIWRAM_SIZE && !(sp & 3u))
{
u32 stackWords = ((AXIWRAM_BASE + AXIWRAM_SIZE - sp) / 4 > 48 ? 48 : (AXIWRAM_BASE + AXIWRAM_SIZE - sp) / 4);
u32 newlineCounter = 0;
for(u32 i = 0; i < stackWords; i++)
{
if(newlineCounter == 4) {ee_printf("\n"); newlineCounter = 0;}
ee_printf("0x%08" PRIX32 " ", ((u32*)sp)[i]);
newlineCounter++;
}
}
PXI_sendPanicCmd(IPC_CMD9_PREPARE_POWER);
// Wait for A/B/X or Y
while(!(REG_HID_PAD & (KEY_A | KEY_B | KEY_X | KEY_Y)));
MCU_powerOffSys();
while(1) __wfi();
}
#ifndef NDEBUG
// Needs to be marked as used to work with LTO.
// The used attribute also overrides the newlib symbol.
// This is for debugging purposes only. For security this value needs to be random!
__attribute__((used)) uintptr_t __stack_chk_guard = 0xC724B66D;
// Needs to be marked as noinline and used to work with LTO.
// The used attribute also overrides the newlib symbol.
// Combine -fstack-protector-all with -fno-inline to get the most effective detection.
__attribute__((noinline, used)) noreturn void __stack_chk_fail(void)
{
panicMsg("Stack smash!");
}
// Add "-Wl,-wrap=malloc,-wrap=calloc,-wrap=free" to LDFLAGS to enable the heap check.
static const u32 __heap_chk_guard[4] = {0x9240A724, 0x6A6594A0, 0x976F0392, 0xB3A669AB};
void* __real_malloc(size_t size);
void __real_free(void *ptr);
void* __wrap_malloc(size_t size)
{
void *const buf = __real_malloc(size + 32);
if(buf == NULL) return NULL;
memcpy(buf, &size, sizeof(size_t));
memcpy(buf + sizeof(size_t), (u8*)__heap_chk_guard + sizeof(size_t), 16 - sizeof(size_t));
memcpy(buf + 16 + size, __heap_chk_guard, 16);
return buf + 16;
}
void* __wrap_calloc(size_t num, size_t size)
{
void *const buf = __wrap_malloc(num * size);
if(buf == NULL) return NULL;
memset(buf, 0, num * size);
return buf;
}
void __wrap_free(void *ptr)
{
if(ptr == NULL) return;
if(memcmp(ptr - (16 - sizeof(size_t)), (u8*)__heap_chk_guard + sizeof(size_t), 16 - sizeof(size_t)) != 0)
panicMsg("Heap underflow!");
size_t size;
memcpy(&size, ptr - 16, sizeof(size_t));
// Important! Adjust the size check if needed.
// 1024u * 512 is roughly ok for AXIWRAM.
if(size > (1024u * 512) || memcmp(ptr + size, __heap_chk_guard, 16) != 0)
panicMsg("Heap overflow!");
__real_free(ptr - 16);
}
#endif

View File

@ -1,131 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "asm_macros.h"
.syntax unified
.cpu mpcore
.fpu vfpv2
#define ICACHE_SIZE (0x4000)
#define DCACHE_SIZE (0x4000)
#define CACHE_LINE_SIZE (32)
BEGIN_ASM_FUNC invalidateICache
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 @ Invalidate Entire Instruction Cache, also flushes the branch target cache
@mcr p15, 0, r0, c7, c5, 6 @ Flush Entire Branch Target Cache
mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier
mcr p15, 0, r0, c7, c5, 4 @ Flush Prefetch Buffer
bx lr
END_ASM_FUNC
BEGIN_ASM_FUNC invalidateICacheRange
add r1, r1, r0
bic r0, r0, #(CACHE_LINE_SIZE - 1)
mov r2, #0
invalidateICacheRange_lp:
mcr p15, 0, r0, c7, c5, 1 @ Invalidate Instruction Cache Line (using MVA)
add r0, r0, #CACHE_LINE_SIZE
cmp r0, r1
blt invalidateICacheRange_lp
mcr p15, 0, r2, c7, c5, 6 @ Flush Entire Branch Target Cache
mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier
mcr p15, 0, r2, c7, c5, 4 @ Flush Prefetch Buffer
bx lr
END_ASM_FUNC
BEGIN_ASM_FUNC cleanDCache
mov r0, #0
mcr p15, 0, r0, c7, c10, 0 @ Clean Entire Data Cache
mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier
bx lr
END_ASM_FUNC
BEGIN_ASM_FUNC flushDCache
mov r0, #0
mcr p15, 0, r0, c7, c14, 0 @ Clean and Invalidate Entire Data Cache
mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier
bx lr
END_ASM_FUNC
BEGIN_ASM_FUNC cleanDCacheRange
cmp r1, #DCACHE_SIZE
bhi cleanDCache
add r1, r1, r0
bic r0, r0, #(CACHE_LINE_SIZE - 1)
mov r2, #0
cleanDCacheRange_lp:
mcr p15, 0, r0, c7, c10, 1 @ Clean Data Cache Line (using MVA)
add r0, r0, #CACHE_LINE_SIZE
cmp r0, r1
blt cleanDCacheRange_lp
mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier
bx lr
END_ASM_FUNC
BEGIN_ASM_FUNC flushDCacheRange
cmp r1, #DCACHE_SIZE
bhi flushDCache
add r1, r1, r0
bic r0, r0, #(CACHE_LINE_SIZE - 1)
mov r2, #0
flushDCacheRange_lp:
mcr p15, 0, r0, c7, c14, 1 @ Clean and Invalidate Data Cache Line (using MVA)
add r0, r0, #CACHE_LINE_SIZE
cmp r0, r1
blt flushDCacheRange_lp
mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier
bx lr
END_ASM_FUNC
BEGIN_ASM_FUNC invalidateDCache
mov r0, #0
mcr p15, 0, r0, c7, c6, 0 @ Invalidate Entire Data Cache
mcr p15, 0, r0, c7, c10, 4 @ Data Synchronization Barrier
bx lr
END_ASM_FUNC
BEGIN_ASM_FUNC invalidateDCacheRange
cmp r1, #DCACHE_SIZE
bhi flushDCache
add r1, r1, r0
tst r0, #(CACHE_LINE_SIZE - 1)
mcrne p15, 0, r0, c7, c10, 1 @ Clean Data Cache Line (using MVA)
tst r1, #(CACHE_LINE_SIZE - 1)
mcrne p15, 0, r1, c7, c10, 1 @ Clean Data Cache Line (using MVA)
bic r0, r0, #(CACHE_LINE_SIZE - 1)
mov r2, #0
invalidateDCacheRange_lp:
mcr p15, 0, r0, c7, c6, 1 @ Invalidate Data Cache Line (using MVA)
add r0, r0, #CACHE_LINE_SIZE
cmp r0, r1
blt invalidateDCacheRange_lp
mcr p15, 0, r2, c7, c10, 4 @ Data Synchronization Barrier
bx lr
END_ASM_FUNC

View File

@ -1,760 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 Sergi Granell (xerpi), Paul LaMendola (paulguy), derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Based on code from https://github.com/xerpi/linux_3ds/blob/master/drivers/input/misc/nintendo3ds_codec_hid.c
#include <assert.h>
#include "types.h"
#include "arm11/drivers/codec.h"
#include "arm11/drivers/codec_regmap.h"
#include "arm11/drivers/spi.h"
#include "arm11/drivers/pdn.h"
#include "arm11/drivers/timer.h"
#include "arm11/drivers/gpio.h"
#define LIBN3DS_LEGACY (1) // TODO: Pass this via makefile.
#define SWAP_HALF(b0, b1, a1) __builtin_bswap16(b0),__builtin_bswap16(b1),__builtin_bswap16(a1)
#define SWAP_FULL(b0, b1, b2, a1, a2) __builtin_bswap16(b0),__builtin_bswap16(b1),__builtin_bswap16(b2),__builtin_bswap16(a1),__builtin_bswap16(a2)
typedef enum
{
I2S_LINE_1 = 0u,
I2S_LINE_2 = 1u
} I2sLine;
typedef enum
{
I2S_FREQ_32KHZ = 0u, // 32728.498046875 Hz.
I2S_FREQ_47KHZ = 1u // 47605.08806818181818182 Hz.
} I2sFreq;
typedef enum
{
MIC_FILTER_HALF = 0u,
MIC_FILTER_32KHZ = 1u, // I2S1?
MIC_FILTER_47KHZ = 2u // I2S2?
} MicFilter;
// All coefficients are 16 bit fixed-point numbers.
// 1 sign bit (bit 15) and 15 fraction bits. Big endian.
typedef struct
{
s16 b0;
s16 b1;
// a0 always 1.0.
s16 a1; // Inverted.
} IirBiquadHalf;
typedef struct
{
s16 b0;
s16 b1; // Halved.
s16 b2;
// a0 always 1.0.
s16 a1; // Halved and inverted.
s16 a2; // Inverted.
} IirBiquad; // Second order biquad.
typedef struct
{
IirBiquadHalf half;
IirBiquad biquads[5];
} IirBiquadHalfAnd5Full;
// Caution:
// Don't change the struct layout without
// adjusting swapCalibrationData().
typedef struct
{
u8 driverGainHp;
u8 driverGainSp;
u8 analogVolumeHp;
u8 analogVolumeSp;
s8 shutterVolume[2];
u8 microphoneBias;
u8 quickCharge; // Microphone related.
u8 pgaGain; // Microphone gain.
u8 reserved[3];
IirBiquad filterHp32[3];
IirBiquad filterHp47[3];
IirBiquad filterSp32[3];
IirBiquad filterSp47[3];
IirBiquadHalfAnd5Full filterMic32;
IirBiquadHalfAnd5Full filterMic47;
IirBiquadHalfAnd5Full filterFree;
u8 analogInterval;
u8 analogStabilize;
u8 analogPrecharge;
u8 analogSense;
u8 analogDebounce;
u8 analogXpPullup;
u8 ymDriver;
u8 reserved2;
} CodecCal;
static_assert(offsetof(CodecCal, analogInterval) - offsetof(CodecCal, filterHp32) == 288, "Error: Filters not contiguous in CodecCal!");
alignas(4) static const CodecCal g_fallbackCal =
{
0u, // 0 dB
1u, // 12 dB
0u, // 0 dB
7u, // -3.5 dB
{-3, -20},
3u,
2u,
0u,
{0, 0, 0},
// Note:
// The sample rate used for all filters
// is the word clock of the I2S line.
{ // filterHp32 I2S1.
{SWAP_FULL( 32767, 0, 0, 0, 0)},
{SWAP_FULL( 32767, 0, 0, 0, 0)},
{SWAP_FULL( 32736, -16368, 0, 16352, 0)} // First order 10 Hz highpass at 32730 Hz.
},
{ // filterHp47 I2S2.
{SWAP_FULL( 32767, 0, 0, 0, 0)},
{SWAP_FULL( 32767, 0, 0, 0, 0)},
{SWAP_FULL( 32745, -16372, 0, 16361, 0)} // First order 10 Hz highpass at 47610 Hz.
},
{ // filterSp32 I2S1.
{SWAP_FULL( 32767, -27535, 22413, 30870, -29096)}, // Customized peak filter with negative offset?
{SWAP_FULL(-14000, 30000, -14000, 0, 0)}, // Customized high shelf filter?
{SWAP_FULL( 32736, -16368, 0, 16352, 0)} // First order 10 Hz highpass at 32730 Hz.
},
{ // filterSp47 I2S2.
{SWAP_FULL( 32767, -28995, 25277, 31456, -30200)}, // Customized peak filter with negative offset?
{SWAP_FULL(-14402, 30000, -14402, 0, 0)}, // Customized high shelf filter?
{SWAP_FULL( 32745, -16372, 0, 16361, 0)} // First order 10 Hz highpass at 47610 Hz.
},
{ // filterMic32 I2S1?
{SWAP_HALF( 32767, 0, 0)},
{
{SWAP_FULL( 32767, 0, 0, 0, 0)},
{SWAP_FULL( 32767, 0, 0, 0, 0)},
{SWAP_FULL( 32767, 0, 0, 0, 0)},
{SWAP_FULL( 32767, 0, 0, 0, 0)},
{SWAP_FULL( 32767, 0, 0, 0, 0)}
}
},
{ // filterMic47 I2S2?
{SWAP_HALF( 32767, 0, 0)},
{
{SWAP_FULL( 32767, 0, 0, 0, 0)},
{SWAP_FULL( 32767, 0, 0, 0, 0)},
{SWAP_FULL( 32767, 0, 0, 0, 0)},
{SWAP_FULL( 32767, 0, 0, 0, 0)},
{SWAP_FULL( 32767, 0, 0, 0, 0)}
}
},
{ // filterFree all I2S lines.
{SWAP_HALF( 32767, 0, 0)},
{
{SWAP_FULL(-12959, -8785, 32767, 8785, 12959)}, // Phase correction?
{SWAP_FULL(-12959, -8785, 32767, 8785, 12959)}, // Phase correction?
{SWAP_FULL(-12959, -8785, 32767, 8785, 12959)}, // Phase correction?
{SWAP_FULL( 32767, 0, 0, 0, 0)},
{SWAP_FULL( 32767, 0, 0, 0, 0)},
}
},
1u,
9u,
4u,
3u,
0u,
6u,
1u,
0u
};
static void switchPage(u16 pageReg)
{
pageReg >>= 8;
static u8 currentPage = 0x63;
if(currentPage != pageReg)
{
currentPage = pageReg;
alignas(4) u8 inBuf[4];
inBuf[0] = CDC_REG_PAGE_CTRL; // Bit 0: 0 = write, 1 = read.
inBuf[1] = pageReg;
NSPI_writeRead(NSPI_DEV_CS_HIGH | NSPI_DEV_CTR_CODEC, (u32*)inBuf, NULL, 2, 0);
}
}
static void readRegBuf(u16 pageReg, u32 *buf, u32 size)
{
switchPage(pageReg);
alignas(4) u8 inBuf[4];
inBuf[0] = pageReg<<1 | 1u; // Bit 0: 0 = write, 1 = read.
NSPI_writeRead(NSPI_DEV_CS_HIGH | NSPI_DEV_CTR_CODEC, (u32*)inBuf, buf, 1, size);
}
static u8 readReg(u16 pageReg)
{
alignas(4) u8 outBuf[4];
readRegBuf(pageReg, (u32*)outBuf, 1);
return outBuf[0];
}
static void writeRegBuf(u16 pageReg, u32 *buf, u32 size)
{
switchPage(pageReg);
alignas(4) u8 inBuf[4];
inBuf[0] = pageReg<<1; // Bit 0: 0 = write, 1 = read.
NSPI_writeRead(NSPI_DEV_CTR_CODEC, (u32*)inBuf, NULL, 1, 0);
NSPI_writeRead(NSPI_DEV_CS_HIGH | NSPI_DEV_CTR_CODEC, buf, NULL, size, 0);
}
static void writeReg(u16 pageReg, u8 val)
{
switchPage(pageReg);
alignas(4) u8 inBuf[4];
inBuf[0] = pageReg<<1; // Bit 0: 0 = write, 1 = read.
inBuf[1] = val;
NSPI_writeRead(NSPI_DEV_CS_HIGH | NSPI_DEV_CTR_CODEC, (u32*)inBuf, NULL, 2, 0);
}
#ifdef LIBN3DS_LEGACY
static void writeRegPowerman(u8 reg, u8 val)
{
alignas(4) u8 inBuf[4];
inBuf[0] = reg & 0x7Fu; // Bit 7: 0 = write, 1 = read.
inBuf[1] = val;
NSPI_writeRead(NSPI_DEV_CS_HIGH | NSPI_DEV_POWERMAN, (u32*)inBuf, NULL, 2, 0);
}
#endif
static void maskReg(u16 pageReg, u8 val, u8 mask)
{
u8 data = readReg(pageReg);
data = (data & ~mask) | (val & mask);
writeReg(pageReg, data);
}
static void maskWaitReg(u16 pageReg, u8 val, u8 mask)
{
for(u32 i = 0; i < 64; i++) // Some kind of timeout? No error checking.
{
maskReg(pageReg, val, mask);
if((readReg(pageReg) & mask) == val) break;
}
}
// Helpers
/*static void swapCalibrationData(CodecCal *cal)
{
// Caution: This relies on struct layout.
const u32 size = (sizeof(IirBiquad) * 3 * 4 + sizeof(IirBiquadHalfAnd5Full) * 3) / 2;
u16 *tmp = (u16*)cal->filterHp32;
for(u32 i = 0; i < size; i++)
{
tmp[i] = __builtin_bswap16(tmp[i]);
}
}*/
static inline void pdnControlMclk(bool enable)
{
// CODEC MCLK output enable(s).
// CODEC is only connected to clock 2.
getPdnRegs()->i2s_cnt = (enable ? PDN_I2S_CNT_I2S_CLK2_EN : 0);
}
static void softReset(void)
{
writeReg(CDC_REG_SOFT_RST_CTR, 1);
TIMER_sleepMs(40);
switchPage(0); // What? Dummy switch after reset?
}
static inline void setI2sFreq(I2sLine i2sLine, I2sFreq freq)
{
if(i2sLine == I2S_LINE_1) // I2S1
{
u8 val;
if(freq == I2S_FREQ_32KHZ) val = 0x87;
else val = 0x85;
writeReg(CDC_REG_DAC_NDAC_VAL, val);
}
else // I2S2
{
u8 val;
if(freq == I2S_FREQ_32KHZ) val = 1;
else val = 0;
maskReg(CDC_REG_100_124, val, 1);
}
}
// TODO: Make this available as public API?
static void setIirFilterMic(MicFilter filter, const void *const coeff)
{
u16 pageReg;
u32 size;
switch(filter)
{
case MIC_FILTER_HALF:
{
pageReg = 4<<8 | 8;
size = sizeof(IirBiquadHalf);
break;
}
case MIC_FILTER_32KHZ:
{
pageReg = 5<<8 | 8;
size = sizeof(IirBiquadHalfAnd5Full);
break;
}
case MIC_FILTER_47KHZ:
{
pageReg = 5<<8 | 72;
size = sizeof(IirBiquadHalfAnd5Full);
break;
}
default:
return;
}
writeRegBuf(pageReg, (u32*)coeff, size);
}
static inline bool isDacMuted(I2sLine i2sLine)
{
if(i2sLine == I2S_LINE_1)
return (~readReg(CDC_REG_DAC_VOLUME_CTRL) & 0xCu) == 0; // I2S1
else
return (~readReg(CDC_REG_100_119) & 0xCu) == 0; // I2S2
}
static void muteUnmuteDac(I2sLine i2sLine, bool mute)
{
if(i2sLine == I2S_LINE_1) // I2S1
{
maskReg(CDC_REG_DAC_DATA_PATH_SETUP, (mute ? 0u : 0xC0u), 0xC0);
writeReg(CDC_REG_DAC_VOLUME_CTRL, (mute ? 0xCu : 0));
}
else // I2S2
{
maskReg(CDC_REG_100_119, (mute ? 0xCu : 0u), 0xC);
}
if(mute)
{
// Wait until muted.
const u8 waitVal = (i2sLine == I2S_LINE_1 ? 0x44u : 0x88u);
for(u32 i = 0; i < 100; i++) // Some kind of timeout? No error checking.
{
if(!(~readReg(CDC_REG_100_38) & waitVal)) break;
TIMER_sleepMs(1);
}
}
}
/*static void setIirFilterSound(u8 type, const void *const coeff)
{
}*/
static void powerOnDac(void)
{
// Power on DAC.
maskReg(CDC_REG_100_118, 0xC0, 0xC0);
// 10 ms wait time for safety?
TIMER_sleepMs(10);
// Also check the flags for extra safety.
for(u32 i = 0; i < 100; i++)
{
if(!(~readReg(CDC_REG_100_37) & 0x88u)) break;
TIMER_sleepMs(1);
}
}
static void enableTouchscreen(void)
{
maskReg(CDC_REG_103_38, 0x80, 0x80);
maskReg(CDC_REG_103_36, 0, 0x80);
maskReg(CDC_REG_103_37, 0x10, 0x3C);
}
static void disableTouchscreen(void)
{
maskReg(CDC_REG_103_38, 0, 0x80);
maskReg(CDC_REG_103_36, 0x80, 0x80);
}
static void legacyTouchscreenMode(bool enabled)
{
if(enabled)
{
*((vu16*)0x10141114) |= 2u;
*((vu16*)0x10141116) |= 2u;
maskReg(CDC_REG_103_37, 0x40, 0x40);
}
else
{
maskReg(CDC_REG_103_37, 0, 0x40);
*((vu16*)0x10141114) &= ~2u;
}
}
// TODO: Implement manual output switching or fix auto switching.
static void headsetInit(void)
{
// Headset detection stuff.
GPIO_config(GPIO_2_HEADPH_JACK, GPIO_IRQ_RISING | GPIO_INPUT); // Headphone jack IRQ.
//maskReg(CDC_REG_HEADSET_SEL, GPIO_read(GPIO_2_HEADPH_JACK)<<HEADSET_SEL_HP_SHIFT | HEADSET_SEL_HP_EN, 0x30); // GPIO bitmask 8.
maskReg(CDC_REG_HEADSET_SEL, 0, 0x30); // With automatic output switching.
maskReg(CDC_REG_100_67, 0, 0x80); // TODO: Can we remove this?
maskReg(CDC_REG_100_67, 0x80, 0x80);
}
static void microphoneInit(const CodecCal *const cal)
{
// Microphone ADC output select stuff.
maskReg(CDC_REG_100_34, 0, 4);
// 10 Hz highpass for 32730 Hz.
alignas(4) static const IirBiquadHalf highPass10Hz = {SWAP_HALF(32737, -32737, 32705)};
setIirFilterMic(MIC_FILTER_HALF, &highPass10Hz);
setIirFilterMic(MIC_FILTER_32KHZ, &cal->filterMic32);
setIirFilterMic(MIC_FILTER_47KHZ, &cal->filterMic47);
// Microphone impedance settings.
maskReg(CDC_REG_ADC_IN_SEL_FOR_P_TERMINAL, 0x40, 0xC0);
maskReg(CDC_REG_ADC_IN_SEL_FOR_M_TERMINAL, 0x40, 0xC0);
// Microphone bias voltage.
writeReg(CDC_REG_101_51, cal->microphoneBias);
// Microphone gain correction.
maskWaitReg(CDC_REG_101_65, cal->pgaGain, 0x3F);
// Quick charge? What does that even mean here?
maskWaitReg(CDC_REG_101_66, cal->quickCharge, 3);
// Microphone PGA.
writeReg(CDC_REG_MIC_PGA, 43u & 0x7Fu); // TODO: Should be a global function?
}
static void shutterSoundInit(const CodecCal *const cal)
{
// I2S mute and volume settings on shutter sound playback.
maskReg(CDC_REG_100_49, 0x44, 0x44); // TODO: TwlBg/AgbBg uses val = 0 here.
// I2S1 volumes.
writeReg(CDC_REG_DAC_L_VOLUME_CTRL, cal->shutterVolume[0]);
writeReg(CDC_REG_DAC_R_VOLUME_CTRL, cal->shutterVolume[0]);
// I2S2 volume.
writeReg(CDC_REG_100_123, cal->shutterVolume[1]);
}
static void soundInit(const CodecCal *const cal)
{
// TODO: Depop circuit stuff is CTR only.
// Speaker depop. Probably to suppress the noise when the driver turns on.
// But this doesn't stop the pop noise on o3DS (CTR) at all?
GPIO_config(GPIO_3_0, GPIO_OUTPUT);
GPIO_write(GPIO_3_0, 1); // GPIO bitmask 0x40
TIMER_sleepMs(10); // Fixed 10 ms delay when setting this GPIO.
// TODO: Clean this up.
// Before enabling the I2S interfaces make sure they are fully
// off so we can write to all bits in these registers.
*((vu16*)0x10145000) = 0;
*((vu16*)0x10145002) = 0;
// Bit 14 is MCLK1 multiplier (8 and 16 MHz)? I2S1: DSP and GBA 32728.498046875 Hz.
*((vu16*)0x10145000) = 1u<<15 | 2u<<13 | 32u<<6;
// Bit 14 is MCLK2 multiplier (8 and 16 MHz)? I2S2: CSND 47605.08806818181818182 Hz.
*((vu16*)0x10145002) = 1u<<15 | 3u<<13;
// Speaker driver powerup time?
maskReg(CDC_REG_101_17, 0x10, 0x1C);
// I2S1 volume?
writeReg(CDC_REG_100_122, 0);
// I2S2 volume?
writeReg(CDC_REG_100_120, 0);
// TODO: Function for setting sound filters.
{
// Missing in Twl-/AgbBg but present in codec module.
// Omiting these filters actually makes sound slightly worse for GBA mode.
const bool dacMuted = isDacMuted(I2S_LINE_1);
muteUnmuteDac(I2S_LINE_1, true); // Mute.
writeRegBuf(9<<8 | 2, (u32*)&cal->filterFree.half, 6);
writeRegBuf(8<<8 | 12, (u32*)cal->filterFree.biquads, 50);
writeRegBuf(9<<8 | 8, (u32*)&cal->filterFree.half, 6);
writeRegBuf(8<<8 | 76, (u32*)cal->filterFree.biquads, 50);
if(!dacMuted) muteUnmuteDac(I2S_LINE_1, false); // Unmute.
}
{
const bool dacMuted = isDacMuted(I2S_LINE_2);
muteUnmuteDac(I2S_LINE_2, true); // Mute.
writeRegBuf(10<<8 | 2, (u32*)&cal->filterFree.half, 6);
writeRegBuf(10<<8 | 12, (u32*)cal->filterFree.biquads, 50);
if(!dacMuted) muteUnmuteDac(I2S_LINE_2, true); // Unmute.
}
writeRegBuf(12<<8 | 2, (u32*)cal->filterSp32, 30);
writeRegBuf(12<<8 | 66, (u32*)cal->filterSp32, 30);
writeRegBuf(12<<8 | 32, (u32*)cal->filterSp47, 30);
writeRegBuf(12<<8 | 96, (u32*)cal->filterSp47, 30);
writeRegBuf(11<<8 | 2, (u32*)cal->filterHp32, 30);
writeRegBuf(11<<8 | 66, (u32*)cal->filterHp32, 30);
writeRegBuf(11<<8 | 32, (u32*)cal->filterHp47, 30);
writeRegBuf(11<<8 | 96, (u32*)cal->filterHp47, 30);
// Power on DAC?
powerOnDac();
// Route DAC?
writeReg(CDC_REG_101_10, 0xA);
// TODO: Can we omit this since the DACs should already be unmuted?
muteUnmuteDac(I2S_LINE_1, false); // Unmute I2S1.
muteUnmuteDac(I2S_LINE_2, false); // Unmute I2S2.
{ // Headphone.
// Power on headphone driver?
// Different settings depending on vendor and revision?
// It seems we have 2 vendors and 3 revisions. Revsions: 1=B?, 2=C?, 3=D?
u8 val;
if((readReg(CDC_REG_0_2) & 0xFu) <= 1u && ((readReg(CDC_REG_0_3) & 0x70u)>>4 <= 2u))
{
val = 0x3C;
}
else val = 0x1C;
writeReg(CDC_REG_101_11, val);
// Unmute headphone driver?
writeReg(CDC_REG_101_12, (cal->driverGainHp<<3) | 4);
// Set/unmute analog volume?
// TODO: We can combine these reg writes.
writeReg(CDC_REG_101_22, cal->analogVolumeHp); // Left?
writeReg(CDC_REG_101_23, cal->analogVolumeHp); // Right?
}
{ // Speaker.
// Power on speaker driver?
maskReg(CDC_REG_101_17, 0xC0, 0xC0);
// Unmute speaker driver?
// TODO: We can combine these reg writes.
writeReg(CDC_REG_101_18, (cal->driverGainSp<<2) | 2); // Left?
writeReg(CDC_REG_101_19, (cal->driverGainSp<<2) | 2); // Right?
// // Set/unmute analog volume?
writeReg(CDC_REG_101_27, cal->analogVolumeSp);
writeReg(CDC_REG_101_28, cal->analogVolumeSp);
}
// Some delay waiting for headphone and speaker
// outputs to be fully up and running?
TIMER_sleepMs(38);
// TODO: Depop circuit stuff is CTR only.
// Speaker depop. Probably to suppress the noise when the driver turns on.
// But this doesn't stop the pop noise on o3DS (CTR) at all?
GPIO_write(GPIO_3_0, 0); // GPIO bitmask 0x40
TIMER_sleepMs(18); // Fixed 18 ms delay when unsetting this GPIO.
}
static void touchAndCirclePadInit(const CodecCal *const cal)
{
// Stop conversion/sampling?
writeReg(CDC_REG_103_36, 0x98);
writeReg(CDC_REG_103_38, 0x00);
writeReg(CDC_REG_103_37, 0x43);
writeReg(CDC_REG_103_36, 0x18);
writeReg(CDC_REG_103_23, cal->analogPrecharge<<4 | cal->analogSense);
writeReg(CDC_REG_103_25, cal->analogXpPullup<<4 | cal->analogStabilize);
writeReg(CDC_REG_103_27, cal->ymDriver<<7 | cal->analogDebounce);
writeReg(CDC_REG_103_39, 0x10u | cal->analogInterval);
writeReg(CDC_REG_103_38, 0xEC);
writeReg(CDC_REG_103_36, 0x18);
writeReg(CDC_REG_103_37, 0x53);
// Not needed?
// Console dependent.
//I2C_writeReg(I2C_DEV_CTR_MCU, 0x26, I2C_readReg(I2C_DEV_CTR_MCU, 0x26) | 0x10);
// TODO: This should be called externally.
enableTouchscreen();
}
#ifdef LIBN3DS_LEGACY
static void legacyWorkaround(void)
{
// CODEC emulates the old DS power management chip.
// Looks like there is a bug where it doesn't generate
// IRQs if these regs are not properly initialized.
writeRegPowerman(0u, 0u);
writeRegPowerman(4u, 0u);
writeRegPowerman(16u, 0u);
writeRegPowerman(0u, 0x0Cu); // Triggers IRQ?
}
#endif
void CODEC_init(void)
{
static bool inited = false;
if(inited) return;
inited = true;
NSPI_init();
// TODO: Load calibration from HWCAL files on eMMC.
const CodecCal *const cal = &g_fallbackCal;
// Turn on CODEC MCLK and reset it.
pdnControlMclk(true); // Enable MCLK.
softReset();
// Headset detection timing stuff.
writeReg(CDC_REG_100_67, 0x11);
maskReg(CDC_REG_101_119, 1, 1);
// Don't force speaker output.
maskReg(CDC_REG_GPI1_GPI2_PIN_CTRL, 0x66, 0x66);
// VREF stuff.
writeReg(CDC_REG_101_122, 1);
// PLL stuff.
maskReg(CDC_REG_100_34, 0x18, 0x18);
headsetInit();
// Set CODEC side I2S frequencies (dividers?).
setI2sFreq(I2S_LINE_1, I2S_FREQ_32KHZ);
setI2sFreq(I2S_LINE_2, I2S_FREQ_47KHZ);
microphoneInit(cal);
shutterSoundInit(cal);
soundInit(cal);
touchAndCirclePadInit(cal);
// TODO: For TWL legacy mode we need to set some uninitialized regs here (bug workaround?).
// We also need to watch for a certain GPIO to detect the TWL side
// changing I2S frequency.
#ifdef LIBN3DS_LEGACY
legacyWorkaround();
#endif
}
bool g_touchscreenState = false;
bool g_legacySwitchState = false;
void CODEC_deinit(void)
{
GPIO_write(GPIO_3_0, 1); // GPIO bitmask 0x40
TIMER_sleepMs(10); // Fixed 10 ms delay when setting this GPIO.
g_legacySwitchState = (readReg(CDC_REG_103_37) & 0x40u) != 0;
if(!g_legacySwitchState) legacyTouchscreenMode(true);
maskReg(CDC_REG_103_37, 0, 3);
g_touchscreenState = (readReg(CDC_REG_103_36)>>7) == 0;
disableTouchscreen();
maskReg(CDC_REG_100_118, 0, 0xC0);
TIMER_sleepMs(30);
for(u32 i = 0; i < 100; i++)
{
if(!(readReg(CDC_REG_100_37) & 0x88u)) break;
TIMER_sleepMs(1);
}
maskReg(CDC_REG_100_34, 2, 2);
TIMER_sleepMs(30);
for(u32 i = 0; i < 64; i++)
{
if(readReg(CDC_REG_100_34) & 1u) break;
TIMER_sleepMs(1);
}
*((vu16*)0x10145000) &= ~0x8000u;
*((vu16*)0x10145002) &= ~0x8000u;
getPdnRegs()->i2s_cnt = 0;
GPIO_write(GPIO_3_0, 0); // GPIO bitmask 0x40
TIMER_sleepMs(18); // Fixed 18 ms delay when unsetting this GPIO.
}
void CODEC_wakeup(void)
{
GPIO_write(GPIO_3_0, 1); // GPIO bitmask 0x40
TIMER_sleepMs(10); // Fixed 10 ms delay when setting this GPIO.
getPdnRegs()->i2s_cnt = PDN_I2S_CNT_I2S_CLK2_EN;
*((vu16*)0x10145000) |= 0x8000u;
*((vu16*)0x10145002) |= 0x8000u;
//maskReg(0x64, 0x45, 0, 0x30); // Output select automatic
maskReg(CDC_REG_100_67, 0, 0x80);
maskReg(CDC_REG_100_67, 0x80, 0x80);
maskReg(CDC_REG_100_34, 0, 2);
TIMER_sleepMs(40);
for(u32 i = 0; i < 40; i++)
{
if(!(readReg(CDC_REG_100_34) & 1u)) break;
TIMER_sleepMs(1);
}
maskReg(CDC_REG_100_118, 0xC0, 0xC0);
TIMER_sleepMs(10);
for(u32 i = 0; i < 100; i++)
{
if(!(~readReg(CDC_REG_100_37) & 0x88u)) break;
TIMER_sleepMs(1);
}
maskReg(CDC_REG_103_37, 3, 3);
legacyTouchscreenMode(g_legacySwitchState);
if(g_touchscreenState) enableTouchscreen();
GPIO_write(GPIO_3_0, 0); // GPIO bitmask 0x40
TIMER_sleepMs(18); // Fixed 18 ms delay when unsetting this GPIO.
}
bool CODEC_getRawAdcData(CdcAdcData *data)
{
if((readReg(CDC_REG_103_38) & 2u) == 0)
{
readRegBuf(251<<8 | 1, (u32*)data, sizeof(CdcAdcData));
return true;
}
// Codec module does this when data is unavailable. Why?
//switchPage(0);
return false;
}

View File

@ -1,72 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "arm11/drivers/csnd.h"
#include "arm11/drivers/codec.h"
void CSND_init(void)
{
static bool inited = false;
if(inited) return;
inited = true;
CODEC_init();
//static const u8 sliderBounds[2] = {0xE, 0xF6}; // Volume slider 0% and 100% offset
//I2C_writeRegBuf(I2C_DEV_CTR_MCU, 0x58, sliderBounds, 2);
Csnd *const csnd = getCsndRegs();
csnd->master_vol = 0x8000;
csnd->unk_cnt = 1u<<15 | 1u<<14;
// Stop all channels.
CsndCh *const csndCh = csnd->ch;
for(u32 i = 0; i < 32; i++) csndCh[i].cnt = 0;
// Stop all captures.
CsndCap *const csndCap = csnd->cap;
csndCap[0].cnt = 0;
csndCap[1].cnt = 0;
}
void CSND_setupCh(u8 ch, s16 srFreq, u32 vol, const u32 *const data, const u32 *const data2, u32 size, u16 flags)
{
CsndCh *const csndCh = getCsndChRegs(ch);
csndCh->sr = srFreq;
csndCh->vol = vol;
csndCh->capvol = vol;
csndCh->st_addr = (u32)data;
csndCh->size = size;
csndCh->lp_addr = (u32)data2;
csndCh->st_adpcm = 0; // TODO: Hardcoded for now.
csndCh->lp_adpcm = 0; // TODO: Hardcoded for now.
csndCh->cnt = CSND_CH_START | flags; // Start in paused state.
}
void CSND_startCap(u8 ch, s16 sr, u32 *const data, u32 size, u16 flags)
{
CsndCap *const csndCap = getCsndCapRegs(ch);
csndCap->sr = sr;
csndCap->size = size;
csndCap->addr = (u32)data;
csndCap->cnt = CSND_CAP_START | flags;
}

View File

@ -1,100 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "asm_macros.h"
#include "arm.h"
#include "mem_map.h"
.syntax unified
.cpu mpcore
.fpu vfpv2
.macro EXCEPTION_ENTRY name, type
BEGIN_ASM_FUNC \name
msr cpsr_f, #\type @ Abuse conditional flags in cpsr for temporary exception type storage
b exceptionHandler
END_ASM_FUNC
.endm
EXCEPTION_ENTRY undefInstrHandler, 0<<29
EXCEPTION_ENTRY prefetchAbortHandler, 1<<29
EXCEPTION_ENTRY dataAbortHandler, 2<<29
BEGIN_ASM_FUNC exceptionHandler
sub sp, #84
stmia sp, {r0-r14}^ @ Save all user/system mode regs except pc
mrs r2, spsr @ Get saved cpsr
mrs r3, cpsr
lsr r0, r3, #29 @ Get back the exception type from cpsr
and r1, r2, #PSR_MODE_MASK
cmp r1, #PSR_USER_MODE
beq exceptionHandler_skip_other_mode
add r4, sp, #32
msr cpsr_c, r2
stmia r4!, {r8-r14} @ Some regs are written twice but we don't care
msr cpsr_c, r3
exceptionHandler_skip_other_mode:
str lr, [sp, #60] @ Save lr (pc) on exception stack
str r2, [sp, #64] @ Save spsr (cpsr) on exception stack
mrc p15, 0, r3, c5, c0, 0
str r3, [sp, #68] @ DFSR
mrc p15, 0, r3, c5, c0, 1
str r3, [sp, #72] @ IFSR
mrc p15, 0, r3, c6, c0, 0
str r3, [sp, #76] @ FAR
mrc p15, 0, r3, c6, c0, 1
str r3, [sp, #80] @ WFAR
mov r4, r0
mov r5, sp
bl deinitCpu
mov r0, r4
mov sp, r5
mov r1, r5
b guruMeditation @ r0 = exception type, r1 = reg dump ptr {r0-r14, pc (unmodified), CPSR, DFSR, IFSR, FAR, WFAR}
END_ASM_FUNC
BEGIN_ASM_FUNC irqHandler
sub lr, lr, #4
srsfd sp!, #PSR_SYS_MODE @ Store lr and spsr on system mode stack
cps #PSR_SYS_MODE
stmfd sp!, {r0-r3, r12, lr}
ldr r12, =MPCORE_PRIV_REG_BASE
ldr r2, =g_irqIsrTable
ldr r0, [r12, #0x10C] @ REG_GIC_CPU_INTACK
and r1, r0, #0x7F
cmp r1, #32
mrclo p15, 0, r3, c0, c0, 5 @ Get CPU ID
andlo r3, r3, #3
addlo r1, r1, r3, lsl #5
addhs r1, r1, #96
ldr r3, [r2, r1, lsl #2]
cmp r3, #0
beq irqHandler_skip_processing
cpsie i
str r0, [sp, #-4]! @ A single ldr/str can't be interrupted
blx r3
ldr r0, [sp], #4
ldr r12, =MPCORE_PRIV_REG_BASE
cpsid i
irqHandler_skip_processing:
str r0, [r12, #0x110] @ REG_GIC_CPU_EOI
ldmfd sp!, {r0-r3, r12, lr}
rfefd sp! @ Restore lr (pc) and spsr (cpsr)
END_ASM_FUNC

View File

@ -1,533 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string.h>
#include <stdatomic.h>
#include "types.h"
#include "fb_assert.h"
#include "drivers/gfx.h"
#include "arm11/drivers/cfg11.h"
#include "arm11/drivers/pdn.h"
#include "arm11/drivers/lcd.h"
#include "arm11/drivers/gx.h"
#include "arm11/drivers/gpu_regs.h"
#include "mem_map.h"
#include "mmio.h"
#include "arm11/drivers/i2c.h"
#include "arm11/drivers/mcu.h"
#include "arm11/debug.h"
#include "arm11/drivers/interrupt.h"
#include "arm11/drivers/timer.h"
#include "arm.h"
#include "util.h"
#include "arm11/allocator/vram.h"
#include "kevent.h"
#define MCU_LCD_IRQ_MASK (MCU_IRQ_TOP_BL_ON | MCU_IRQ_TOP_BL_OFF | \
MCU_IRQ_BOT_BL_ON | MCU_IRQ_BOT_BL_OFF | \
MCU_IRQ_LCD_POWER_ON | MCU_IRQ_LCD_POWER_OFF)
static struct
{
u32 swap; // Currently active framebuffer.
void *framebufs[2][4]; // For each screen A1, A2, B1, B2
KHandle events[6];
u8 doubleBuf[2]; // Top, bottom, 1 = enable.
u8 lcdPower; // 1 = on. Bit 4 top light, bit 2 bottom light, bit 0 LCDs.
u8 lcdLights[2]; // LCD backlight brightness. Top, bottom.
u32 formats[2]; // Top, bottom
u16 strides[2]; // Top, bottom
} g_gfxState = {0};
static u8 fmt2PixSize(GfxFbFmt fmt);
static void setupFramebufs(GfxFbFmt fmtTop, GfxFbFmt fmtBot);
static void deallocFramebufs(void);
static void setupDislayController(u8 lcd);
void GFX_init(GfxFbFmt fmtTop, GfxFbFmt fmtBot)
{
g_gfxState.lcdPower = 0x15; // All on.
setupFramebufs(fmtTop, fmtBot);
g_gfxState.doubleBuf[0] = 1;
g_gfxState.doubleBuf[1] = 1;
// FIXME: Temporary workaround for screen init compatibility (Luma/fb3DS 1.2).
TIMER_sleepMs(50);
(void)MCU_getIrqs(MCU_LCD_IRQ_MASK); // Discard any screen init events.
getCfg11Regs()->gpuprot = GPUPROT_NO_PROT;
// Reset the whole GX block.
Pdn *const pdn = getPdnRegs();
pdn->gpu_cnt = PDN_GPU_CNT_CLK_EN;
wait_cycles(12);
pdn->gpu_cnt = PDN_GPU_CNT_CLK_EN | PDN_GPU_CNT_NORST_ALL;
REG_GX_GPU_CLK = 0x100; // P3D
REG_GX_PSC_VRAM = 0; // All VRAM banks enabled.
// These 3 reg writes are normally done way later in the
// init but we will be fine doing it early.
REG_GX_PSC_FILL0_CNT = 0;
REG_GX_PSC_FILL1_CNT = 0;
REG_GX_PPF_CNT = 0;
// PDC/framebuffer setup. This must be done before LCD init.
setupDislayController(0);
setupDislayController(1);
REG_LCD_PDC0_SWAP = 0; // Select framebuf 0.
REG_LCD_PDC1_SWAP = 0; // Select framebuf 0.
REG_LCD_PDC0_CNT = PDC_CNT_OUT_E | PDC_CNT_I_MASK_ERR | PDC_CNT_I_MASK_H | PDC_CNT_E; // Start
REG_LCD_PDC1_CNT = PDC_CNT_OUT_E | PDC_CNT_I_MASK_ALL | PDC_CNT_E; // Start
// LCD reg setup.
REG_LCD_ABL0_FILL = 1u<<24; // Force blackscreen.
REG_LCD_ABL1_FILL = 1u<<24; // Force blackscreen.
REG_LCD_PARALLAX_CNT = 0;
REG_LCD_PARALLAX_PWM = 0xA390A39;
REG_LCD_RST = 0; // Reset LCD drivers. Unknown for how long this must be low.
// GSP seems to rely on boot11/previous FIRM having set it to 0 already.
REG_LCD_UNK00C = 0x10001; // Stops H-/V-sync control signals?
// Create IRQ events.
// PSC0, PSC1, PDC0, PDC1, PPF, P3D
for(u8 i = 0; i < 6; i++)
{
KHandle tmp = createEvent(false);
bindInterruptToEvent(tmp, IRQ_PSC0 + i, 14);
g_gfxState.events[i] = tmp;
}
// Clear entire VRAM.
GX_memoryFill((u32*)VRAM_BANK0, 1u<<9, VRAM_SIZE / 2, 0,
(u32*)VRAM_BANK1, 1u<<9, VRAM_SIZE / 2, 0);
// Backlight and other stuff.
REG_LCD_ABL0_LIGHT = 0;
REG_LCD_ABL0_CNT = 0;
REG_LCD_ABL0_LIGHT_PWM = 0;
REG_LCD_ABL1_LIGHT = 0;
REG_LCD_ABL1_CNT = 0;
REG_LCD_ABL1_LIGHT_PWM = 0;
// Timing critical part start.
// This must be done within 4 frames.
REG_LCD_RST = 1; // Take LCD drivers out of reset.
// At this point the output must be forced black or
// the LCD drivers will not sync. Already done above.
REG_LCD_UNK00C = 0; // Starts H-/V-sync control signals?
TIMER_sleepMs(10); // Wait for power supply (which?) to stabilize and LCD drivers to finish resetting.
LCDI2C_init(); // Initialize LCD drivers.
MCU_setLcdPower(2u); // Power on LCDs (MCU --> PMIC).
// Timing critical part end.
// Wait 50 us for LCD sync. The MCU event wait will cover this.
if(MCU_waitIrqs(MCU_LCD_IRQ_MASK) != MCU_IRQ_LCD_POWER_ON) panic();
// The transfer engine is (sometimes) borked on screen init.
// Doing a dummy texture copy fixes it.
// TODO: Proper fix.
//GX_textureCopy((u32*)RENDERBUF_TOP, 0, (u32*)RENDERBUF_BOT, 0, 16);
LCDI2C_waitBacklightsOn();
REG_LCD_ABL0_LIGHT_PWM = 0x1023E; // TODO: Figure out how this works.
REG_LCD_ABL0_LIGHT = 1;
REG_LCD_ABL1_LIGHT_PWM = 0x1023E; // TODO: Figure out how this works.
REG_LCD_ABL1_LIGHT = 1;
MCU_setLcdPower(0x28u); // Power on backlights.
if(MCU_waitIrqs(MCU_LCD_IRQ_MASK) != (MCU_IRQ_TOP_BL_ON | MCU_IRQ_BOT_BL_ON)) panic();
// Make sure the fills finished.
GFX_waitForPSC0();
GFX_waitForPSC1();
REG_LCD_ABL0_FILL = 0;
REG_LCD_ABL1_FILL = 0;
// GPU stuff.
REG_GX_GPU_CLK = 0x70100;
*((vu32*)0x10400050) = 0x22221200;
*((vu32*)0x10400054) = 0xFF2;
REG_GX_P3D(GPUREG_IRQ_ACK) = 0;
REG_GX_P3D(GPUREG_IRQ_CMP) = 0x12345678;
REG_GX_P3D(GPUREG_IRQ_MASK) = 0xFFFFFFF0;
REG_GX_P3D(GPUREG_IRQ_AUTOSTOP) = 1;
// This reg needs to be set to 1 (configuration)
// before running the first cmd list.
REG_GX_P3D(GPUREG_START_DRAW_FUNC0) = 1;
}
void GFX_deinit(void)
{
// Power off backlights if on.
const u8 power = g_gfxState.lcdPower;
if(power & ~1u)
{
MCU_setLcdPower(power & ~1u);
if(MCU_waitIrqs(MCU_LCD_IRQ_MASK) != (u32)(power & ~1u)<<24) panic();
}
GFX_setBrightness(0, 0);
REG_LCD_ABL0_LIGHT_PWM = 0;
REG_LCD_ABL1_LIGHT_PWM = 0;
// Make sure the LCDs are completely black.
REG_LCD_ABL0_FILL = 1u<<24; // Force blackscreen.
REG_LCD_ABL1_FILL = 1u<<24; // Force blackscreen.
GFX_waitForVBlank0();
GFX_waitForVBlank0();
// Reset the LCD drivers.
// And stop the H-/V-sync control signals?
REG_LCD_RST = 0;
REG_LCD_UNK00C = 0x10001;
// Power off LCDs if on.
if(power & 1u)
{
MCU_setLcdPower(1u);
if(MCU_waitIrqs(MCU_LCD_IRQ_MASK) != MCU_IRQ_LCD_POWER_OFF) panic();
}
// TODO: Wait until PDC is not reading any data from mem.
REG_LCD_PDC0_CNT = PDC_CNT_I_MASK_ALL; // Stop
REG_LCD_PDC0_SWAP = PDC_SWAP_RST_FIFO | PDC_SWAP_I_ALL; // Reset FIFO and clear IRQs.
REG_LCD_PDC1_CNT = PDC_CNT_I_MASK_ALL; // Start
REG_LCD_PDC1_SWAP = PDC_SWAP_RST_FIFO | PDC_SWAP_I_ALL; // Reset FIFO and clear IRQs.
REG_GX_PSC_VRAM = 0xF00;
REG_GX_GPU_CLK = 0;
getPdnRegs()->gpu_cnt = PDN_GPU_CNT_CLK_EN | PDN_GPU_CNT_NORST_REGS;
deallocFramebufs();
// PSC0, PSC1, PDC0, PDC1, PPF, P3D
for(u8 i = 0; i < 6; i++)
{
unbindInterruptEvent(IRQ_PSC0 + i);
deleteEvent(g_gfxState.events[i]);
g_gfxState.events[i] = 0;
}
}
void GFX_setFramebufFmt(GfxFbFmt fmtTop, GfxFbFmt fmtBot)
{
REG_LCD_ABL0_FILL = 1u<<24; // Force blackscreen
REG_LCD_ABL1_FILL = 1u<<24; // Force blackscreen
if(fmtTop < (g_gfxState.formats[0] & 7u) || fmtBot < (g_gfxState.formats[1] & 7u))
{
deallocFramebufs();
setupFramebufs(fmtTop, fmtBot);
}
// Update PDC regs.
REG_LCD_PDC0_FB_A1 = (u32)g_gfxState.framebufs[0][0];
REG_LCD_PDC0_FB_A2 = (u32)g_gfxState.framebufs[0][1];
REG_LCD_PDC0_FB_B1 = (u32)g_gfxState.framebufs[0][2];
REG_LCD_PDC0_FB_B2 = (u32)g_gfxState.framebufs[0][3];
REG_LCD_PDC0_STRIDE = g_gfxState.strides[0];
REG_LCD_PDC0_FMT = g_gfxState.formats[0];
REG_LCD_PDC1_FB_A1 = (u32)g_gfxState.framebufs[1][0];
REG_LCD_PDC1_FB_A2 = (u32)g_gfxState.framebufs[1][1];
REG_LCD_PDC1_FB_B1 = (u32)g_gfxState.framebufs[1][2];
REG_LCD_PDC1_FB_B2 = (u32)g_gfxState.framebufs[1][3];
REG_LCD_PDC1_STRIDE = g_gfxState.strides[1];
REG_LCD_PDC1_FMT = g_gfxState.formats[1];
REG_LCD_ABL0_FILL = 0;
REG_LCD_ABL1_FILL = 0;
}
static u8 fmt2PixSize(GfxFbFmt fmt)
{
u8 size;
switch(fmt)
{
case GFX_RGBA8:
size = 4;
break;
case GFX_BGR8:
size = 3;
break;
default: // 2 = RGB565, 3 = RGB5A1, 4 = RGBA4
size = 2;
}
return size;
}
static void setupFramebufs(GfxFbFmt fmtTop, GfxFbFmt fmtBot)
{
const u8 topPixSize = fmt2PixSize(fmtTop);
const u8 botPixSize = fmt2PixSize(fmtBot);
g_gfxState.strides[0] = 240u * topPixSize; // No gap.
g_gfxState.strides[1] = 240u * botPixSize; // No gap.
const u32 topSize = 400u * 240 * topPixSize;
const u32 botSize = 320u * 240 * botPixSize;
g_gfxState.framebufs[0][0] = vramAlloc(topSize); // Top A1 (3D left eye)
void *botPtr = vramAlloc(botSize);
g_gfxState.framebufs[1][0] = botPtr; // Bottom A1
g_gfxState.framebufs[1][2] = botPtr; // Bottom B1 (unused)
g_gfxState.framebufs[0][2] = vramAlloc(topSize); // Top B1 (3D right eye)
g_gfxState.framebufs[0][1] = vramAlloc(topSize); // Top A2 (3D left eye)
botPtr = vramAlloc(botSize);
g_gfxState.framebufs[1][1] = botPtr; // Bottom A2
g_gfxState.framebufs[1][3] = botPtr; // Bottom B2 (unused)
g_gfxState.framebufs[0][3] = vramAlloc(topSize); // Top B2 (3D right eye)
g_gfxState.formats[0] = 0u<<16 | 3u<<8 | 1u<<6 | 0u<<4 | fmtTop;
g_gfxState.formats[1] = 0u<<16 | 3u<<8 | 0u<<6 | 0u<<4 | fmtBot;
}
static void deallocFramebufs(void)
{
vramFree(g_gfxState.framebufs[0][3]);
vramFree(g_gfxState.framebufs[1][1]);
vramFree(g_gfxState.framebufs[0][1]);
vramFree(g_gfxState.framebufs[0][2]);
vramFree(g_gfxState.framebufs[1][0]);
vramFree(g_gfxState.framebufs[0][0]);
}
static void setupDislayController(u8 lcd)
{
if(lcd > 1) return;
static const u32 displayCfgs[2][24] =
{
{
// PDC0 regs 0-0x4C.
450, 209, 449, 449, 0, 207, 209, 453<<16 | 449,
1<<16 | 0, 413, 2, 402, 402, 402, 1, 2,
406<<16 | 402, 0, 0<<4 | 0, 0<<16 | 0xFF<<8 | 0,
// PDC0 regs 0x5C-0x64.
400<<16 | 240, // Width and height.
449<<16 | 209,
402<<16 | 2,
// PDC0 reg 0x9C.
0<<16 | 0
},
{
// PDC1 regs 0-0x4C.
450, 209, 449, 449, 205, 207, 209, 453<<16 | 449,
1<<16 | 0, 413, 82, 402, 402, 79, 80, 82,
408<<16 | 404, 0, 1<<4 | 1, 0<<16 | 0<<8 | 0xFF,
// PDC1 regs 0x5C-0x64.
320<<16 | 240, // Width and height.
449<<16 | 209,
402<<16 | 82,
// PDC1 reg 0x9C.
0<<16 | 0
}
};
const u32 *const cfg = displayCfgs[lcd];
vu32 *const regs = (vu32*)(GX_REGS_BASE + 0x400 + (0x100u * lcd));
iomemcpy(regs, cfg, 0x50); // PDC regs 0-0x4C.
iomemcpy(regs + 23, &cfg[20], 0xC); // PDC regs 0x5C-0x64.
regs[36] = g_gfxState.strides[lcd]; // PDC reg 0x90 stride.
regs[39] = cfg[23]; // PDC reg 0x9C.
// PDC regs 0x68, 0x6C, 0x94, 0x98 and 0x70.
regs[26] = (u32)g_gfxState.framebufs[lcd][0]; // Framebuffer A first address.
regs[27] = (u32)g_gfxState.framebufs[lcd][1]; // Framebuffer A second address.
regs[37] = (u32)g_gfxState.framebufs[lcd][2]; // Framebuffer B first address.
regs[38] = (u32)g_gfxState.framebufs[lcd][3]; // Framebuffer B second address.
regs[28] = g_gfxState.formats[lcd]; // Format
regs[32] = 0; // Gamma table index 0.
for(u32 i = 0; i < 256; i++) regs[33] = 0x10101u * i;
}
void GFX_powerOnBacklights(GfxBlight mask)
{
fb_assert((mask & ~GFX_BLIGHT_BOTH) == 0u);
g_gfxState.lcdPower |= mask;
mask <<= 1;
MCU_setLcdPower(mask); // Power on backlights.
if(MCU_waitIrqs(MCU_LCD_IRQ_MASK) != (u32)mask<<24) panic();
}
void GFX_powerOffBacklights(GfxBlight mask)
{
fb_assert((mask & ~GFX_BLIGHT_BOTH) == 0u);
g_gfxState.lcdPower &= ~mask;
MCU_setLcdPower(mask); // Power off backlights.
if(MCU_waitIrqs(MCU_LCD_IRQ_MASK) != (u32)mask<<24) panic();
}
void GFX_setBrightness(u8 top, u8 bot)
{
g_gfxState.lcdLights[0] = top;
g_gfxState.lcdLights[1] = bot;
REG_LCD_ABL0_LIGHT = top;
REG_LCD_ABL1_LIGHT = bot;
}
void GFX_setForceBlack(bool top, bool bot)
{
REG_LCD_ABL0_FILL = (u32)top<<24; // Force blackscreen
REG_LCD_ABL1_FILL = (u32)bot<<24; // Force blackscreen
}
void GFX_setDoubleBuffering(u8 screen, bool dBuf)
{
g_gfxState.doubleBuf[screen] = dBuf;
if(!dBuf)
{
if(screen == SCREEN_TOP) REG_LCD_PDC0_SWAP = 0;
else REG_LCD_PDC1_SWAP = 0;
}
}
void* GFX_getFramebuffer(u8 screen)
{
const u32 idx = (g_gfxState.swap ^ 1u) & g_gfxState.doubleBuf[screen];
return g_gfxState.framebufs[screen][idx];
}
void GFX_swapFramebufs(void)
{
u32 swap = g_gfxState.swap;
swap ^= 1u;
g_gfxState.swap = swap;
swap |= PDC_SWAP_I_ALL; // Acknowledge IRQs.
if(g_gfxState.doubleBuf[0]) REG_LCD_PDC0_SWAP = swap;
if(g_gfxState.doubleBuf[1]) REG_LCD_PDC1_SWAP = swap;
}
void GFX_waitForEvent(GfxEvent event, bool discard)
{
KHandle kevent = g_gfxState.events[event];
if(discard) clearEvent(kevent);
waitForEvent(kevent);
clearEvent(kevent);
}
void GX_memoryFill(u32 *buf0a, u32 buf0v, u32 buf0Sz, u32 val0, u32 *buf1a, u32 buf1v, u32 buf1Sz, u32 val1)
{
if(buf0a)
{
REG_GX_PSC_FILL0_S_ADDR = (u32)buf0a>>3;
REG_GX_PSC_FILL0_E_ADDR = ((u32)buf0a + buf0Sz)>>3;
REG_GX_PSC_FILL0_VAL = val0;
REG_GX_PSC_FILL0_CNT = buf0v | 1u; // Pattern + start
}
if(buf1a)
{
REG_GX_PSC_FILL1_S_ADDR = (u32)buf1a>>3;
REG_GX_PSC_FILL1_E_ADDR = ((u32)buf1a + buf1Sz)>>3;
REG_GX_PSC_FILL1_VAL = val1;
REG_GX_PSC_FILL1_CNT = buf1v | 1u; // Pattern + start
}
}
// Example: GX_displayTransfer(in, 160u<<16 | 240u, out, 160u<<16 | 240u, 2u<<12 | 2u<<8);
// Copy and unswizzle GBA sized frame in RGB565.
void GX_displayTransfer(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 flags)
{
if(!in || !out) return;
REG_GX_PPF_IN_ADDR = (u32)in>>3;
REG_GX_PPF_OUT_ADDR = (u32)out>>3;
REG_GX_PPF_DT_INDIM = indim;
REG_GX_PPF_DT_OUTDIM = outdim;
REG_GX_PPF_FlAGS = flags;
REG_GX_PPF_UNK14 = 0;
REG_GX_PPF_CNT = 1;
}
// Example: GX_textureCopy(in, (240 * 2)<<12 | (240 * 2)>>4, out, (240 * 2)<<12 | (240 * 2)>>4, 240 * 400);
// Copies every second line of a 240x400 framebuffer.
void GX_textureCopy(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 size)
{
if(!in || !out) return;
REG_GX_PPF_IN_ADDR = (u32)in>>3;
REG_GX_PPF_OUT_ADDR = (u32)out>>3;
REG_GX_PPF_FlAGS = 1u<<3;
REG_GX_PPF_LEN = size;
REG_GX_PPF_TC_INDIM = indim;
REG_GX_PPF_TC_OUTDIM = outdim;
REG_GX_PPF_CNT = 1;
}
void GX_processCommandList(u32 size, const u32 *const cmdList)
{
REG_GX_P3D(GPUREG_IRQ_ACK) = 0; // Acknowledge last P3D.
while(REG_GX_PSC_STAT & 1u<<31) wait_cycles(0x30);
REG_GX_P3D(GPUREG_CMDBUF_SIZE0) = size>>3;
REG_GX_P3D(GPUREG_CMDBUF_ADDR0) = (u32)cmdList>>3;
REG_GX_P3D(GPUREG_CMDBUF_JUMP0) = 1;
}
// TODO: Sleep mode stuff needs some work.
/*void GFX_enterLowPowerState(void)
{
REG_LCD_ABL0_FILL = 1u<<24; // Force blackscreen
REG_LCD_ABL1_FILL = 1u<<24; // Force blackscreen
GFX_waitForEvent(GFX_EVENT_PDC0, true);
// Stop PDCs.
REG_LCD_PDC0_CNT = 0x700; // Stop
REG_LCD_PDC1_CNT = 0x700; // Stop
REG_LCD_PDC0_SWAP = 0x70100;
REG_LCD_PDC1_SWAP = 0x70100;
REG_GX_PSC_VRAM = 0xF00;
getPdnRegs()->gpu_cnt = PDN_GPU_CNT_NORST_ALL;
}
void GFX_returnFromLowPowerState(void)
{
getPdnRegs()->gpu_cnt = PDN_GPU_CNT_CLK_EN | PDN_GPU_CNT_NORST_ALL;
REG_GX_PSC_VRAM = 0;
//REG_GX_GPU_CLK = 0x70100;
REG_GX_PSC_FILL0_CNT = 0;
REG_GX_PSC_FILL1_CNT = 0;
// *((vu32*)0x10400050) = 0x22221200;
// *((vu32*)0x10400054) = 0xFF2;
setupDislayController(0);
setupDislayController(1);
const u32 swap = 0x70100 | g_gfxState.swap;
REG_LCD_PDC0_SWAP = swap;
REG_LCD_PDC1_SWAP = swap;
REG_LCD_PDC0_CNT = 0x10501; // Start
REG_LCD_PDC1_CNT = 0x10501; // Start
REG_LCD_ABL0_FILL = 0;
REG_LCD_ABL1_FILL = 0;
}*/

View File

@ -1,93 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "types.h"
#include "arm11/drivers/gpio.h"
#define GPIO_EDGE_FALLING (0u)
#define GPIO_EDGE_RISING (1u<<1)
#define GPIO_IRQ_ENABLE (1u<<2)
static vu16 *const g_datRegs[5] = {(vu16*)&REG_GPIO1_DAT, (vu16*)&REG_GPIO2_DAT,
&REG_GPIO2_DAT2, &REG_GPIO3_DAT, &REG_GPIO3_DAT2};
void GPIO_config(Gpio gpio, u8 cfg)
{
const u8 regIdx = gpio & 7u;
const u8 pinNum = gpio>>3;
// GPIO1 and GPIO3_DAT2 are not configurable.
if(regIdx == 1)
{
u32 reg = REG_GPIO2 & ~((1u<<24 | 1u<<16 | 1u<<8)<<pinNum);
if(cfg & GPIO_OUTPUT) reg |= (1u<<8)<<pinNum; // Direction.
if(cfg & GPIO_EDGE_RISING) reg |= (1u<<16)<<pinNum; // IRQ edge.
if(cfg & GPIO_IRQ_ENABLE) reg |= (1u<<24)<<pinNum; // IRQ enable.
REG_GPIO2 = reg;
}
else if(regIdx == 3)
{
u32 reg = REG_GPIO3_H1 & ~((1u<<16)<<pinNum);
u32 reg2 = REG_GPIO3_H2 & ~((1u<<16 | 1u)<<pinNum);
if(cfg & GPIO_OUTPUT) reg |= (1u<<16)<<pinNum; // Direction.
if(cfg & GPIO_EDGE_RISING) reg2 |= 1u<<pinNum; // IRQ edge.
if(cfg & GPIO_IRQ_ENABLE) reg2 |= (1u<<16)<<pinNum; // IRQ enable.
REG_GPIO3_H1 = reg;
REG_GPIO3_H2 = reg2;
}
}
u8 GPIO_read(Gpio gpio)
{
const u8 regIdx = gpio & 7u;
const u8 pinNum = gpio>>3;
if(regIdx > 4) return 0;
return *g_datRegs[regIdx]>>pinNum & 1u;
}
void GPIO_write(Gpio gpio, u8 val)
{
const u8 regIdx = gpio & 7u;
const u8 pinNum = gpio>>3;
if(regIdx == 0 || regIdx > 4) return;
u16 tmp = *g_datRegs[regIdx];
tmp = (tmp & ~(1u<<pinNum)) | (u16)val<<pinNum;
*g_datRegs[regIdx] = tmp;
}
/*#include "arm11/fmt.h"
void GPIO_print(void)
{
ee_printf("REG_GPIO1_DAT %04" PRIx8 "\n", REG_GPIO1_DAT);
ee_printf("REG_GPIO2_DAT %02" PRIx8 "\nREG_GPIO2_DIR %02" PRIx8 "\nREG_GPIO2_EDGE %02" PRIx8 "\nREG_GPIO2_IRQ %02" PRIx8 "\n", REG_GPIO2_DAT, REG_GPIO2_DIR, REG_GPIO2_EDGE, REG_GPIO2_IRQ);
ee_printf("REG_GPIO2_DAT2 %04" PRIx16 "\n", REG_GPIO2_DAT2);
ee_printf("REG_GPIO3_DAT %04" PRIx16 "\nREG_GPIO3_DIR %04" PRIx16 "\nREG_GPIO3_EDGE %04" PRIx16 "\nREG_GPIO3_IRQ %04" PRIx16 "\n", REG_GPIO3_DAT, REG_GPIO3_DIR, REG_GPIO3_EDGE, REG_GPIO3_IRQ);
ee_printf("REG_GPIO3_DAT2 %04" PRIx16 "\n", REG_GPIO3_DAT2);
}*/

View File

@ -1,155 +0,0 @@
/*
* This file is part of open_agb_firm
* Copyright (C) 2021 derrek, profi200
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Based on code from https://github.com/smealum/ctrulib
*/
#include "types.h"
#include "mem_map.h"
#include "arm11/drivers/hid.h"
#include "arm11/drivers/mcu.h"
#include "arm11/drivers/interrupt.h"
#include "arm11/drivers/gpio.h"
#include "arm11/drivers/codec.h"
#define MCU_HID_IRQ_MASK (MCU_IRQ_VOL_SLIDER_CHANGE | MCU_IRQ_BATT_CHARGE_START | \
MCU_IRQ_BATT_CHARGE_STOP | MCU_IRQ_SHELL_OPEN | \
MCU_IRQ_SHELL_CLOSE | MCU_IRQ_WIFI_PRESS | \
MCU_IRQ_HOME_RELEASE | MCU_IRQ_HOME_PRESS | \
MCU_IRQ_POWER_HELD | MCU_IRQ_POWER_PRESS)
#define CPAD_THRESHOLD (400)
static u32 g_kHeld = 0, g_kDown = 0, g_kUp = 0;
static u32 g_extraKeys = 0;
TouchPos g_tPos = {0};
CpadPos g_cPos = {0};
void hidInit(void)
{
static bool inited = false;
if(inited) return;
inited = true;
MCU_init();
u16 state = MCU_getExternalHardwareStatus();
u32 tmp = ~state<<3 & KEY_SHELL; // Current shell state. Bit is inverted.
tmp |= state<<1 & KEY_BAT_CHARGING; // Current battery charging state
state = MCU_getEarlyButtonsHeld();
tmp |= ~state<<1 & KEY_HOME; // Current HOME button state
g_extraKeys = tmp;
CODEC_init();
}
static void updateMcuHidState(void)
{
const u32 state = MCU_getIrqs(MCU_HID_IRQ_MASK);
if(state == 0) return;
u32 tmp = g_extraKeys;
tmp |= state & (KEY_POWER | KEY_POWER_HELD | KEY_HOME); // Power button pressed/held, HOME button pressed
if(state & 1u<<3) tmp &= ~KEY_HOME; // HOME released
tmp |= state>>1 & (KEY_WIFI | KEY_SHELL); // WiFi switch, shell closed
if(state & 1u<<6) tmp &= ~KEY_SHELL; // Shell opened
tmp |= state>>10 & KEY_BAT_CHARGING; // Battery started charging
if(state & 1u<<14) tmp &= ~KEY_BAT_CHARGING; // Battery stopped charging
tmp |= state>>16 & KEY_VOL_SLIDER; // Volume slider update
g_extraKeys = tmp;
}
static u32 rawCodec2Hid(void)
{
static u32 fakeKeysCache = 0;
alignas(4) CdcAdcData adc;
if(!CODEC_getRawAdcData(&adc)) return fakeKeysCache;
// Touchscreen
// TODO: Calibration
const u16 tx = __builtin_bswap16(adc.touchX[0]);
u32 fakeKeys = (~tx & 1u<<12)<<8; // KEY_TOUCH
g_tPos.x = tx * 320u / 4096u;
g_tPos.y = __builtin_bswap16(adc.touchY[0]) * 240u / 4096u;
// Circle-Pad
// TODO: Calibration
g_cPos.y = (__builtin_bswap16(adc.cpadY[0]) & 0xFFFu) - 2048u;
g_cPos.x = -((__builtin_bswap16(adc.cpadX[0]) & 0xFFFu) - 2048u); // X axis is inverted.
if((g_cPos.x >= 0 ? g_cPos.x : -g_cPos.x) > CPAD_THRESHOLD)
{
if(g_cPos.x >= 0) fakeKeys |= KEY_CPAD_RIGHT;
else fakeKeys |= KEY_CPAD_LEFT;
}
if((g_cPos.y >= 0 ? g_cPos.y : -g_cPos.y) > CPAD_THRESHOLD)
{
if(g_cPos.y >= 0) fakeKeys |= KEY_CPAD_UP;
else fakeKeys |= KEY_CPAD_DOWN;
}
fakeKeysCache = fakeKeys;
return fakeKeys;
}
void hidScanInput(void)
{
updateMcuHidState();
const u32 kOld = g_kHeld;
g_kHeld = rawCodec2Hid() | REG_HID_PAD;
g_kDown = (~kOld) & g_kHeld;
g_kUp = kOld & (~g_kHeld);
}
u32 hidKeysHeld(void)
{
return g_kHeld;
}
u32 hidKeysDown(void)
{
return g_kDown;
}
u32 hidKeysUp(void)
{
return g_kUp;
}
const TouchPos* hidGetTouchPosPtr(void)
{
return &g_tPos;
}
const CpadPos* hidGetCpadPosPtr(void)
{
return &g_cPos;
}
u32 hidGetExtraKeys(u32 clearMask)
{
const u32 tmp = g_extraKeys;
g_extraKeys &= ~clearMask;
return tmp;
}

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