Initial commit

This commit is contained in:
Gericom 2023-08-20 18:22:07 +02:00
commit ba3af908ce
55 changed files with 4509 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
build
.vs/
.vscode/
*.nds
*.o
*.a
*.d
*.elf
*.map
*.bin

31
Makefile Normal file
View File

@ -0,0 +1,31 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
export TARGET := $(shell basename $(CURDIR))
export TOPDIR := $(CURDIR)
include $(DEVKITARM)/ds_rules
.PHONY: check9 check7 clean
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all: check9 check7
#---------------------------------------------------------------------------------
check9:
$(MAKE) -C libtwl9
#---------------------------------------------------------------------------------
check7:
$(MAKE) -C libtwl7
#---------------------------------------------------------------------------------
clean:
$(MAKE) -C libtwl9 clean
$(MAKE) -C libtwl7 clean

View File

@ -0,0 +1,2 @@
#pragma GCC push_options
#pragma GCC target ("thumb")

View File

@ -0,0 +1,124 @@
#pragma once
#define REG_MCCNT0 (*(vu16*)0x040001A0)
#define REG_MCD0 (*(vu16*)0x040001A2)
#define REG_MCCNT1 (*(vu32*)0x040001A4)
#define REG_MCCMD0 (*(vu32*)0x040001A8)
#define REG_MCCMD1 (*(vu32*)0x040001AC)
#define REG_MCSCR0 (*(vu32*)0x040001B0)
#define REG_MCSCR1 (*(vu32*)0x040001B4)
#define REG_MCSCR2 (*(vu32*)0x040001B8)
#define REG_MCD1 (*(vu32*)0x04100010)
// REG_MCCNT0
#define MCCNT0_SPI_RATE_4_19_MHZ 0
#define MCCNT0_SPI_RATE_2_09_MHZ 1
#define MCCNT0_SPI_RATE_1_05_MHZ 2
#define MCCNT0_SPI_RATE_524_KHZ 3
#define MCCNT0_SPI_HOLD_CS (1 << 6)
#define MCCNT0_SPI_BUSY (1 << 7)
#define MCCNT0_MODE_MASK (1 << 13)
#define MCCNT0_MODE_ROM (0 << 13)
#define MCCNT0_MODE_SPI (1 << 13)
#define MCCNT0_ROM_XFER_IRQ (1 << 14)
#define MCCNT0_ENABLE (1 << 15)
// REG_MCCNT1
#define MCCNT1_LATENCY1_SHIFT 0
#define MCCNT1_LATENCY1_MASK 0x1FFF
#define MCCNT1_LATENCY1(x) (x)
#define MCCNT1_READ_DATA_DESCRAMBLE (1 << 13)
#define MCCNT1_CLOCK_SCRAMBLER (1 << 14)
#define MCCNT1_APPLY_SCRAMBLE_SEED (1 << 15)
#define MCCNT1_LATENCY2_SHIFT 16
#define MCCNT1_LATENCY2_MASK 0x3F0000
#define MCCNT1_LATENCY2(x) (((x) << MCCNT1_LATENCY2_SHIFT) & MCCNT1_LATENCY2_MASK)
#define MCCNT1_CMD_SCRAMBLE (1 << 22)
#define MCCNT1_DATA_READY (1 << 23)
#define MCCNT1_LEN_0 (0 << 24)
#define MCCNT1_LEN_512 (1 << 24)
#define MCCNT1_LEN_1024 (2 << 24)
#define MCCNT1_LEN_2048 (3 << 24)
#define MCCNT1_LEN_4096 (4 << 24)
#define MCCNT1_LEN_8192 (5 << 24)
#define MCCNT1_LEN_16384 (6 << 24)
#define MCCNT1_LEN_4 (7 << 24)
#define MCCNT1_CLK_6_7_MHZ (0 << 27)
#define MCCNT1_CLK_4_2_MHZ (1 << 27)
#define MCCNT1_LATENCY_CLK (1 << 28)
#define MCCNT1_RESET_ON (0 << 29)
#define MCCNT1_RESET_OFF (1 << 29)
#define MCCNT1_DIR_READ (0 << 30)
#define MCCNT1_DIR_WRITE (1 << 30)
#define MCCNT1_ENABLE (1 << 31)
#ifdef __cplusplus
extern "C"
{
#endif
static inline void card_romSetCmd(u64 cmd)
{
*(vu64*)&REG_MCCMD0 = __builtin_bswap64(cmd);
}
static inline bool card_romIsDataReady(void)
{
return REG_MCCNT1 & MCCNT1_DATA_READY;
}
static inline void card_romWaitDataReady(void)
{
while(!card_romIsDataReady());
}
static inline u32 card_romGetData(void)
{
return REG_MCD1;
}
static inline void card_romSetData(u32 data)
{
REG_MCD1 = data;
}
static inline bool card_romIsBusy(void)
{
return REG_MCCNT1 & MCCNT1_ENABLE;
}
static inline void card_romWaitBusy(void)
{
while(card_romIsBusy());
}
static inline void card_romStartXfer(u32 settings, bool irq)
{
REG_MCCNT0 = (REG_MCCNT0 & ~(MCCNT0_MODE_MASK | MCCNT0_ROM_XFER_IRQ)) | MCCNT0_MODE_ROM | (irq ? MCCNT0_ROM_XFER_IRQ : 0) | MCCNT0_ENABLE;
REG_MCCNT1 = MCCNT1_ENABLE | settings;
}
void card_romCpuRead(u32* dst, u32 len);
void card_romCpuReadUnaligned(u8* dst, u32 words);
void card_romCpuWrite(const u32* src, u32 words);
void card_romCpuWriteUnaligned(const u8* src, u32 words);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,120 @@
#pragma once
#define REG_DMA0SAD (*(vu32*)0x040000B0)
#define REG_DMA0DAD (*(vu32*)0x040000B4)
#define REG_DMA0CNT (*(vu32*)0x040000B8)
#define REG_DMA1SAD (*(vu32*)0x040000BC)
#define REG_DMA1DAD (*(vu32*)0x040000C0)
#define REG_DMA1CNT (*(vu32*)0x040000C4)
#define REG_DMA2SAD (*(vu32*)0x040000C8)
#define REG_DMA2DAD (*(vu32*)0x040000CC)
#define REG_DMA2CNT (*(vu32*)0x040000D0)
#define REG_DMA3SAD (*(vu32*)0x040000D4)
#define REG_DMA3DAD (*(vu32*)0x040000D8)
#define REG_DMA3CNT (*(vu32*)0x040000DC)
#define REG_DMACNT(x) (((vu32*)0x040000B8)[(x) * 3])
#ifdef LIBTWL_ARM9
#define REG_DMA0FILL (*(vu32*)0x040000E0)
#define REG_DMA1FILL (*(vu32*)0x040000E4)
#define REG_DMA2FILL (*(vu32*)0x040000E8)
#define REG_DMA3FILL (*(vu32*)0x040000EC)
#endif
#define DMACNT_COUNT(x) (x)
#define DMACNT_DST_MODE_INCREMENT (0 << 21)
#define DMACNT_DST_MODE_DECREMENT (1 << 21)
#define DMACNT_DST_MODE_FIXED (2 << 21)
#define DMACNT_DST_MODE_INCREMENT_RELOAD (3 << 21)
#define DMACNT_SRC_MODE_INCREMENT (0 << 23)
#define DMACNT_SRC_MODE_DECREMENT (1 << 23)
#define DMACNT_SRC_MODE_FIXED (2 << 23)
#define DMACNT_REPEAT (1 << 25)
#define DMACNT_16BIT (0 << 26)
#define DMACNT_32BIT (1 << 26)
#ifdef LIBTWL_ARM9
#define DMACNT_MODE_IMMEDIATE (0 << 27)
#define DMACNT_MODE_VBLANK (1 << 27)
#define DMACNT_MODE_HBLANK (2 << 27)
#define DMACNT_MODE_DISPLAY (3 << 27)
#define DMACNT_MODE_MMEM_DISP_FIFO (4 << 27)
#define DMACNT_MODE_DS_ROM_XFER (5 << 27)
#define DMACNT_MODE_GBA_DREQ (6 << 27)
#define DMACNT_MODE_GX_FIFO (7 << 27)
#endif
#ifdef LIBTWL_ARM7
#define DMACNT_MODE_IMMEDIATE (0 << 28)
#define DMACNT_MODE_VBLANK (1 << 28)
#define DMACNT_MODE_DS_ROM_XFER (2 << 28)
#define DMA0CNT_MODE_WIFI (3 << 28)
#define DMA1CNT_MODE_GBA_DREQ (3 << 28)
#define DMA2CNT_MODE_WIFI (3 << 28)
#define DMA3CNT_MODE_GBA_DREQ (3 << 28)
#endif
#define DMACNT_IRQ (1 << 30)
#define DMACNT_ENABLE (1 << 31)
#ifdef __cplusplus
extern "C" {
#endif
// todo: arm7
#ifdef LIBTWL_ARM9
/// @brief Safely sets the parameters of a nitro dma channel to prevent lockups.
/// @param dma The nitro dma channel to configure
/// @param src The source address
/// @param dst The destination address
/// @param control The channel configuration
extern void dma_ntrSetParams(int dma, const void* src, volatile void* dst, u32 control);
/// @brief Stops a nitro dma channel with a special procedure to prevent a lockup if the dma was just about to start.
/// @param dma The nitro dma channel to stop
extern void dma_ntrStopSafe(int dma);
/// @brief Stops a nitro dma channel directly by writing 0 to the control register.
/// Use with caution! Stopping a dma that is just about to start can lock up the system!
/// A safe use case would for example be stopping a hblank dma during vblank.
/// @param dma The nitro dma channel to stop
static inline void dma_ntrStopDirect(int dma)
{
REG_DMACNT(dma) = 0;
}
static inline void dma_ntrCopy16(int dma, const void* src, volatile void* dst, u32 length)
{
dma_ntrSetParams(dma, src, dst,
DMACNT_ENABLE | DMACNT_MODE_IMMEDIATE | DMACNT_16BIT |
DMACNT_SRC_MODE_INCREMENT | DMACNT_DST_MODE_INCREMENT |
DMACNT_COUNT(length >> 1));
}
static inline void dma_ntrCopy32(int dma, const void* src, volatile void* dst, u32 length)
{
dma_ntrSetParams(dma, src, dst,
DMACNT_ENABLE | DMACNT_MODE_IMMEDIATE | DMACNT_32BIT |
DMACNT_SRC_MODE_INCREMENT | DMACNT_DST_MODE_INCREMENT |
DMACNT_COUNT(length >> 2));
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,223 @@
#pragma once
typedef struct
{
const void* src; // Source address; not used in fill mode
void* dst; // Destination address
u32 totalWordCount; // For auto-start mode without infinite repeat
u32 wordCount; // Number of words to transfer per start trigger
u32 blockInterval; // Sets prescaler and cycles of delay between physical blocks
u32 fillData; // For fill mode
u32 control;
} dma_twl_config_t;
#define REG_NDMAGCNT (*(vu32*)0x04004100)
#define NDMAGCNT_YIELD_CYCLES_0 (0 << 16)
#define NDMAGCNT_YIELD_CYCLES_1 (1 << 16)
#define NDMAGCNT_YIELD_CYCLES_2 (2 << 16)
#define NDMAGCNT_YIELD_CYCLES_4 (3 << 16)
#define NDMAGCNT_YIELD_CYCLES_8 (4 << 16)
#define NDMAGCNT_YIELD_CYCLES_16 (5 << 16)
#define NDMAGCNT_YIELD_CYCLES_32 (6 << 16)
#define NDMAGCNT_YIELD_CYCLES_64 (7 << 16)
#define NDMAGCNT_YIELD_CYCLES_128 (8 << 16)
#define NDMAGCNT_YIELD_CYCLES_256 (9 << 16)
#define NDMAGCNT_YIELD_CYCLES_512 (10 << 16)
#define NDMAGCNT_YIELD_CYCLES_1024 (11 << 16)
#define NDMAGCNT_YIELD_CYCLES_2048 (12 << 16)
#define NDMAGCNT_YIELD_CYCLES_4096 (13 << 16)
#define NDMAGCNT_YIELD_CYCLES_8192 (14 << 16)
#define NDMAGCNT_YIELD_CYCLES_16384 (15 << 16)
#define NDMAGCNT_ARBITRATION_FIXED (0 << 31)
#define NDMAGCNT_ARBITRATION_ROUND_ROBIN (1 << 31)
#define REG_NDMA0SAD (*(vu32*)0x04004104)
#define REG_NDMA0DAD (*(vu32*)0x04004108)
#define REG_NDMA0TCNT (*(vu32*)0x0400410C)
#define REG_NDMA0WCNT (*(vu32*)0x04004110)
#define REG_NDMA0BCNT (*(vu32*)0x04004114)
#define REG_NDMA0FDATA (*(vu32*)0x04004118)
#define REG_NDMA0CNT (*(vu32*)0x0400411C)
#define REG_NDMA1SAD (*(vu32*)0x04004120)
#define REG_NDMA1DAD (*(vu32*)0x04004124)
#define REG_NDMA1TCNT (*(vu32*)0x04004128)
#define REG_NDMA1WCNT (*(vu32*)0x0400412C)
#define REG_NDMA1BCNT (*(vu32*)0x04004130)
#define REG_NDMA1FDATA (*(vu32*)0x04004134)
#define REG_NDMA1CNT (*(vu32*)0x04004138)
#define REG_NDMA2SAD (*(vu32*)0x0400413C)
#define REG_NDMA2DAD (*(vu32*)0x04004140)
#define REG_NDMA2TCNT (*(vu32*)0x04004144)
#define REG_NDMA2WCNT (*(vu32*)0x04004148)
#define REG_NDMA2BCNT (*(vu32*)0x0400414C)
#define REG_NDMA2FDATA (*(vu32*)0x04004150)
#define REG_NDMA2CNT (*(vu32*)0x04004154)
#define REG_NDMA3SAD (*(vu32*)0x04004158)
#define REG_NDMA3DAD (*(vu32*)0x0400415C)
#define REG_NDMA3TCNT (*(vu32*)0x04004160)
#define REG_NDMA3WCNT (*(vu32*)0x04004164)
#define REG_NDMA3BCNT (*(vu32*)0x04004168)
#define REG_NDMA3FDATA (*(vu32*)0x0400416C)
#define REG_NDMA3CNT (*(vu32*)0x04004170)
#define NDMABCNT_INTERVAL(x) (x)
#define NDMABCNT_PRESCALER_1 (0 << 16)
#define NDMABCNT_PRESCALER_4 (1 << 16)
#define NDMABCNT_PRESCALER_16 (2 << 16)
#define NDMABCNT_PRESCALER_64 (3 << 16)
#define NDMACNT_DST_MODE_INCREMENT (0 << 10)
#define NDMACNT_DST_MODE_DECREMENT (1 << 10)
#define NDMACNT_DST_MODE_FIXED (2 << 10)
#define NDMACNT_DST_RELOAD (1 << 12)
#define NDMACNT_SRC_MODE_INCREMENT (0 << 13)
#define NDMACNT_SRC_MODE_DECREMENT (1 << 13)
#define NDMACNT_SRC_MODE_FIXED (2 << 13)
#define NDMACNT_SRC_MODE_FILLDATA (3 << 13)
#define NDMACNT_SRC_RELOAD (1 << 15)
#define NDMACNT_PHYSICAL_COUNT_1 (0 << 16)
#define NDMACNT_PHYSICAL_COUNT_2 (1 << 16)
#define NDMACNT_PHYSICAL_COUNT_4 (2 << 16)
#define NDMACNT_PHYSICAL_COUNT_8 (3 << 16)
#define NDMACNT_PHYSICAL_COUNT_16 (4 << 16)
#define NDMACNT_PHYSICAL_COUNT_32 (5 << 16)
#define NDMACNT_PHYSICAL_COUNT_64 (6 << 16)
#define NDMACNT_PHYSICAL_COUNT_128 (7 << 16)
#define NDMACNT_PHYSICAL_COUNT_256 (8 << 16)
#define NDMACNT_PHYSICAL_COUNT_512 (9 << 16)
#define NDMACNT_PHYSICAL_COUNT_1024 (10 << 16)
#define NDMACNT_PHYSICAL_COUNT_2048 (11 << 16)
#define NDMACNT_PHYSICAL_COUNT_4096 (12 << 16)
#define NDMACNT_PHYSICAL_COUNT_8192 (13 << 16)
#define NDMACNT_PHYSICAL_COUNT_16384 (14 << 16)
#define NDMACNT_PHYSICAL_COUNT_32768 (15 << 16)
#define NDMACNT_MODE_TIMER_0 (0 << 24)
#define NDMACNT_MODE_TIMER_1 (1 << 24)
#define NDMACNT_MODE_TIMER_2 (2 << 24)
#define NDMACNT_MODE_TIMER_3 (3 << 24)
#define NDMACNT_MODE_DS_SLOTA_ROM_XFER (4 << 24)
#define NDMACNT_MODE_DS_SLOTB_ROM_XFER (5 << 24)
#define NDMACNT_MODE_VBLANK (6 << 24)
#ifdef LIBTWL_ARM9
#define NDMACNT_MODE_HBLANK (7 << 24)
#define NDMACNT_MODE_DISPLAY (8 << 24)
#define NDMACNT_MODE_MMEM_DISP_FIFO (9 << 24)
#define NDMACNT_MODE_GX_FIFO (10 << 24)
#define NDMACNT_MODE_CAMERA (11 << 24)
#endif
#ifdef LIBTWL_ARM7
#define NDMACNT_MODE_WIFI (7 << 24)
#define NDMACNT_MODE_SDMMC (8 << 24)
#define NDMACNT_MODE_SDIO (9 << 24)
#define NDMACNT_MODE_AES_IN (10 << 24)
#define NDMACNT_MODE_AES_OUT (11 << 24)
#define NDMACNT_MODE_MIC (12 << 24)
#endif
#define NDMACNT_MODE_IMMEDIATE (1 << 28)
#define NDMACNT_REPEAT_INFINITELY (1 << 29)
#define NDMACNT_IRQ (1 << 30)
#define NDMACNT_ENABLE (1 << 31)
#ifdef __cplusplus
extern "C" {
#endif
/// @brief Configures twl ndma to use fixed arbitration.
/// In this mode ndma0 has the highest and ndma3 the lowest priority,
/// similar to the nitro dma channels. Note that ndma0 has a lower
/// priority than nitro dma channel 3. When ndma channels are active
/// the dsp and cpu can not access the bus.
static inline void dma_twlSetFixedArbitration(void)
{
REG_NDMAGCNT = NDMAGCNT_ARBITRATION_FIXED;
}
/// @brief Configures twl ndma to use round robin arbitration.
/// In this mode nitro dma channels still have a higher priority,
/// but bus access is distributed between all ndma channels and
/// the dsp and cpu.
/// This is done in the order ndma0, ndma1, ndma2, ndma3, dsp/cpu.
/// Candidates that do not have any outstanding request are skipped,
/// and the dsp takes priority over the cpu (as usual). The amount
/// of cycles reserved for the dsp/cpu is configurable.
/// @param yieldCycles The number of cycles that will be yielded to the
/// dsp/cpu in the round robin schedule. When there is no request
/// outstanding the cycles will not be wasted. Should be one of
/// NDMAGCNT_YIELD_CYCLES_*.
static inline void dma_twlSetRoundRobinArbitration(u32 yieldCycles)
{
REG_NDMAGCNT = NDMAGCNT_ARBITRATION_ROUND_ROBIN | yieldCycles;
}
static inline void dma_twlSetParams(int dma, const dma_twl_config_t* config)
{
vu32* channel = &(&REG_NDMA0SAD)[7 * dma];
channel[0] = (u32)config->src;
channel[1] = (u32)config->dst;
channel[2] = config->totalWordCount;
channel[3] = config->wordCount;
channel[4] = config->blockInterval;
channel[5] = config->fillData;
channel[6] = config->control;
}
static inline void dma_twlWait(int dma)
{
vu32* cnt = &(&REG_NDMA0CNT)[7 * dma];
while (*cnt & NDMACNT_ENABLE);
}
static inline void dma_twlCopy32Async(int dma, const void* src, void* dst, u32 length)
{
vu32* channel = &(&REG_NDMA0SAD)[7 * dma];
channel[0] = (u32)src; //SAD
channel[1] = (u32)dst; //DAD
channel[3] = length >> 2; //WCNT
channel[4] = NDMABCNT_PRESCALER_1 | NDMABCNT_INTERVAL(0); //BCNT
channel[6] = NDMACNT_DST_MODE_INCREMENT | NDMACNT_SRC_MODE_INCREMENT |
NDMACNT_PHYSICAL_COUNT_1 | NDMACNT_MODE_IMMEDIATE | NDMACNT_ENABLE;
}
static inline void dma_twlCopy32(int dma, const void* src, void* dst, u32 length)
{
dma_twlCopy32Async(dma, src, dst, length);
dma_twlWait(dma);
}
static inline void dma_twlFill32Async(int dma, u32 value, void* dst, u32 length)
{
vu32* channel = &(&REG_NDMA0SAD)[7 * dma];
channel[1] = (u32)dst; //DAD
channel[3] = length >> 2; //WCNT
channel[4] = NDMABCNT_PRESCALER_1 | NDMABCNT_INTERVAL(0); //BCNT
channel[5] = value; //FDATA
channel[6] = NDMACNT_DST_MODE_INCREMENT | NDMACNT_SRC_MODE_FILLDATA |
NDMACNT_PHYSICAL_COUNT_1 | NDMACNT_MODE_IMMEDIATE | NDMACNT_ENABLE;
}
static inline void dma_twlFill32(int dma, u32 value, void* dst, u32 length)
{
dma_twlFill32Async(dma, value, dst, length);
dma_twlWait(dma);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1 @@
#pragma GCC pop_options

View File

@ -0,0 +1,95 @@
#pragma once
#define REG_DISPSTAT (*(vu16*)0x04000004)
#define REG_VCOUNT (*(vu16*)0x04000006)
#define DISPSTAT_IN_VBLANK (1 << 0)
#define DISPSTAT_IN_HBLANK (1 << 1)
#define DISPSTAT_VCOUNT_MATCH (1 << 2)
#define DISPSTAT_VBLANK_IRQ (1 << 3)
#define DISPSTAT_HBLANK_IRQ (1 << 4)
#define DISPSTAT_VCOUNT_MATCH_IRQ (1 << 5)
#ifdef __cplusplus
extern "C" {
#endif
static inline bool gfx_isInVBlank(void)
{
return REG_DISPSTAT & DISPSTAT_IN_VBLANK;
}
static inline bool gfx_isInHBlank(void)
{
return REG_DISPSTAT & DISPSTAT_IN_HBLANK;
}
static inline bool gfx_isVCountMatch(void)
{
return REG_DISPSTAT & DISPSTAT_VCOUNT_MATCH;
}
static inline bool gfx_getVBlankIrqEnabled(void)
{
return REG_DISPSTAT & DISPSTAT_VBLANK_IRQ;
}
static inline void gfx_setVBlankIrqEnabled(bool enabled)
{
if (enabled)
REG_DISPSTAT |= DISPSTAT_VBLANK_IRQ;
else
REG_DISPSTAT &= ~DISPSTAT_VBLANK_IRQ;
}
static inline bool gfx_getHBlankIrqEnabled(void)
{
return REG_DISPSTAT & DISPSTAT_HBLANK_IRQ;
}
static inline void gfx_setHBlankIrqEnabled(bool enabled)
{
if (enabled)
REG_DISPSTAT |= DISPSTAT_HBLANK_IRQ;
else
REG_DISPSTAT &= ~DISPSTAT_HBLANK_IRQ;
}
static inline bool gfx_getVCountMatchIrqEnabled(void)
{
return REG_DISPSTAT & DISPSTAT_VCOUNT_MATCH_IRQ;
}
static inline void gfx_setVCountMatchIrqEnabled(bool enabled)
{
if (enabled)
REG_DISPSTAT |= DISPSTAT_VCOUNT_MATCH_IRQ;
else
REG_DISPSTAT &= ~DISPSTAT_VCOUNT_MATCH_IRQ;
}
static inline u32 gfx_getVCountMatchLine(void)
{
u32 dispStat = REG_DISPSTAT;
return (dispStat >> 8) | ((dispStat & 0x80) << 1);
}
static inline void gfx_setVCountMatchLine(u32 line)
{
REG_DISPSTAT = (REG_DISPSTAT & ~0xFF80) | ((line & 0xFF) << 8) | ((line & 0x100) >> 1);
}
static inline u32 gfx_getVCount(void)
{
return REG_VCOUNT;
}
static inline void gfx_setVCount(u32 line)
{
REG_VCOUNT = line;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,101 @@
#pragma once
#define IPCFIFOCNT_SEND_FIFO_EMPTY (1 << 0)
#define IPCFIFOCNT_SEND_FIFO_FULL (1 << 1)
#define IPCFIFOCNT_SEND_FIFO_EMPTY_IRQ (1 << 2)
#define IPCFIFOCNT_SEND_FIFO_CLEAR (1 << 3)
#define IPCFIFOCNT_RECV_FIFO_EMPTY (1 << 8)
#define IPCFIFOCNT_RECV_FIFO_FULL (1 << 9)
#define IPCFIFOCNT_RECV_FIFO_NOT_EMPTY_IRQ (1 << 10)
#define IPCFIFOCNT_ERROR (1 << 14)
#define IPCFIFOCNT_ENABLE (1 << 15)
#define REG_IPCFIFOCNT (*(vu32*)0x04000184)
#define REG_IPCFIFOSEND (*(vu32*)0x04000188)
#define REG_IPCFIFORECV (*(vu32*)0x04100000)
#ifdef __cplusplus
extern "C" {
#endif
static inline bool ipc_isSendFifoEmpty(void)
{
return REG_IPCFIFOCNT & IPCFIFOCNT_SEND_FIFO_EMPTY;
}
static inline bool ipc_isSendFifoFull(void)
{
return REG_IPCFIFOCNT & IPCFIFOCNT_SEND_FIFO_FULL;
}
static inline void ipc_enableSendFifoEmptyIrq(void)
{
REG_IPCFIFOCNT |= IPCFIFOCNT_SEND_FIFO_EMPTY_IRQ;
}
static inline void ipc_disableSendFifoEmptyIrq(void)
{
REG_IPCFIFOCNT &= ~IPCFIFOCNT_SEND_FIFO_EMPTY_IRQ;
}
static inline void ipc_clearSendFifo(void)
{
REG_IPCFIFOCNT |= IPCFIFOCNT_SEND_FIFO_CLEAR;
}
static inline bool ipc_isRecvFifoEmpty(void)
{
return REG_IPCFIFOCNT & IPCFIFOCNT_RECV_FIFO_EMPTY;
}
static inline bool ipc_isRecvFifoFull(void)
{
return REG_IPCFIFOCNT & IPCFIFOCNT_RECV_FIFO_FULL;
}
static inline void ipc_enableRecvFifoNotEmptyIrq(void)
{
REG_IPCFIFOCNT |= IPCFIFOCNT_RECV_FIFO_NOT_EMPTY_IRQ;
}
static inline void ipc_disableRecvFifoNotEmptyIrq(void)
{
REG_IPCFIFOCNT &= ~IPCFIFOCNT_RECV_FIFO_NOT_EMPTY_IRQ;
}
static inline bool ipc_isFifoError(void)
{
return REG_IPCFIFOCNT & IPCFIFOCNT_ERROR;
}
static inline void ipc_ackFifoError(void)
{
REG_IPCFIFOCNT |= IPCFIFOCNT_ERROR;
}
static inline void ipc_enableFifo(void)
{
REG_IPCFIFOCNT |= IPCFIFOCNT_ENABLE;
}
static inline void ipc_disableFifo(void)
{
REG_IPCFIFOCNT &= ~IPCFIFOCNT_ENABLE;
}
static inline void ipc_sendWordDirect(u32 word)
{
REG_IPCFIFOSEND = word;
}
static inline u32 ipc_recvWordDirect(void)
{
return REG_IPCFIFORECV;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,21 @@
#pragma once
#define IPC_FIFO_MSG_CHANNEL_BITS 5
#define IPC_FIFO_MSG_CHANNEL_COUNT (1 << IPC_FIFO_MSG_CHANNEL_BITS)
#define IPC_FIFO_MSG_CHANNEL_MASK ((1 << IPC_FIFO_MSG_CHANNEL_BITS) - 1)
typedef void (*ipc_fifo_ch_handler_func_t)(u32 channel, u32 data, void* arg);
#ifdef __cplusplus
extern "C" {
#endif
void ipc_initFifoSystem(void);
void ipc_setChannelHandler(u32 channel, ipc_fifo_ch_handler_func_t handler, void* arg);
bool ipc_trySendFifoMessage(u32 channel, u32 data);
void ipc_sendFifoMessage(u32 channel, u32 data);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,76 @@
#pragma once
#define IPCSYNC_REMOTE_DATA_MASK (0xF << 0)
#define IPCSYNC_LOCAL_DATA_SHIFT 8
#define IPCSYNC_LOCAL_DATA_MASK (0xF << IPCSYNC_LOCAL_DATA_SHIFT)
#define IPCSYNC_IRQ_TRIGGER (1 << 13)
#define IPCSYNC_REMOTE_IRQ_ENABLE (1 << 14)
#define REG_IPCSYNC (*(vu32*)0x04000180)
#ifdef __cplusplus
extern "C" {
#endif
#ifdef LIBTWL_ARM9
static inline u32 ipc_getArm7SyncBits(void)
{
return REG_IPCSYNC & IPCSYNC_REMOTE_DATA_MASK;
}
static inline void ipc_setArm9SyncBits(u32 bits)
{
REG_IPCSYNC = (REG_IPCSYNC & ~IPCSYNC_LOCAL_DATA_MASK) | ((bits & 0xF) << IPCSYNC_LOCAL_DATA_SHIFT);
}
static inline void ipc_enableArm7Irq(void)
{
REG_IPCSYNC |= IPCSYNC_REMOTE_IRQ_ENABLE;
}
static inline void ipc_disableArm7Irq(void)
{
REG_IPCSYNC &= ~IPCSYNC_REMOTE_IRQ_ENABLE;
}
static inline void ipc_triggerArm9Irq(void)
{
REG_IPCSYNC |= IPCSYNC_IRQ_TRIGGER;
}
#endif
#ifdef LIBTWL_ARM7
static inline u32 ipc_getArm9SyncBits(void)
{
return REG_IPCSYNC & IPCSYNC_REMOTE_DATA_MASK;
}
static inline void ipc_setArm7SyncBits(u32 bits)
{
REG_IPCSYNC = (REG_IPCSYNC & ~IPCSYNC_LOCAL_DATA_MASK) | ((bits & 0xF) << IPCSYNC_LOCAL_DATA_SHIFT);
}
static inline void ipc_enableArm9Irq(void)
{
REG_IPCSYNC |= IPCSYNC_REMOTE_IRQ_ENABLE;
}
static inline void ipc_disableArm9Irq(void)
{
REG_IPCSYNC &= ~IPCSYNC_REMOTE_IRQ_ENABLE;
}
static inline void ipc_triggerArm7Irq(void)
{
REG_IPCSYNC |= IPCSYNC_IRQ_TRIGGER;
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,41 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
static inline int math_abs(int x)
{
return x >= 0 ? x : -x;
}
static inline int math_min(int x, int y)
{
return x < y ? x : y;
}
static inline int math_max(int x, int y)
{
return x > y ? x : y;
}
static inline u32 math_clz(u32 x)
{
return __builtin_clz(x);
}
static inline int math_ctz(u32 x)
{
if (!x)
return 32;
return 31 - __builtin_clz(x & -x);
}
static inline int math_ilog2(u32 x)
{
return 31 - __builtin_clz(x);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,145 @@
#pragma once
typedef enum
{
MEM_TWL_WRAM_A_SLOT_0 = 0,
MEM_TWL_WRAM_A_SLOT_01 = 2,
MEM_TWL_WRAM_A_SLOT_ALL = 3
} MemTwlWramASlots;
typedef enum
{
MEM_TWL_WRAM_BC_SLOT_0 = 0,
MEM_TWL_WRAM_BC_SLOT_01 = 1,
MEM_TWL_WRAM_BC_SLOT_0123 = 2,
MEM_TWL_WRAM_BC_SLOT_ALL = 3
} MemTwlWramBCSlots;
typedef enum
{
MEM_TWL_WRAM_A_NONE = 0,
MEM_TWL_WRAM_A_ARM9 = 0x80,
MEM_TWL_WRAM_A_ARM7 = 0x81,
} MemTwlWramAMaster;
typedef enum
{
MEM_TWL_WRAM_B_NONE = 0,
MEM_TWL_WRAM_B_ARM9 = 0x80,
MEM_TWL_WRAM_B_ARM7 = 0x81,
MEM_TWL_WRAM_B_DSP_CODE = 0x82
} MemTwlWramBMaster;
typedef enum
{
MEM_TWL_WRAM_C_NONE = 0,
MEM_TWL_WRAM_C_ARM9 = 0x80,
MEM_TWL_WRAM_C_ARM7 = 0x81,
MEM_TWL_WRAM_C_DSP_DATA = 0x82
} MemTwlWramCMaster;
#define MEM_TWL_WRAM_BASE 0x03000000
#define MEM_TWL_WRAM_A_SLOT_COUNT 4
#define MEM_TWL_WRAM_A_SLOT_SIZE 0x10000
#define MEM_TWL_WRAM_BC_SLOT_COUNT 8
#define MEM_TWL_WRAM_BC_SLOT_SIZE 0x8000
#define REG_MBK1 (*(vu32*)0x04004040)
#define REG_MBK2 (*(vu32*)0x04004044)
#define REG_MBK3 (*(vu32*)0x04004048)
#define REG_MBK4 (*(vu32*)0x0400404C)
#define REG_MBK5 (*(vu32*)0x04004050)
#define REG_MBK6 (*(vu32*)0x04004054)
#define REG_MBK7 (*(vu32*)0x04004058)
#define REG_MBK8 (*(vu32*)0x0400405C)
#define REG_MBK9 (*(vu32*)0x04004060)
#ifdef __cplusplus
extern "C" {
#endif
static inline void mem_setTwlWramAMapping(MemTwlWramASlots usedSlots, u32 start, u32 length)
{
start = (start - MEM_TWL_WRAM_BASE) >> 16;
u32 end = start + (length >> 16);
REG_MBK6 = (start << 4) | (usedSlots << 12) | (end << 20);
}
static inline void mem_setTwlWramBMapping(MemTwlWramBCSlots usedSlots, u32 start, u32 length)
{
start = (start - MEM_TWL_WRAM_BASE) >> 15;
u32 end = start + (length >> 15);
REG_MBK7 = (start << 3) | (usedSlots << 12) | (end << 19);
}
static inline void mem_setTwlWramCMapping(MemTwlWramBCSlots usedSlots, u32 start, u32 length)
{
start = (start - MEM_TWL_WRAM_BASE) >> 15;
u32 end = start + (length >> 15);
REG_MBK8 = (start << 3) | (usedSlots << 12) | (end << 19);
}
static inline void* mem_getTwlWramAStart(void)
{
return (void*)(MEM_TWL_WRAM_BASE + (((REG_MBK6 >> 4) & 0xFF) << 16));
}
static inline void* mem_getTwlWramBStart(void)
{
return (void*)(MEM_TWL_WRAM_BASE + (((REG_MBK7 >> 3) & 0x1FF) << 15));
}
static inline void* mem_getTwlWramCStart(void)
{
return (void*)(MEM_TWL_WRAM_BASE + (((REG_MBK8 >> 3) & 0x1FF) << 15));
}
#ifdef LIBTWL_ARM9
static inline void mem_setTwlWramABlockMapping(MemTwlWramAMaster master, int block, int slot)
{
((vu8*)&REG_MBK1)[block] = master | (slot << 2);
}
static inline void mem_setTwlWramBBlockMapping(MemTwlWramBMaster master, int block, int slot)
{
((vu8*)&REG_MBK2)[block] = master | (slot << 2);
}
static inline void mem_setTwlWramCBlockMapping(MemTwlWramCMaster master, int block, int slot)
{
((vu8*)&REG_MBK4)[block] = master | (slot << 2);
}
#endif
static inline bool mem_isTwlWramUnlocked(void)
{
if ((REG_SCFG_EXT & 0x80000000) == 0)
return false; // SCFG and MBK registers are permanently locked
if ((REG_MBK9 & 0xFFFF0F) != 0)
return false; // One or more MBK registers are locked
return true;
}
#ifdef LIBTWL_ARM7
static inline bool mem_isTwlWramUnlockable(void)
{
return (REG_SCFG_EXT & 0x80000000) != 0;
}
static inline void mem_unlockAllTwlWram(void)
{
REG_MBK9 = 0;
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,27 @@
#pragma once
#include "rtosThread.h"
typedef struct
{
bool flag;
rtos_thread_queue_t queue;
} rtos_event_t;
#ifdef __cplusplus
extern "C" {
#endif
void rtos_createEvent(rtos_event_t* event);
void rtos_signalEvent(rtos_event_t* event);
static inline void rtos_clearEvent(rtos_event_t* event)
{
event->flag = false;
}
void rtos_waitEvent(rtos_event_t* event, bool waitNew, bool clearAfter);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,167 @@
#pragma once
#include "rtosState.h"
enum
{
RTOS_IRQ_VBLANK = 1 << 0,
RTOS_IRQ_HBLANK = 1 << 1,
RTOS_IRQ_VCOUNT = 1 << 2,
RTOS_IRQ_TIMER0 = 1 << 3,
RTOS_IRQ_TIMER1 = 1 << 4,
RTOS_IRQ_TIMER2 = 1 << 5,
RTOS_IRQ_TIMER3 = 1 << 6,
#ifdef LIBTWL_ARM7
RTOS_IRQ_SIO = 1 << 7,
#endif
RTOS_IRQ_DMA0 = 1 << 8,
RTOS_IRQ_DMA1 = 1 << 9,
RTOS_IRQ_DMA2 = 1 << 10,
RTOS_IRQ_DMA3 = 1 << 11,
RTOS_IRQ_KEYS = 1 << 12,
RTOS_IRQ_GBA_IREQ = 1 << 13,
RTOS_IRQ_DS_SLOTA_DETECT = 1 << 14,
RTOS_IRQ_DS_SLOTB_DETECT = 1 << 15,
RTOS_IRQ_IPC_SYNC = 1 << 16,
RTOS_IRQ_IPC_FIFO_SEND = 1 << 17,
RTOS_IRQ_IPC_FIFO_RECV = 1 << 18,
RTOS_IRQ_DS_SLOTA_ROM_XFER = 1 << 19,
RTOS_IRQ_DS_SLOTA_IREQ = 1 << 20,
#ifdef LIBTWL_ARM9
RTOS_IRQ_GX_FIFO = 1 << 21,
RTOS_IRQ_DSP = 1 << 24,
RTOS_IRQ_CAMERA = 1 << 25,
#endif
#ifdef LIBTWL_ARM7
RTOS_IRQ_PMIC = 1 << 22,
RTOS_IRQ_SPI = 1 << 23,
RTOS_IRQ_WIFI = 1 << 24,
#endif
RTOS_IRQ_DS_SLOTB_ROM_XFER = 1 << 26,
RTOS_IRQ_DS_SLOTB_IREQ = 1 << 27,
RTOS_IRQ_NDMA0 = 1 << 28,
RTOS_IRQ_NDMA1 = 1 << 29,
RTOS_IRQ_NDMA2 = 1 << 30,
RTOS_IRQ_NDMA3 = 1 << 31
};
#define RTOS_IRQ_TIMER(x) (1 << ((x) + 3))
#ifdef LIBTWL_ARM7
enum
{
RTOS_IRQ2_GPIO18_0 = 1 << 0,
RTOS_IRQ2_GPIO18_1 = 1 << 1,
RTOS_IRQ2_GPIO18_2 = 1 << 2,
RTOS_IRQ2_GPIO33_0 = 1 << 4,
RTOS_IRQ2_GPIO33_1 = 1 << 5,
RTOS_IRQ2_MCU = 1 << 6, //GPIO33[2]
RTOS_IRQ2_GPIO33_3 = 1 << 7,
RTOS_IRQ2_SDMMC = 1 << 8,
RTOS_IRQ2_SDMMC_DATA1 = 1 << 9,
RTOS_IRQ2_SDIO = 1 << 10,
RTOS_IRQ2_SDIO_DATA1 = 1 << 11,
RTOS_IRQ2_AES = 1 << 12,
RTOS_IRQ2_I2C = 1 << 13,
RTOS_IRQ2_MIC = 1 << 14
};
#endif
#define REG_IME (*(vu32*)0x04000208)
#define REG_IE (*(vu32*)0x04000210)
#define REG_IF (*(vu32*)0x04000214)
#ifdef LIBTWL_ARM7
#define REG_IE2 (*(vu32*)0x04000218)
#define REG_IF2 (*(vu32*)0x0400021C)
#define BIOS_IRQ_HANDLER (*(vu32*)0x0380FFFC)
#endif
typedef void (*rtos_irq_func_t)(u32 irqMask);
#ifdef __cplusplus
extern "C" {
#endif
extern void rtos_halt(void);
extern void rtos_irqVector(void);
extern u32 rtos_disableIrqs(void);
extern u32 rtos_enableIrqs(void);
extern void rtos_restoreIrqs(u32 value);
void rtos_initIrq(void);
void rtos_setIrqFunc(u32 mask, rtos_irq_func_t func);
static inline u32 rtos_getIrqDepth(void)
{
return gRtosState.irqDepth;
}
static inline void rtos_ackIrqMask(u32 mask)
{
REG_IF = mask;
}
static inline void rtos_enableIrqMask(u32 mask)
{
REG_IE |= mask;
}
static inline void rtos_disableIrqMask(u32 mask)
{
REG_IE &= ~mask;
}
static inline void rtos_setIrqMask(u32 mask)
{
REG_IE = mask;
}
static inline u32 rtos_getIrqMask(void)
{
return REG_IE;
}
static inline u32 rtos_getIrqFlags(void)
{
return REG_IF;
}
#ifdef LIBTWL_ARM7
static inline void rtos_ackIrq2Mask(u32 mask)
{
REG_IF2 = mask;
}
static inline void rtos_enableIrq2Mask(u32 mask)
{
REG_IE2 |= mask;
}
static inline void rtos_disableIrq2Mask(u32 mask)
{
REG_IE2 &= ~mask;
}
static inline void rtos_setIrq2Mask(u32 mask)
{
REG_IE2 = mask;
}
static inline u32 rtos_getIrq2Mask(void)
{
return REG_IE2;
}
static inline u32 rtos_getIrq2Flags(void)
{
return REG_IF2;
}
#endif
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,24 @@
#pragma once
#include "rtosObject.h"
#include "rtosThread.h"
typedef struct
{
rtos_object_t obj;
volatile u16 lockCount;
rtos_thread_t* owner;
rtos_thread_queue_t queue;
} rtos_mutex_t;
#ifdef __cplusplus
extern "C" {
#endif
void rtos_createMutex(rtos_mutex_t* mutex);
void rtos_lockMutex(rtos_mutex_t* mutex);
bool rtos_tryLockMutex(rtos_mutex_t* mutex);
void rtos_unlockMutex(rtos_mutex_t* mutex);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,14 @@
#pragma once
enum
{
RTOS_OBJECT_TYPE_MUTEX,
RTOS_OBJECT_TYPE_EVENT
};
typedef struct rtos_object_t
{
struct rtos_object_t* prev;
struct rtos_object_t* next;
u8 type;
} rtos_object_t;

View File

@ -0,0 +1,16 @@
#pragma once
struct rtos_thread_t;
typedef struct
{
void* irqTable[32];
#ifdef LIBTWL_ARM7
void* irq2Table[32];
#endif
u32 irqDepth;
struct rtos_thread_t* threadReadyList;
struct rtos_thread_t* curThread;
} rtos_state_t;
extern rtos_state_t gRtosState;

View File

@ -0,0 +1,73 @@
#pragma once
#include "rtosState.h"
#include "rtosObject.h"
enum
{
RTOS_THREAD_STATE_SLEEPING,
RTOS_THREAD_STATE_WAITING,
RTOS_THREAD_STATE_READY,
RTOS_THREAD_STATE_RUNNING,
RTOS_THREAD_STATE_DEAD
};
struct rtos_thread_t;
typedef struct
{
u32 divNumerLo;
u32 divNumerHi;
u32 divDenomLo;
u32 divDenomHi;
u16 sqrtCnt;
u16 divCnt;
u32 sqrtParamLo;
u32 sqrtParamHi;
} math_div_sqrt_state_t;
typedef struct
{
struct rtos_thread_t* head;
} rtos_thread_queue_t;
typedef struct rtos_thread_t
{
u32 r[16];
u32 cpsr;
#ifdef LIBTWL_ARM9
math_div_sqrt_state_t divSqrtState;
#endif
struct rtos_thread_t* prev;
struct rtos_thread_t* next;
u8 priority;
u8 state;
rtos_object_t* objListHead;
rtos_thread_queue_t* inQueue;
rtos_thread_queue_t joinQueue;
} rtos_thread_t;
#ifdef __cplusplus
extern "C" {
#endif
void rtos_startMainThread(void);
void rtos_createThread(rtos_thread_t* thread, u8 priority, void (*mainFunc)(void*), void* arg, u32* stack, u32 stackSize);
void rtos_wakeupThread(rtos_thread_t* thread);
void rtos_sleepThread(rtos_thread_t* thread);
void rtos_joinThread(rtos_thread_t* thread);
void rtos_queueThread(rtos_thread_t* thread, rtos_thread_queue_t* queue);
void rtos_wakeupQueue(rtos_thread_queue_t* queue);
static inline rtos_thread_t* rtos_getCurThread(void)
{
return gRtosState.curThread;
}
static inline u8 rtos_getThreadPriority(const rtos_thread_t* thread)
{
return thread->priority;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,72 @@
#pragma once
#define REG_TM0CNT_L (*(vu16*)0x04000100)
#define REG_TM0CNT_H (*(vu16*)0x04000102)
#define REG_TM1CNT_L (*(vu16*)0x04000104)
#define REG_TM1CNT_H (*(vu16*)0x04000106)
#define REG_TM2CNT_L (*(vu16*)0x04000108)
#define REG_TM2CNT_H (*(vu16*)0x0400010A)
#define REG_TM3CNT_L (*(vu16*)0x0400010C)
#define REG_TM3CNT_H (*(vu16*)0x0400010E)
#define REG_TMCNT_L(x) (((vu16*)0x04000100)[(x) * 2])
#define REG_TMCNT_H(x) (((vu16*)0x04000102)[(x) * 2])
/// @brief System clock. Frequency: 33.513982 MHz.
#define TMCNT_H_CLK_SYS (0 << 0)
/// @brief System clock divided by 64. Frequency: 523.65596875 kHz.
#define TMCNT_H_CLK_SYS_DIV_64 (1 << 0)
/// @brief System clock divided by 256: Frequency: 130.9139921875 kHz.
#define TMCNT_H_CLK_SYS_DIV_256 (2 << 0)
/// @brief System clock divided by 1024. Frequency: 32.728498046875 kHz.
#define TMCNT_H_CLK_SYS_DIV_1024 (3 << 0)
/// @brief Timer ticks when the previous timer overflows.
/// @note This mode is not supported by timer 0 since it has no previous timer.
#define TMCNT_H_CLK_PREV_TMR_OVF (1 << 2)
/// @brief Timer triggers an irq on overflow.
#define TMCNT_H_IRQ (1 << 6)
/// @brief Enables the timer.
#define TMCNT_H_ENABLE (1 << 7)
#ifdef __cplusplus
extern "C" {
#endif
static inline void tmr_configure(int timer, int clock, u16 reload, bool irq)
{
REG_TMCNT_H(timer) = clock | (irq ? TMCNT_H_IRQ : 0);
REG_TMCNT_L(timer) = reload;
}
static inline void tmr_start(int timer)
{
REG_TMCNT_H(timer) |= TMCNT_H_ENABLE;
}
static inline void tmr_stop(int timer)
{
REG_TMCNT_H(timer) &= ~TMCNT_H_ENABLE;
}
static inline u16 tmr_getCounter(int timer)
{
return REG_TMCNT_L(timer);
}
static inline void tmr_setReload(int timer, u16 reload)
{
REG_TMCNT_L(timer) = reload;
}
#ifdef __cplusplus
}
#endif

72
common/source/card/card.c Normal file
View File

@ -0,0 +1,72 @@
#include <nds.h>
#include "libtwl/card/card.h"
void card_romCpuRead(u32* dst, u32 words)
{
u32* target = dst + words;
do
{
// Read data if available
if (card_romIsDataReady())
{
u32 data = card_romGetData();
if (dst < target)
*dst++ = data;
}
} while (card_romIsBusy());
}
void card_romCpuReadUnaligned(u8* dst, u32 words)
{
u8* target = dst + (words << 2);
do
{
// Read data if available
if (card_romIsDataReady())
{
u32 data = card_romGetData();
if (dst < target)
{
*dst++ = data & 0xFF;
*dst++ = (data >> 8) & 0xFF;
*dst++ = (data >> 16) & 0xFF;
*dst++ = (data >> 24) & 0xFF;
}
}
} while (card_romIsBusy());
}
void card_romCpuWrite(const u32* src, u32 words)
{
u32 data = 0;
const u32* target = src + words;
do
{
// Write data if ready
if (card_romIsDataReady())
{
if (src < target)
data = *src++;
card_romSetData(data);
}
} while (card_romIsBusy());
}
void card_romCpuWriteUnaligned(const u8* src, u32 words)
{
u32 data = 0;
const u8* target = src + (words << 2);
do
{
// Write data if ready
if (card_romIsDataReady())
{
if (src < target)
{
data = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
src += 4;
}
card_romSetData(data);
}
} while (card_romIsBusy());
}

View File

@ -0,0 +1,90 @@
#include <nds.h>
#include "libtwl/rtos/rtosIrq.h"
#include "libtwl/ipc/ipcSync.h"
#include "libtwl/ipc/ipcFifo.h"
#include "libtwl/ipc/ipcFifoSystem.h"
#define HANDSHAKE_PART0 0xA
#define HANDSHAKE_PART1 0xB
#define HANDSHAKE_PART2 0xC
static ipc_fifo_ch_handler_func_t sHandlerFuncs[IPC_FIFO_MSG_CHANNEL_COUNT];
static void* sHandlerArgs[IPC_FIFO_MSG_CHANNEL_COUNT];
static void recvFifoNotEmptyIrq(u32 irqMask)
{
while (!ipc_isRecvFifoEmpty())
{
u32 msg = ipc_recvWordDirect();
u32 channel = msg & IPC_FIFO_MSG_CHANNEL_MASK;
sHandlerFuncs[channel](channel, msg >> IPC_FIFO_MSG_CHANNEL_BITS, sHandlerArgs[channel]);
}
}
static void dummyChannelHandler(u32 channel, u32 data, void* arg)
{
}
void ipc_initFifoSystem(void)
{
for (int i = 0; i < IPC_FIFO_MSG_CHANNEL_COUNT; i++)
sHandlerFuncs[i] = &dummyChannelHandler;
u32 irqs = rtos_disableIrqs();
{
ipc_clearSendFifo();
ipc_ackFifoError();
ipc_enableRecvFifoNotEmptyIrq();
ipc_enableFifo();
rtos_ackIrqMask(RTOS_IRQ_IPC_FIFO_RECV);
rtos_setIrqFunc(RTOS_IRQ_IPC_FIFO_RECV, recvFifoNotEmptyIrq);
rtos_enableIrqMask(RTOS_IRQ_IPC_FIFO_RECV);
#ifdef LIBTWL_ARM9
while (ipc_getArm7SyncBits() != HANDSHAKE_PART0);
ipc_setArm9SyncBits(HANDSHAKE_PART0);
while (ipc_getArm7SyncBits() != HANDSHAKE_PART1);
ipc_setArm9SyncBits(HANDSHAKE_PART1);
while (ipc_getArm7SyncBits() != HANDSHAKE_PART2);
ipc_setArm9SyncBits(HANDSHAKE_PART2);
#endif
#ifdef LIBTWL_ARM7
ipc_setArm7SyncBits(HANDSHAKE_PART0);
while (ipc_getArm9SyncBits() != HANDSHAKE_PART0);
ipc_setArm7SyncBits(HANDSHAKE_PART1);
while (ipc_getArm9SyncBits() != HANDSHAKE_PART1);
ipc_setArm7SyncBits(HANDSHAKE_PART2);
while (ipc_getArm9SyncBits() != HANDSHAKE_PART2);
#endif
}
rtos_restoreIrqs(irqs);
}
void ipc_setChannelHandler(u32 channel, ipc_fifo_ch_handler_func_t handler, void* arg)
{
if (handler == NULL)
handler = &dummyChannelHandler;
sHandlerFuncs[channel] = handler;
sHandlerArgs[channel] = arg;
}
bool ipc_trySendFifoMessage(u32 channel, u32 data)
{
u32 irqs = rtos_disableIrqs();
if (ipc_isSendFifoFull())
{
rtos_restoreIrqs(irqs);
return false;
}
ipc_sendWordDirect((channel & IPC_FIFO_MSG_CHANNEL_MASK) | (data << IPC_FIFO_MSG_CHANNEL_BITS));
rtos_restoreIrqs(irqs);
return true;
}
void ipc_sendFifoMessage(u32 channel, u32 data)
{
while (!ipc_trySendFifoMessage(channel, data));
}

View File

@ -0,0 +1,48 @@
#include <nds.h>
#include "libtwl/rtos/rtosThread.h"
#include "libtwl/rtos/rtosIrq.h"
#include "libtwl/rtos/rtosEvent.h"
void rtos_createEvent(rtos_event_t* event)
{
event->flag = false;
event->queue.head = NULL;
}
void rtos_signalEvent(rtos_event_t* event)
{
u32 irq = rtos_disableIrqs();
if (event->flag)
{
rtos_restoreIrqs(irq);
return;
}
event->flag = true;
rtos_wakeupQueue(&event->queue);
rtos_restoreIrqs(irq);
}
void rtos_waitEvent(rtos_event_t* event, bool waitNew, bool clearAfter)
{
u32 irq = rtos_disableIrqs();
if (!waitNew && event->flag)
{
if (clearAfter)
event->flag = false;
rtos_restoreIrqs(irq);
return;
}
event->flag = false;
rtos_queueThread(rtos_getCurThread(), &event->queue);
if (clearAfter)
event->flag = false;
rtos_restoreIrqs(irq);
}

View File

@ -0,0 +1,83 @@
#include <nds.h>
#include "libtwl/rtos/rtosState.h"
#include "libtwl/math/mathUtil.h"
#include "libtwl/rtos/rtosIrq.h"
#ifdef LIBTWL_ARM7
#define ARM7_MAGIC_MUL 0x04D7651F
#define ARM7_MAGIC_SHIFT 27
#endif
static void irqDummyFunc(u32 irqMask)
{
}
void rtos_initIrq(void)
{
REG_IME = 0;
rtos_disableIrqs();
rtos_disableIrqMask(~0);
rtos_ackIrqMask(~0);
#ifdef LIBTWL_ARM7
rtos_disableIrq2Mask(~0);
rtos_ackIrq2Mask(~0);
#endif
for (int i = 0; i < 32; i++)
gRtosState.irqTable[i] = irqDummyFunc;
#ifdef LIBTWL_ARM7
for (int i = 0; i < 32; i++)
gRtosState.irq2Table[i] = irqDummyFunc;
#endif
gRtosState.irqDepth = 0;
#ifdef LIBTWL_ARM9
((vu32*)&SystemVectors)[5] = (u32)&rtos_irqVector;
setVectorBase(0);
#endif
#ifdef LIBTWL_ARM7
BIOS_IRQ_HANDLER = (u32)&rtos_irqVector;
#endif
rtos_enableIrqs();
REG_IME = 1;
}
void rtos_setIrqFunc(u32 mask, rtos_irq_func_t func)
{
if (!func)
func = irqDummyFunc;
while (mask)
{
u32 bit = (-mask) & mask;
mask &= ~bit;
#ifdef LIBTWL_ARM9
int idx = math_clz(bit);
#endif
#ifdef LIBTWL_ARM7
int idx = (bit * ARM7_MAGIC_MUL) >> ARM7_MAGIC_SHIFT;
#endif
gRtosState.irqTable[idx] = func;
}
}
#ifdef LIBTWL_ARM7
void rtos_setIrq2Func(u32 mask, rtos_irq_func_t func)
{
if (!func)
func = irqDummyFunc;
while (mask)
{
u32 bit = (-mask) & mask;
mask &= ~bit;
int idx = (bit * ARM7_MAGIC_MUL) >> ARM7_MAGIC_SHIFT;
gRtosState.irq2Table[idx] = func;
}
}
#endif

View File

@ -0,0 +1,164 @@
#ifdef LIBTWL_ARM9
.section .itcm
#endif
#ifdef LIBTWL_ARM7
.text
#endif
.arm
.global rtos_disableIrqs
rtos_disableIrqs:
mrs r0, cpsr
orr r1, r0, #0x80
msr cpsr_c, r1
bx lr
.global rtos_enableIrqs
rtos_enableIrqs:
mrs r0, cpsr
bic r1, r0, #0x80
msr cpsr_c, r1
bx lr
.global rtos_restoreIrqs
rtos_restoreIrqs:
msr cpsr_c, r0
bx lr
.global rtos_halt
rtos_halt:
#ifdef LIBTWL_ARM9
mov r0, #0
mcr p15, 0, r0, c7, c0, 4
#endif
#ifdef LIBTWL_ARM7
swi #(6 << 16)
#endif
bx lr
#ifdef LIBTWL_ARM9
#define RTOS_STATE_IRQ_DEPTH_OFFSET (32 * 4)
#endif
#ifdef LIBTWL_ARM7
#define RTOS_STATE_IRQ2_TABLE_OFFSET (32 * 4)
#define RTOS_STATE_IRQ_DEPTH_OFFSET (64 * 4)
#endif
.global rtos_irqVector
rtos_irqVector:
#ifdef LIBTWL_ARM7
//subtract 4 from the lr stored on the stack by the bios
ldr lr, [sp, #(5 * 4)]
ldr r2,= (gRtosState + RTOS_STATE_IRQ_DEPTH_OFFSET)
sub lr, lr, #4
str lr, [sp, #(5 * 4)]
#endif
#ifdef LIBTWL_ARM9
sub lr, lr, #4
push {r0-r3,r12,lr}
ldr r2,= (gRtosState + RTOS_STATE_IRQ_DEPTH_OFFSET)
#endif
mov r12, #0x04000000
ldr r3, [r2] // irqDepth
add r12, r12, #0x210
ldmia r12!, {r0, r1} // REG_IE and REG_IF
add r3, r3, #1
str r3, [r2], #-RTOS_STATE_IRQ_DEPTH_OFFSET // irqDepth
ands r0, r0, r1
#ifdef LIBTWL_ARM9
beq finish
#endif
#ifdef LIBTWL_ARM7
beq arm7_check_irq2
#endif
handle_irq:
rsb r1, r0, #0
and r0, r1, r0
#ifdef LIBTWL_ARM9
clz r1, r0
#endif
#ifdef LIBTWL_ARM7
ldr r1,= 0x04D7651F
mul r1, r0, r1
mov r1, r1, lsr #27
#endif
ldr r1, [r2, r1, lsl #2] //handler function is never NULL so no check needed
str r0, [r12, #-4] //ack
#ifdef LIBTWL_ARM7
adr lr, finish
bx r1
arm7_check_irq2:
ldmia r12!, {r0, r1}
add r2, r2, #RTOS_STATE_IRQ2_TABLE_OFFSET
ands r0, r0, r1
bne handle_irq
// we fall through to finish here
#endif
#ifdef LIBTWL_ARM9
blx r1
#endif
finish:
ldr r12,= (gRtosState + RTOS_STATE_IRQ_DEPTH_OFFSET)
ldmia r12, {r0, r1, r2} //irqDepth, threadReadyList, curThread
subs r0, r0, #1
str r0, [r12] //irqDepth
ldmnefd sp!, {r0-r3,r12,pc}^ //if nested irq, no thread switch
cmp r2, r1 //curThread == threadReadyList?
ldmeqfd sp!, {r0-r3,r12,pc}^
irq_thread_switch:
str r1, [r12, #8] // curThread = threadReadyList
pop {r0,r3,r12,lr}
stmia r2!, {r0,r3,r12,lr} // r0,r1,r2,r3
pop {r12,lr}
mrs r3, spsr
str lr, [r2, #0x2C] // pc
str r3, [r2, #0x30] // cpsr
msr cpsr, #0xD3
#ifdef LIBTWL_ARM9
stmia r2, {r4-r12,sp,lr}^
//div/sqrt state
mov r0, #0x04000000
add r0, r0, #0x290
ldmia r0, {r3-r12,sp,lr}
ldr r7, [r0, #-0x10]
add r2, r2, #0x34
orr r11, r11, r7, lsl #16
stmia r2, {r3-r6,r11,sp,lr}
ldr r2, [r1, #(16 * 4)]!
ldmib r1, {r3-r6,r11,sp,lr}
stmia r0, {r3-r12,sp,lr}
mov r3, r11, lsr #16
strh r3, [r0, #-0x10]!
ldr r3, [r0]
1:
tst r3, #0x8000
ldrne r3, [r0]
bne 1b
ldr lr, [r1, #-4]!
msr spsr, r2
ldmdb r1, {r0-r12,sp,lr}^
#endif
#ifdef LIBTWL_ARM7
ldr r0, [r1, #(16 * 4)] // cpsr
stmia r2, {r4-r12,sp,lr}^
ldr lr, [r1, #(15 * 4)]
msr spsr, r0
ldmia r1, {r0-r12,sp,lr}^
#endif
nop // safety for loading user regs
movs pc, lr
.pool
.end

View File

@ -0,0 +1,89 @@
#include <nds.h>
#include "libtwl/rtos/rtosThread.h"
#include "libtwl/rtos/rtosIrq.h"
#include "libtwl/rtos/rtosMutex.h"
void rtos_createMutex(rtos_mutex_t* mutex)
{
mutex->obj.prev = NULL;
mutex->obj.next = NULL;
mutex->obj.type = RTOS_OBJECT_TYPE_MUTEX;
mutex->lockCount = 0;
mutex->owner = NULL;
mutex->queue.head = NULL;
}
void rtos_lockMutex(rtos_mutex_t* mutex)
{
u32 irq = rtos_disableIrqs();
rtos_thread_t* curThread = rtos_getCurThread();
if (mutex->owner == curThread)
{
mutex->lockCount++;
rtos_restoreIrqs(irq);
return;
}
while (1)
{
if (mutex->lockCount == 0)
{
mutex->owner = curThread;
mutex->lockCount = 1;
mutex->obj.prev = NULL;
mutex->obj.next = curThread->objListHead;
if (curThread->objListHead)
curThread->objListHead->prev = &mutex->obj;
curThread->objListHead = &mutex->obj;
break;
}
rtos_queueThread(rtos_getCurThread(), &mutex->queue);
}
rtos_restoreIrqs(irq);
}
bool rtos_tryLockMutex(rtos_mutex_t* mutex)
{
u32 irq = rtos_disableIrqs();
rtos_thread_t* curThread = rtos_getCurThread();
if (mutex->owner == curThread)
{
mutex->lockCount++;
rtos_restoreIrqs(irq);
return true;
}
if (mutex->lockCount == 0)
{
mutex->owner = curThread;
mutex->lockCount = 1;
mutex->obj.prev = NULL;
mutex->obj.next = curThread->objListHead;
if (curThread->objListHead)
curThread->objListHead->prev = &mutex->obj;
curThread->objListHead = &mutex->obj;
rtos_restoreIrqs(irq);
return true;
}
rtos_restoreIrqs(irq);
return false;
}
void rtos_unlockMutex(rtos_mutex_t* mutex)
{
u32 irq = rtos_disableIrqs();
if (--mutex->lockCount == 0)
{
mutex->owner = NULL;
rtos_wakeupQueue(&mutex->queue);
}
rtos_restoreIrqs(irq);
}

View File

@ -0,0 +1,9 @@
#include <nds.h>
#include "libtwl/rtos/rtosState.h"
#ifdef LIBTWL_ARM9
DTCM_BSS rtos_state_t gRtosState;
#endif
#ifdef LIBTWL_ARM7
rtos_state_t gRtosState;
#endif

View File

@ -0,0 +1,242 @@
#include <nds.h>
#include "libtwl/rtos/rtosMutex.h"
#include "libtwl/rtos/rtosIrq.h"
#include "libtwl/rtos/rtosThread.h"
#ifdef LIBTWL_ARM9
static DTCM_BSS rtos_thread_t sMainThread;
#endif
#ifdef LIBTWL_ARM7
static rtos_thread_t sMainThread;
#endif
static rtos_thread_t sIdleThread;
static u32 sIdleStack[64];
static void insertReadyList(rtos_thread_t* thread)
{
thread->state = RTOS_THREAD_STATE_READY;
int prio = thread->priority;
rtos_thread_t* t = gRtosState.threadReadyList;
if (t->priority <= prio)
{
gRtosState.threadReadyList = thread;
thread->prev = NULL;
thread->next = t;
t->prev = thread;
}
else
{
while (t->priority > prio)
t = t->next;
thread->next = t;
rtos_thread_t* newPrev = t->prev;
thread->prev = newPrev;
t->prev = thread;
newPrev->next = thread;
}
}
static void idleMain(void* arg)
{
while (true)
{
rtos_halt();
}
}
void rtos_startMainThread(void)
{
rtos_createThread(&sIdleThread, 0, idleMain, NULL, sIdleStack, sizeof(sIdleStack));
sMainThread.inQueue = NULL;
sMainThread.priority = 16;
gRtosState.curThread = &sMainThread;
gRtosState.threadReadyList = &sMainThread;
gRtosState.threadReadyList->prev = NULL;
gRtosState.threadReadyList->next = &sIdleThread;
sIdleThread.prev = &sMainThread;
sIdleThread.next = NULL;
sIdleThread.state = RTOS_THREAD_STATE_READY;
sMainThread.state = RTOS_THREAD_STATE_RUNNING;
}
extern void rtos_switchThreads(rtos_thread_t* cur, rtos_thread_t* new);
static void reschedule(void)
{
if (gRtosState.curThread == gRtosState.threadReadyList || gRtosState.irqDepth)
return;
rtos_thread_t* cur = gRtosState.curThread;
gRtosState.curThread = gRtosState.threadReadyList;
gRtosState.curThread->state = RTOS_THREAD_STATE_RUNNING;
rtos_switchThreads(cur, gRtosState.threadReadyList);
}
static void wakeupQueueWithoutReschedule(rtos_thread_queue_t* queue)
{
rtos_thread_t* t = queue->head;
while (t)
{
rtos_thread_t* next = t->next;
t->inQueue = NULL;
insertReadyList(t);
t = next;
}
queue->head = NULL;
}
static void threadEnd(void)
{
u32 irq = rtos_disableIrqs();
rtos_thread_t* cur = gRtosState.curThread;
cur->state = RTOS_THREAD_STATE_DEAD;
gRtosState.threadReadyList = cur->next;
cur->next->prev = NULL;
cur->next = NULL;
cur->prev = NULL;
rtos_object_t* obj = cur->objListHead;
while (obj)
{
rtos_object_t* next = obj->next;
if (obj->type == RTOS_OBJECT_TYPE_MUTEX)
{
rtos_mutex_t* mutex = (rtos_mutex_t*)obj;
mutex->owner = NULL;
mutex->lockCount = 0;
wakeupQueueWithoutReschedule(&mutex->queue);
}
obj->prev = NULL;
obj->next = NULL;
obj = next;
}
wakeupQueueWithoutReschedule(&cur->joinQueue);
reschedule();
//we'll never return here
rtos_restoreIrqs(irq);
}
void rtos_createThread(rtos_thread_t* thread, u8 priority, void (*mainFunc)(void*), void* arg, u32* stack, u32 stackSize)
{
u32* stackTop = (u32*)((u8*)stack + stackSize);
thread->r[0] = (u32)arg;
thread->r[13] = (u32)stackTop;
thread->r[14] = (u32)threadEnd;
thread->r[15] = (u32)mainFunc;
thread->cpsr = /*0x13*/0x1F | (((u32)mainFunc & 1) ? 0x20 : 0); //cpsr, svc mode, irq and fiq on
thread->next = NULL;
thread->prev = NULL;
thread->state = RTOS_THREAD_STATE_SLEEPING;
thread->priority = priority;
thread->objListHead = NULL;
thread->inQueue = NULL;
thread->joinQueue.head = NULL;
}
void rtos_wakeupThread(rtos_thread_t* thread)
{
u32 irq = rtos_disableIrqs();
if (thread->state != RTOS_THREAD_STATE_SLEEPING)
{
rtos_restoreIrqs(irq);
return;
}
insertReadyList(thread);
reschedule();
rtos_restoreIrqs(irq);
}
void rtos_sleepThread(rtos_thread_t* thread)
{
u32 irq = rtos_disableIrqs();
if (thread == NULL)
thread = gRtosState.curThread;
if (thread->state == RTOS_THREAD_STATE_DEAD || thread->state == RTOS_THREAD_STATE_SLEEPING)
{
rtos_restoreIrqs(irq);
return;
}
thread->state = RTOS_THREAD_STATE_SLEEPING;
if (!thread->prev)
{
gRtosState.threadReadyList = thread->next;
thread->next->prev = NULL;
thread->next = NULL;
thread->prev = NULL;
reschedule();
}
else
{
thread->prev->next = thread->next;
thread->next->prev = thread->prev;
thread->next = NULL;
thread->prev = NULL;
}
rtos_restoreIrqs(irq);
}
void rtos_joinThread(rtos_thread_t* thread)
{
rtos_queueThread(rtos_getCurThread(), &thread->joinQueue);
}
void rtos_queueThread(rtos_thread_t* thread, rtos_thread_queue_t* queue)
{
u32 irq = rtos_disableIrqs();
thread->state = RTOS_THREAD_STATE_SLEEPING;
thread->inQueue = queue;
if (!thread->prev)
{
gRtosState.threadReadyList = thread->next;
thread->next->prev = NULL;
thread->next = queue->head;
if (queue->head)
queue->head->prev = thread;
queue->head = thread;
thread->prev = NULL;
reschedule();
}
else
{
thread->prev->next = thread->next;
thread->next->prev = thread->prev;
thread->next = queue->head;
if (queue->head)
queue->head->prev = thread;
queue->head = thread;
thread->prev = NULL;
}
rtos_restoreIrqs(irq);
}
void rtos_wakeupQueue(rtos_thread_queue_t* queue)
{
u32 irq = rtos_disableIrqs();
wakeupQueueWithoutReschedule(queue);
reschedule();
rtos_restoreIrqs(irq);
}

View File

@ -0,0 +1,51 @@
#ifdef LIBTWL_ARM9
.section .itcm
#endif
#ifdef LIBTWL_ARM7
.text
#endif
.arm
//r0=cur
//r1=new
.global rtos_switchThreads
rtos_switchThreads:
add r0, r0, #16
stmia r0!, {r4-r12,sp}
mov r2, lr
mrs r3, cpsr
stmib r0!, {r2,r3} //pc,cpsr
#ifdef LIBTWL_ARM9
//div/sqrt state
mov r2, #0x04000000
add r2, r2, #0x290
ldmia r2, {r3-r12,sp,lr}
ldr r7, [r2, #-0x10]
ldr r8, [r1, #(16 * 4)]! //cpsr
orr r11, r11, r7, lsl #16
stmib r0, {r3-r6,r11,sp,lr}
ldmib r1, {r3-r6,r11,sp,lr}
stmia r2, {r3-r12,sp,lr}
mov r3, r11, lsr #16
strh r3, [r2, #-0x10]!
ldr r3, [r2]
1:
tst r3, #0x8000
ldrne r3, [r2]
bne 1b
#endif
#ifdef LIBTWL_ARM7
ldr r8, [r1, #(16 * 4)]! //cpsr
#endif
msr cpsr, #0xD3
ldr lr, [r1, #-4]!
msr spsr, r8
ldmdb r1, {r0-r12,sp,lr}^
nop
movs pc, lr
.end

126
libtwl7/Makefile Normal file
View File

@ -0,0 +1,126 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := source source/sio ../common/source/rtos ../common/source/ipc ../common/source/card
DATA := data
INCLUDES := include ../common/include
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -marm -mthumb-interwork -DLIBTWL_ARM7 -DARM7
CFLAGS := -g -Wall -O2\
-mcpu=arm7tdmi -mtune=arm7tdmi \
-fomit-frame-pointer -ffast-math \
-ffunction-sections -fdata-sections\
-Werror=implicit-function-declaration -Werror=return-type\
$(ARCH)
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fno-threadsafe-statics
ASFLAGS := -g $(ARCH) -mcpu=arm7tdmi -mtune=arm7tdmi
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) -ffunction-sections -fdata-sections
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/lib/$(TARGET).a
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
lib:
@[ -d $@ ] || mkdir -p $@
$(BUILD): lib
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) lib
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@ -0,0 +1,117 @@
#pragma once
#define KEYINPUT_KEY_A (1 << 0)
#define KEYINPUT_KEY_B (1 << 1)
#define KEYINPUT_KEY_SELECT (1 << 2)
#define KEYINPUT_KEY_START (1 << 3)
#define KEYINPUT_KEY_DPAD_LEFT (1 << 4)
#define KEYINPUT_KEY_DPAD_RIGHT (1 << 5)
#define KEYINPUT_KEY_DPAD_UP (1 << 6)
#define KEYINPUT_KEY_DPAD_DOWN (1 << 7)
#define KEYINPUT_KEY_R (1 << 8)
#define KEYINPUT_KEY_L (1 << 9)
#define KEYCNT_MASK_KEY_A (1 << 0)
#define KEYCNT_MASK_KEY_B (1 << 1)
#define KEYCNT_MASK_KEY_SELECT (1 << 2)
#define KEYCNT_MASK_KEY_START (1 << 3)
#define KEYCNT_MASK_KEY_DPAD_LEFT (1 << 4)
#define KEYCNT_MASK_KEY_DPAD_RIGHT (1 << 5)
#define KEYCNT_MASK_KEY_DPAD_UP (1 << 6)
#define KEYCNT_MASK_KEY_DPAD_DOWN (1 << 7)
#define KEYCNT_MASK_KEY_R (1 << 8)
#define KEYCNT_MASK_KEY_L (1 << 9)
#define KEYCNT_IRQ (1 << 14)
#define KEYCNT_MODE_OR (0 << 15)
#define KEYCNT_MODE_AND (1 << 15)
#define RCNT0_L_DATA_SC (1 << 0)
#define RCNT0_L_DATA_SD (1 << 1)
#define RCNT0_L_DATA_SI (1 << 2)
#define RCNT0_L_DATA_SO (1 << 3)
#define RCNT0_L_DIR_SC_OUTPUT (1 << 4)
#define RCNT0_L_DIR_SD_OUTPUT (1 << 5)
#define RCNT0_L_DIR_SI_OUTPUT (1 << 6)
#define RCNT0_L_DIR_SO_OUTPUT (1 << 7)
#define RCNT0_L_IRQ (1 << 8)
#define RCNT0_L_MODE_MASK (3 << 14)
#define RCNT0_L_MODE_SIO (0 << 14)
#define RCNT0_L_MODE_GPIO (2 << 14)
#define RCNT0_L_MODE_JOYBUS (3 << 14)
#define RCNT0_H_DATA_KEY_X (1 << 0)
#define RCNT0_H_DATA_KEY_Y (1 << 1)
#define RCNT0_H_DATA_KEY_DEBUG (1 << 3)
#define RCNT0_H_DATA_PEN (1 << 6)
#define RCNT0_H_DATA_LID (1 << 7)
#define RCNT1_DATA_RTC_SIO (1 << 0)
#define RCNT1_DATA_RTC_SCK (1 << 1)
#define RCNT1_DATA_RTC_CS (1 << 2)
#define RCNT1_DIR_RTC_SIO_OUTPUT (1 << 4)
#define RCNT1_DIR_RTC_SCK_OUTPUT (1 << 5)
#define RCNT1_DIR_RTC_CS_OUTPUT (1 << 6)
#define REG_SIOCNT_L (*(vu16*)0x04000128)
#define REG_SIOCNT_H (*(vu16*)0x0400012A)
#define REG_KEYINPUT (*(vu16*)0x04000130)
#define REG_KEYCNT (*(vu16*)0x04000132)
#define REG_RCNT0_L (*(vu16*)0x04000134)
#define REG_RCNT0_H (*(vu16*)0x04000136)
#define REG_RCNT1 (*(vu16*)0x04000138)
#define REG_JOYCNT (*(vu16*)0x04000140)
#ifdef __cplusplus
extern "C" {
#endif
static inline void sio_setGpioSiIrq(bool enabled)
{
// SI must always be used as input
REG_RCNT0_L &= ~RCNT0_L_DIR_SI_OUTPUT;
if (enabled)
REG_RCNT0_L |= RCNT0_L_IRQ;
else
REG_RCNT0_L &= ~RCNT0_L_IRQ;
}
static inline void sio_setGpioMode(u32 mode)
{
REG_RCNT0_L = (REG_RCNT0_L & ~RCNT0_L_MODE_MASK) | (mode & RCNT0_L_MODE_MASK);
}
/// @brief Sets the direction and output levels of all rtc pins at once.
/// @param direction The pin directions as a combination of RCNT1_DIR_RTC_x_OUTPUT.
/// @param data The output levels as a combination of RCNT1_DATA_RTC_x.
static inline void sio_setRtcPins(u32 direction, u32 data)
{
const u32 dirMask =
RCNT1_DIR_RTC_SIO_OUTPUT | RCNT1_DIR_RTC_SCK_OUTPUT | RCNT1_DIR_RTC_CS_OUTPUT;
const u32 dataMask =
RCNT1_DATA_RTC_SIO | RCNT1_DATA_RTC_SCK | RCNT1_DATA_RTC_CS;
REG_RCNT1 = (REG_RCNT1 & ~(dirMask | dataMask)) | (direction & dirMask) | (data & dataMask);
}
/// @brief Sets the rtc chip select output level. This function assumes the
/// pin has already been configured as output.
/// @param high True if the output level should be high, or false otherwise.
static inline void sio_setRtcChipSelect(bool high)
{
if (high)
REG_RCNT1 |= RCNT1_DATA_RTC_CS;
else
REG_RCNT1 &= ~RCNT1_DATA_RTC_CS;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,168 @@
#pragma once
#define RTC_AM 0
#define RTC_PM 1
#define RTC_STATUS1_RESET (1 << 0)
#define RTC_STATUS1_24HOUR (1 << 1)
#define RTC_STATUS1_SC0 (1 << 2)
#define RTC_STATUS1_SC1 (1 << 3)
#define RTC_STATUS1_INT1 (1 << 4)
#define RTC_STATUS1_INT2 (1 << 5)
#define RTC_STATUS1_BLD (1 << 6)
#define RTC_STATUS1_POC (1 << 7)
#define RTC_STATUS2_INT1FE (1 << 0)
#define RTC_STATUS2_INT1ME (1 << 1)
#define RTC_STATUS2_INT1AE (1 << 2)
#define RTC_STATUS2_32KE (1 << 3)
#define RTC_STATUS2_SC2 (1 << 4)
#define RTC_STATUS2_SC3 (1 << 5)
#define RTC_STATUS2_INT2AE (1 << 6)
#define RTC_STATUS2_TEST (1 << 7)
#define RTC_REG_STATUS1 0b00000110
#define RTC_REG_STATUS2 0b01000110
#define RTC_REG_DATA1 0b00100110
#define RTC_REG_DATA2 0b01100110
#define RTC_REG_ALARM1 0b00010110
#define RTC_REG_ALARM2 0b01010110
#define RTC_REG_ADJUST 0b00110110
#define RTC_REG_FREE 0b01110110
#define RTC_EXREG_UPCOUNT 0b00001110
#define RTC_EXREG_FOUT1 0b01001110
#define RTC_EXREG_FOUT2 0b00101110
#define RTC_EXREG_ALARM_EX1 0b00011110
#define RTC_EXREG_ALARM_EX2 0b01011110
typedef struct
{
/// @brief Represents the year 20xx as the last 2 digits in BCD format.
u8 year;
/// @brief Month of the year from 01 to 12 in BCD format.
u8 month;
/// @brief Day of the month from 01 to 31 in BCD format.
u8 monthDay;
/// @brief Day of the week from 0 to 6.
/// @note This is only a counter value. The RTC increases the counter
/// each day, and wraps from 6 back to 0. As such which number
/// corresponds to Monday is user defined.
u8 weekDay;
} rtc_date_t;
typedef struct
{
u8 hour : 6;
u8 amPm : 2;
/// @brief Minute from 00 to 59 in BCD format.
u8 minute;
/// @brief Second from 00 to 59 in BCD format.
u8 second;
} rtc_time_t;
typedef struct
{
rtc_date_t date;
rtc_time_t time;
} rtc_datetime_t;
typedef struct
{
u8 weekDay : 7;
u8 weekDayEnable : 1;
u8 hour : 6;
u8 amPm : 1;
u8 hourEnable : 1;
u8 minute : 7;
u8 minuteEnable : 1;
} rtc_alarm_t;
#ifdef LIBTWL_ARM7
#ifdef __cplusplus
extern "C" {
#endif
void rtc_init(void);
void rtc_readRegister(u32 reg, u8* dst, u32 length);
void rtc_writeRegister(u32 reg, const u8* src, u32 length);
static inline u32 rtc_readStatus1(void)
{
u8 status1;
rtc_readRegister(RTC_REG_STATUS1, &status1, 1);
return status1;
}
static inline void rtc_writeStatus1(u8 status1)
{
rtc_writeRegister(RTC_REG_STATUS1, &status1, 1);
}
static inline u32 rtc_readStatus2(void)
{
u8 status2;
rtc_readRegister(RTC_REG_STATUS2, &status2, 1);
return status2;
}
static inline void rtc_writeStatus2(u8 status2)
{
rtc_writeRegister(RTC_REG_STATUS2, &status2, 1);
}
static inline void rtc_readDateTime(rtc_datetime_t* dateTime)
{
rtc_readRegister(RTC_REG_DATA1, (u8*)dateTime, 7);
}
static inline void rtc_readDate(rtc_date_t* date)
{
rtc_readRegister(RTC_REG_DATA1, (u8*)date, 4);
}
static inline void rtc_readTime(rtc_time_t* time)
{
rtc_readRegister(RTC_REG_DATA2, (u8*)time, 3);
}
static inline void rtc_readAlarm1(rtc_alarm_t* alarm1)
{
rtc_readRegister(RTC_REG_ALARM1, (u8*)alarm1, 3);
}
static inline void rtc_writeAlarm1(const rtc_alarm_t* alarm1)
{
rtc_writeRegister(RTC_REG_ALARM1, (const u8*)alarm1, 3);
}
static inline void rtc_readAlarm2(rtc_alarm_t* alarm2)
{
rtc_readRegister(RTC_REG_ALARM2, (u8*)alarm2, 3);
}
static inline void rtc_writeAlarm2(const rtc_alarm_t* alarm2)
{
rtc_writeRegister(RTC_REG_ALARM2, (const u8*)alarm2, 3);
}
static inline u32 rtc_readAdjust(void)
{
u8 adjust;
rtc_readRegister(RTC_REG_ADJUST, &adjust, 1);
return adjust;
}
static inline u32 rtc_readFree(void)
{
u8 free;
rtc_readRegister(RTC_REG_FREE, &free, 1);
return free;
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,62 @@
#pragma once
#define REG_SOUNDCNT (*(vu32*)0x04000500)
#define REG_SOUNDBIAS (*(vu32*)0x04000504)
#define SOUNDCNT_MASTER_VOLUME(x) ((x) << 0)
#define SOUNDCNT_LEFT_OUT_MIXER (0 << 8)
#define SOUNDCNT_LEFT_OUT_CH1 (1 << 8)
#define SOUNDCNT_LEFT_OUT_CH3 (2 << 8)
#define SOUNDCNT_LEFT_OUT_CH1_CH3 (3 << 8)
#define SOUNDCNT_RIGHT_OUT_MIXER (0 << 10)
#define SOUNDCNT_RIGHT_OUT_CH1 (1 << 10)
#define SOUNDCNT_RIGHT_OUT_CH3 (2 << 10)
#define SOUNDCNT_RIGHT_OUT_CH1_CH3 (3 << 10)
#define SOUNDCNT_CH1_MIX_DISABLE (1 << 12)
#define SOUNDCNT_CH3_MIX_DISABLE (1 << 13)
#define SOUNDCNT_MASTER_ENABLE (1 << 15)
#ifdef __cplusplus
extern "C" {
#endif
static inline void snd_setMasterVolume(u8 volume)
{
*(vu8*)&REG_SOUNDCNT = volume;
}
static inline void snd_setOutputs(int left, int right)
{
REG_SOUNDCNT = (REG_SOUNDCNT & ~0xF00) | left | right;
}
static inline void snd_setCh1ToMixer(bool outputToMixer)
{
if (outputToMixer)
REG_SOUNDCNT &= ~SOUNDCNT_CH1_MIX_DISABLE;
else
REG_SOUNDCNT |= SOUNDCNT_CH1_MIX_DISABLE;
}
static inline void snd_setCh3ToMixer(bool outputToMixer)
{
if (outputToMixer)
REG_SOUNDCNT &= ~SOUNDCNT_CH3_MIX_DISABLE;
else
REG_SOUNDCNT |= SOUNDCNT_CH3_MIX_DISABLE;
}
static inline void snd_setMasterEnable(bool enabled)
{
if (enabled)
REG_SOUNDCNT |= SOUNDCNT_MASTER_ENABLE;
else
REG_SOUNDCNT &= ~SOUNDCNT_MASTER_ENABLE;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,27 @@
#pragma once
#define REG_SNDCAP0CNT (*(vu8*)0x04000508)
#define REG_SNDCAP1CNT (*(vu8*)0x04000509)
#define REG_SNDCAP0DAD (*(vu32*)0x04000510)
#define REG_SNDCAP0LEN (*(vu32*)0x04000514)
#define REG_SNDCAP1DAD (*(vu32*)0x04000518)
#define REG_SNDCAP1LEN (*(vu32*)0x0400051C)
#define SNDCAP0CNT_CH0_ADD_CH1 (1 << 0)
#define SNDCAP1CNT_CH2_ADD_CH3 (1 << 0)
#define SNDCAP0CNT_SRC_LEFT_MIXER (0 << 1)
#define SNDCAP0CNT_SRC_CH0 (1 << 1)
#define SNDCAP1CNT_SRC_RIGHT_MIXER (0 << 1)
#define SNDCAP1CNT_SRC_CH2 (1 << 1)
#define SNDCAPCNT_REPEAT_LOOP (0 << 2)
#define SNDCAPCNT_REPEAT_OFF (1 << 2)
#define SNDCAPCNT_FORMAT_PCM16 (0 << 3)
#define SNDCAPCNT_FORMAT_PCM8 (1 << 3)
#define SNDCAPCNT_ENABLE (1 << 7)
#define SNDCAPCNT_BUSY (1 << 7)

View File

@ -0,0 +1,139 @@
#pragma once
/// @brief Sets the volume of the sound channel.
#define SOUNDCNT_VOLUME(x) ((x) << 0)
/// @brief No shift is applied to samples (100% volume).
#define SOUNDCNT_SHIFT_0 (0 << 8)
/// @brief Sample values are shifted right by 1 (50% volume).
#define SOUNDCNT_SHIFT_1 (1 << 8)
/// @brief Sample values are shifted right by 2 (25% volume).
#define SOUNDCNT_SHIFT_2 (2 << 8)
/// @brief Sample values are shifted right by 4 (6.25% volume).
#define SOUNDCNT_SHIFT_4 (3 << 8)
/// @brief When set the last sample value keeps being output when
/// playback ends in SOUNDCNT_MODE_ONCE.
/// @note This is bugged in the sense that when restarting the
/// channel it will stop outputting for a few samples.
#define SOUNDCNT_HOLD (1 << 15)
/// @brief Sets the pan of the sound channel. 0 = left, 127 = right.
/// @note The pan is actually the volume ratio between the left and right
/// speaker. When setting center (64) the volume level will
/// be 50% on each speaker. To get full volume for mono sounds
/// you need two sound channels.
#define SOUNDCNT_PAN(x) ((x) << 16)
/// @brief Square wave duty cycle of 12.5%.
#define SOUNDCNT_DUTY_12_5 (0 << 24)
/// @brief Square wave duty cycle of 25.0%.
#define SOUNDCNT_DUTY_25_0 (1 << 24)
/// @brief Square wave duty cycle of 37.5%.
#define SOUNDCNT_DUTY_37_5 (2 << 24)
/// @brief Square wave duty cycle of 50.0%.
#define SOUNDCNT_DUTY_50_0 (3 << 24)
/// @brief Square wave duty cycle of 62.5%.
#define SOUNDCNT_DUTY_62_5 (4 << 24)
/// @brief Square wave duty cycle of 75.0%.
#define SOUNDCNT_DUTY_75_0 (5 << 24)
/// @brief Square wave duty cycle of 87.5%.
#define SOUNDCNT_DUTY_87_5 (6 << 24)
/// @brief The sound channel must be manually stopped.
#define SOUNDCNT_MODE_MANUAL (0 << 27)
/// @brief The sound channel plays PNT once, then loops LEN infinitely.
#define SOUNDCNT_MODE_LOOP (1 << 27)
/// @brief The sound channel stops automatically when the end is reached (PNT + LEN).
#define SOUNDCNT_MODE_ONCE (2 << 27)
/// @brief Signed 8 bit PCM.
/// @note PCM8 value 0xAB is treated as PCM16 value 0xAB00.
#define SOUNDCNT_FORMAT_PCM8 (0 << 29)
/// @brief Signed 16 bit PCM.
#define SOUNDCNT_FORMAT_PCM16 (1 << 29)
/// @brief IMA-ADPCM.
#define SOUNDCNT_FORMAT_ADPCM (2 << 29)
/// @brief Not available on channels 0-7, square wave on channels 8-13, noise on channels 14-15.
#define SOUNDCNT_FORMAT_PSG (3 << 29)
/// @brief Gets or sets whether the channel is currently playing.
#define SOUNDCNT_ENABLED (1 << 31)
#ifdef LIBTWL_ARM7
/// @brief Sound channel x control register.
#define REG_SOUNDxCNT(x) (*(vu32*)(0x04000400 + (x) * 0x10))
/// @brief Sound channel x source address register.
#define REG_SOUNDxSAD(x) (*(vu32*)(0x04000404 + (x) * 0x10))
/// @brief Sound channel x timer register.
/// @note Reload value of an increasing timer that runs at 16756991 Hz.
/// A new sample is fetched when the timer overflows.
/// Usually computed as -16756991 / frequency.
#define REG_SOUNDxTMR(x) (*(vu16*)(0x04000408 + (x) * 0x10))
/// @brief Sound channel x loop point register.
/// @note Counted in 32 bit words.
#define REG_SOUNDxPNT(x) (*(vu16*)(0x0400040A + (x) * 0x10))
/// @brief Sound channel x length register.
/// @note Counted in 32 bit words. Minimum length is 4 words (=16 bytes).
#define REG_SOUNDxLEN(x) (*(vu32*)(0x0400040C + (x) * 0x10))
#ifdef __cplusplus
extern "C" {
#endif
/// @brief Starts the given sound channel.
/// @param channel The channel to start.
static inline void snd_startChannel(u32 channel)
{
REG_SOUNDxCNT(channel) |= SOUNDCNT_ENABLED;
}
/// @brief Stops the given sound channel.
/// @param channel The channel to stop.
static inline void snd_stopChannel(u32 channel)
{
REG_SOUNDxCNT(channel) &= ~SOUNDCNT_ENABLED;
}
/// @brief Checks whether the given sound channel is playing.
/// @param channel The channel to check.
/// @return True if the channel is playing, or false otherwise.
static inline bool snd_isChannelPlaying(u32 channel)
{
return REG_SOUNDxCNT(channel) & SOUNDCNT_ENABLED;
}
/// @brief Sets the volume of the given sound channel.
/// @param channel The channel to set the volume of.
/// @param volume The volume to set.
static inline void snd_setChannelVolume(u32 channel, u32 volume)
{
((vu8*)&REG_SOUNDxCNT(channel))[0] = volume;
}
/// @brief Sets the pan of the given sound channel.
/// @param channel The channel to set the pan of.
/// @param pan The pan to set.
static inline void snd_setChannelPan(u32 channel, u32 pan)
{
((vu8*)&REG_SOUNDxCNT(channel))[2] = pan;
}
/// @brief Sets the timer value of the given sound channel.
/// @param channel The channel to set the timer value of.
/// @param timer The timer value to set.
static inline void snd_setChannelTimer(u32 channel, u16 timer)
{
REG_SOUNDxTMR(channel) = timer;
}
#ifdef __cplusplus
}
#endif
#endif

166
libtwl7/source/sio/sioRtc.c Normal file
View File

@ -0,0 +1,166 @@
#include <nds.h>
#include "libtwl/sio/sio.h"
#include "libtwl/sio/sioRtc.h"
// rtc setup/hold duration
#define RTC_WAIT_200NS 0
// rtc clock pulse duration
#define RTC_WAIT_1US 7
/// @brief Waits the given number of iterations of a loop
/// that takes 4 cycles per iteration.
/// @note Calling this method and returning takes at least 8 cycles.
/// As such the number of cycles is 8 + iterations * 4.
extern void rtc_waitByLoop(int iterations);
static inline void sendBit(u32 bit)
{
REG_RCNT1 = (REG_RCNT1 & ~(RCNT1_DATA_RTC_SIO | RCNT1_DATA_RTC_SCK)) | (bit ? RCNT1_DATA_RTC_SIO : 0);
rtc_waitByLoop(RTC_WAIT_1US);
REG_RCNT1 |= RCNT1_DATA_RTC_SCK;
rtc_waitByLoop(RTC_WAIT_1US);
}
static inline void sendByte(u32 byte)
{
// all rtc pins to output, CS high
sio_setRtcPins(
RCNT1_DIR_RTC_CS_OUTPUT | RCNT1_DIR_RTC_SCK_OUTPUT | RCNT1_DIR_RTC_SIO_OUTPUT,
RCNT1_DATA_RTC_CS);
for (u32 i = 0; i < 8; i++)
{
sendBit((byte >> i) & 1);
}
}
static inline u32 receiveBit(void)
{
REG_RCNT1 &= ~(RCNT1_DATA_RTC_SIO | RCNT1_DATA_RTC_SCK);
rtc_waitByLoop(RTC_WAIT_1US);
u32 result = REG_RCNT1 & RCNT1_DATA_RTC_SIO;
REG_RCNT1 |= RCNT1_DATA_RTC_SCK;
rtc_waitByLoop(RTC_WAIT_1US);
return result;
}
static inline u32 receiveByte(void)
{
// CS and SCK output, SIO input, CS high
sio_setRtcPins(
RCNT1_DIR_RTC_CS_OUTPUT | RCNT1_DIR_RTC_SCK_OUTPUT,
RCNT1_DATA_RTC_CS);
u32 result = 0;
for (u32 i = 0; i < 8; i++)
{
result = (result >> 1) | (receiveBit() << 7);
}
return result;
}
static void startTransfer(void)
{
// to use the rtc pins we must be in gpio mode
sio_setGpioMode(RCNT0_L_MODE_GPIO);
// all rtc pins to output, SCK high
sio_setRtcPins(
RCNT1_DIR_RTC_CS_OUTPUT | RCNT1_DIR_RTC_SCK_OUTPUT | RCNT1_DIR_RTC_SIO_OUTPUT,
RCNT1_DATA_RTC_SCK);
rtc_waitByLoop(RTC_WAIT_200NS); // setup/hold
// set CS high
sio_setRtcChipSelect(true);
rtc_waitByLoop(RTC_WAIT_200NS); // setup/hold
}
static void endTransfer(void)
{
rtc_waitByLoop(RTC_WAIT_200NS); // setup/hold
// set CS low
sio_setRtcChipSelect(false);
rtc_waitByLoop(RTC_WAIT_200NS); // setup/hold
}
static int bcdToDecimal(u8 bcd)
{
u32 ones = bcd & 0xF;
if (ones > 9)
return -1;
u32 tens = bcd >> 4;
if (tens > 9)
return -1;
return tens * 10 + ones;
}
static u8 decimalToBcd(u32 decimal)
{
u32 ones = decimal % 10;
u32 tens = decimal / 10;
return (tens << 4) | ones;
}
static void alarmTo24Hour(rtc_alarm_t* alarm)
{
int alarm1Hour = bcdToDecimal(alarm->hour);
if (alarm1Hour < 0 || alarm1Hour > 23)
{
alarm->hour = 0;
alarm->amPm = RTC_AM;
}
else if (alarm->amPm != RTC_AM && alarm1Hour < 12)
{
alarm->hour = decimalToBcd(alarm1Hour + 12);
}
else if (alarm1Hour >= 12)
{
alarm->amPm = RTC_PM;
}
}
void rtc_init(void)
{
u32 status1 = rtc_readStatus1();
u32 status2 = rtc_readStatus2();
if ((status1 & (RTC_STATUS1_POC | RTC_STATUS1_BLD)) || (status2 & RTC_STATUS2_TEST))
{
status1 |= RTC_STATUS1_RESET;
rtc_writeStatus1(status1);
}
if (status1 & (RTC_STATUS1_INT1 | RTC_STATUS1_INT2))
{
status2 &= ~(RTC_STATUS2_INT1FE | RTC_STATUS2_INT1ME | RTC_STATUS2_INT1AE | RTC_STATUS2_32KE);
status2 &= ~RTC_STATUS2_INT2AE;
rtc_writeStatus2(status2);
}
if (!(status1 & RTC_STATUS1_24HOUR))
{
status1 |= RTC_STATUS1_24HOUR;
rtc_writeStatus1(status1);
rtc_alarm_t alarm1;
rtc_readAlarm1(&alarm1);
alarmTo24Hour(&alarm1);
rtc_writeAlarm1(&alarm1);
rtc_alarm_t alarm2;
rtc_readAlarm2(&alarm2);
alarmTo24Hour(&alarm2);
rtc_writeAlarm2(&alarm2);
}
}
void rtc_readRegister(u32 reg, u8* dst, u32 length)
{
reg |= 0x80; // read
startTransfer();
sendByte(reg);
for (u32 i = 0; i < length; i++)
dst[i] = receiveByte();
endTransfer();
}
void rtc_writeRegister(u32 reg, const u8* src, u32 length)
{
reg &= ~0x80; // write
startTransfer();
sendByte(reg);
for (u32 i = 0; i < length; i++)
sendByte(src[i]);
endTransfer();
}

View File

@ -0,0 +1,9 @@
.text
.arm
.global rtc_waitByLoop
.type rtc_waitByLoop, %function
rtc_waitByLoop:
subs r0, r0, #1
bge rtc_waitByLoop
bx lr

126
libtwl9/Makefile Normal file
View File

@ -0,0 +1,126 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------
TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := source source/dma source/gx source/ipc source/math source/mem source/rtos source/gfx ../common/source/rtos ../common/source/ipc ../common/source/card
DATA := data
INCLUDES := include ../common/include
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -marm -mthumb-interwork -DLIBTWL_ARM9 -DARM9
CFLAGS := -g -Wall -O2\
-march=armv5te -mtune=arm946e-s \
-fomit-frame-pointer -ffast-math \
-ffunction-sections -fdata-sections\
-Werror=implicit-function-declaration\
$(ARCH)
CFLAGS += $(INCLUDE)
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fno-threadsafe-statics
ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s
LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),--use-blx -ffunction-sections -fdata-sections
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/lib/$(TARGET).a
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
lib:
@[ -d $@ ] || mkdir -p $@
$(BUILD): lib
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) lib
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT) : $(OFILES)
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@ -0,0 +1,7 @@
#pragma once
#define GFX_BG_MAIN ((vu16*)0x06000000)
#define GFX_BG_SUB ((vu16*)0x06200000)
#define GFX_OBJ_MAIN ((vu16*)0x06400000)
#define GFX_OBJ_SUB ((vu16*)0x06600000)

View File

@ -0,0 +1,156 @@
#pragma once
#define DISP3DCNT_TEXTURE_MAPPING (1 << 0)
#define DISP3DCNT_TOON_SHADING (0 << 1)
#define DISP3DCNT_HIGHLIGHT_SHADING (1 << 1)
#define DISP3DCNT_ALPHA_TEST (1 << 2)
#define DISP3DCNT_ALPHA_BLENDING (1 << 3)
#define DISP3DCNT_ANTI_ALIASING (1 << 4)
#define DISP3DCNT_EDGE_MARKING (1 << 5)
#define DISP3DCNT_FOG_MODE_COLOR_ALPHA (0 << 6)
#define DISP3DCNT_FOG_MODE_ALPHA (1 << 6)
#define DISP3DCNT_FOG (1 << 7)
#define DISP3DCNT_FOG_SHIFT(x) ((x) << 8)
#define DISP3DCNT_COLOR_BUFFER_UNDERFLOW (1 << 12)
#define DISP3DCNT_POLY_VTX_RAM_OVERFLOW (1 << 13)
#define DISP3DCNT_CLEAR_IMAGE (1 << 14)
#define GXSTAT_TEST_BUSY (1 << 0)
#define GXSTAT_BOX_TEST_RESULT (1 << 1)
#define GXSTAT_POS_VEC_MTX_STACK_LEVEL_MASK (0x1F)
#define GXSTAT_POS_VEC_MTX_STACK_LEVEL_SHIFT (8)
#define GXSTAT_PROJ_MTX_STACK_LEVEL_MASK (1)
#define GXSTAT_PROJ_MTX_STACK_LEVEL_SHIFT (13)
#define GXSTAT_MTX_STACK_BUSY (1 << 14)
#define GXSTAT_MTX_STACK_ERROR (1 << 15)
#define GXSTAT_GEOMETRY_ENGINE_BUSY (1 << 27)
#define REG_DISP3DCNT (*(vu16*)0x04000060)
#define REG_RDLINES_COUNT (*(vu16*)0x04000320)
#define REG_EDGE_COLOR(x) (((vu32*)0x04000330)[(x)])
#define REG_ALPHA_TEST_REF (*(vu16*)0x04000340)
#define REG_CLEAR_COLOR (*(vu32*)0x04000350)
#define REG_CLEAR_DEPTH (*(vu16*)0x04000354)
#define REG_CLRIMAGE_OFFSET (*(vu16*)0x04000356)
#define REG_FOG_COLOR (*(vu32*)0x04000358)
#define REG_FOG_OFFSET (*(vu16*)0x0400035C)
#define REG_FOG_TABLE(x) (((vu32*)0x04000360)[(x)])
#define REG_GXSTAT (*(vu32*)0x04000600)
#define REG_LISTRAM_COUNT (*(vu16*)0x04000604)
#define REG_VTXRAM_COUNT (*(vu16*)0x04000606)
#define REG_DISP_1DOT_DEPTH (*(vu16*)0x04000610)
#ifdef __cplusplus
extern "C" {
#endif
void gx_init(void);
void gx_reset(void);
void gx_resetMatrixStack(void);
void gx_clearFifo(void);
static inline bool gx_getColorBufferUnderflow(void)
{
return REG_DISP3DCNT & DISP3DCNT_COLOR_BUFFER_UNDERFLOW;
}
static inline void gx_ackColorBufferUnderflow(void)
{
REG_DISP3DCNT |= DISP3DCNT_COLOR_BUFFER_UNDERFLOW;
}
static inline bool gx_getPolyVtxRamOverflow(void)
{
return REG_DISP3DCNT & DISP3DCNT_POLY_VTX_RAM_OVERFLOW;
}
static inline void gx_ackPolyVtxRamOverflow(void)
{
REG_DISP3DCNT |= DISP3DCNT_POLY_VTX_RAM_OVERFLOW;
}
static inline void gx_setClearImageEnabled(bool enabled)
{
if (enabled)
REG_DISP3DCNT |= DISP3DCNT_CLEAR_IMAGE;
else
REG_DISP3DCNT &= ~DISP3DCNT_CLEAR_IMAGE;
}
static inline bool gx_isTestBusy(void)
{
return REG_GXSTAT & GXSTAT_TEST_BUSY;
}
static inline void gx_waitTestBusy(void)
{
while (gx_isTestBusy());
}
static inline bool gx_getBoxTestResult(void)
{
return REG_GXSTAT & GXSTAT_BOX_TEST_RESULT;
}
static inline u32 gx_getPositionVectorMtxStackLevel(void)
{
return (REG_GXSTAT >> GXSTAT_POS_VEC_MTX_STACK_LEVEL_SHIFT) & GXSTAT_POS_VEC_MTX_STACK_LEVEL_MASK;
}
static inline u32 gx_getProjectionMtxStackLevel(void)
{
return (REG_GXSTAT >> GXSTAT_PROJ_MTX_STACK_LEVEL_SHIFT) & GXSTAT_PROJ_MTX_STACK_LEVEL_MASK;
}
static inline bool gx_isMtxStackBusy(void)
{
return REG_GXSTAT & GXSTAT_MTX_STACK_BUSY;
}
static inline void gx_waitMtxStackBusy(void)
{
while (gx_isMtxStackBusy());
}
static inline bool gx_getMtxStackError(void)
{
return REG_GXSTAT & GXSTAT_MTX_STACK_ERROR;
}
static inline void gx_ackMtxStackError(void)
{
REG_GXSTAT |= GXSTAT_MTX_STACK_ERROR;
}
static inline bool gx_isGeometryEngineBusy(void)
{
return REG_GXSTAT & GXSTAT_GEOMETRY_ENGINE_BUSY;
}
static inline void gx_waitGeometryEngineBusy(void)
{
while (gx_isGeometryEngineBusy());
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,361 @@
#pragma once
#include "../math/mathVec3.h"
enum
{
GX_CMD_NOP = 0x00,
GX_CMD_MTX_MODE = 0x10,
GX_CMD_MTX_PUSH,
GX_CMD_MTX_POP,
GX_CMD_MTX_STORE,
GX_CMD_MTX_RESTORE,
GX_CMD_MTX_IDENTITY,
GX_CMD_MTX_LOAD_44,
GX_CMD_MTX_LOAD_43,
GX_CMD_MTX_MULT_44,
GX_CMD_MTX_MULT_43,
GX_CMD_MTX_MULT_33,
GX_CMD_MTX_SCALE,
GX_CMD_MTX_TRANS,
GX_CMD_COLOR = 0x20,
GX_CMD_NORMAL,
GX_CMD_TEXCOORD,
GX_CMD_VTX_16,
GX_CMD_VTX_10,
GX_CMD_VTX_XY,
GX_CMD_VTX_XZ,
GX_CMD_VTX_YZ,
GX_CMD_VTX_DIFF,
GX_CMD_POLYGON_ATTR,
GX_CMD_TEXIMAGE_PARAM,
GX_CMD_PLTT_BASE,
GX_CMD_DIF_AMB = 0x30,
GX_CMD_SPE_EMI,
GX_CMD_LIGHT_VECTOR,
GX_CMD_LIGHT_COLOR,
GX_CMD_SHININESS,
GX_CMD_BEGIN_VTXS = 0x40,
GX_CMD_END_VTXS,
GX_CMD_SWAP_BUFFERS = 0x50,
GX_CMD_VIEWPORT = 0x60,
GX_CMD_BOX_TEST = 0x70,
GX_CMD_POS_TEST,
GX_CMD_VEC_TEST
};
typedef enum
{
GX_MTX_MODE_PROJECTION = 0,
GX_MTX_MODE_POSITION = 1,
GX_MTX_MODE_POSITION_VECTOR = 2,
GX_MTX_MODE_TEXTURE = 3
} GxMtxMode;
typedef enum
{
GX_PRIMITIVE_TRIANGLE = 0,
GX_PRIMITIVE_QUAD = 1,
GX_PRIMITIVE_TRIANGLE_STRIP = 2,
GX_PRIMITIVE_QUAD_STRIP = 3
} GxPrimitiveType;
typedef enum
{
GX_XLU_SORT_AUTO = 0,
GX_XLU_SORT_MANUAL = 1
} GxXluSortMode;
typedef enum
{
GX_DEPTH_MODE_Z = 0,
GX_DEPTH_MODE_W = 1
} GxDepthMode;
typedef enum
{
GX_TEXGEN_NONE = 0,
GX_TEXGEN_TEXCOORD = 1,
GX_TEXGEN_NORMAL = 2,
GX_TEXGEN_VERTEX = 3
} GxTexGen;
typedef enum
{
GX_TEXFMT_NONE = 0,
GX_TEXFMT_A3I5 = 1,
GX_TEXFMT_PLTT4 = 2,
GX_TEXFMT_PLTT16 = 3,
GX_TEXFMT_PLTT256 = 4,
GX_TEXFMT_COMP4x4 = 5,
GX_TEXFMT_A5I3 = 6,
GX_TEXFMT_DIRECT = 7
} GxTexFormat;
typedef enum
{
GX_TEXSIZE_8 = 0,
GX_TEXSIZE_16 = 1,
GX_TEXSIZE_32 = 2,
GX_TEXSIZE_64 = 3,
GX_TEXSIZE_128 = 4,
GX_TEXSIZE_256 = 5,
GX_TEXSIZE_512 = 6,
GX_TEXSIZE_1024 = 7
} GxTexSize;
typedef enum
{
GX_LIGHTMASK_NONE = 0b0000,
GX_LIGHTMASK_0 = 0b0001,
GX_LIGHTMASK_1 = 0b0010,
GX_LIGHTMASK_01 = 0b0011,
GX_LIGHTMASK_2 = 0b0100,
GX_LIGHTMASK_02 = 0b0101,
GX_LIGHTMASK_12 = 0b0110,
GX_LIGHTMASK_012 = 0b0111,
GX_LIGHTMASK_3 = 0b1000,
GX_LIGHTMASK_03 = 0b1001,
GX_LIGHTMASK_13 = 0b1010,
GX_LIGHTMASK_013 = 0b1011,
GX_LIGHTMASK_23 = 0b1100,
GX_LIGHTMASK_023 = 0b1101,
GX_LIGHTMASK_123 = 0b1110,
GX_LIGHTMASK_0123 = 0b1111
} GxLightMask;
typedef enum
{
GX_POLYGON_MODE_MODULATE = 0,
GX_POLYGON_MODE_DECAL = 1,
GX_POLYGON_MODE_TOON_HIGHLIGHT = 2,
GX_POLYGON_MODE_SHADOW = 3
} GxPolygonMode;
typedef enum
{
GX_DISPLAY_MODE_NONE = 0,
GX_DISPLAY_MODE_BACK = 1,
GX_DISPLAY_MODE_FRONT = 2,
GX_DISPLAY_MODE_BOTH = 3
} GxDisplayMode;
typedef enum
{
GX_DEPTH_FUNC_LESS = 0,
GX_DEPTH_FUNC_EQUAL = 1
} GxDepthFunc;
#define GX_CMD_PACK(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
#define REG_GXFIFO (*(vu32*)0x04000400)
#define REG_GX_MTX_MODE (*(vu32*)0x04000440)
#define REG_GX_MTX_PUSH (*(vu32*)0x04000444)
#define REG_GX_MTX_POP (*(vu32*)0x04000448)
#define REG_GX_MTX_STORE (*(vu32*)0x0400044C)
#define REG_GX_MTX_RESTORE (*(vu32*)0x04000450)
#define REG_GX_MTX_IDENTITY (*(vu32*)0x04000454)
#define REG_GX_MTX_LOAD_44 (*(vu32*)0x04000458)
#define REG_GX_MTX_LOAD_43 (*(vu32*)0x0400045C)
#define REG_GX_MTX_MULT_44 (*(vu32*)0x04000460)
#define REG_GX_MTX_MULT_43 (*(vu32*)0x04000464)
#define REG_GX_MTX_MULT_33 (*(vu32*)0x04000468)
#define REG_GX_MTX_SCALE (*(vu32*)0x0400046C)
#define REG_GX_MTX_TRANS (*(vu32*)0x04000470)
#define REG_GX_COLOR (*(vu32*)0x04000480)
#define REG_GX_NORMAL (*(vu32*)0x04000484)
#define REG_GX_TEXCOORD (*(vu32*)0x04000488)
#define REG_GX_VTX_16 (*(vu32*)0x0400048C)
#define REG_GX_VTX_10 (*(vu32*)0x04000490)
#define REG_GX_VTX_XY (*(vu32*)0x04000494)
#define REG_GX_VTX_XZ (*(vu32*)0x04000498)
#define REG_GX_VTX_YZ (*(vu32*)0x0400049C)
#define REG_GX_VTX_DIFF (*(vu32*)0x040004A0)
#define REG_GX_POLYGON_ATTR (*(vu32*)0x040004A4)
#define REG_GX_TEXIMAGE_PARAM (*(vu32*)0x040004A8)
#define REG_GX_TEXPLTT_BASE (*(vu32*)0x040004AC)
#define REG_GX_DIF_AMB (*(vu32*)0x040004C0)
#define REG_GX_SPE_EMI (*(vu32*)0x040004C4)
#define REG_GX_LIGHT_VECTOR (*(vu32*)0x040004C8)
#define REG_GX_LIGHT_COLOR (*(vu32*)0x040004CC)
#define REG_GX_SHININESS (*(vu32*)0x040004D0)
#define REG_GX_BEGIN_VTXS (*(vu32*)0x04000500)
#define REG_GX_END_VTXS (*(vu32*)0x04000504)
#define REG_GX_SWAP_BUFFERS (*(vu32*)0x04000540)
#define REG_GX_VIEWPORT (*(vu32*)0x04000580)
#define REG_GX_BOX_TEST (*(vu32*)0x040005C0)
#define REG_GX_POS_TEST (*(vu32*)0x040005C4)
#define REG_GX_VEC_TEST (*(vu32*)0x040005C8)
#define GX_VTX_PACK(a,b) ((u16)(a) | ((b) << 16))
static inline void gx_mtxMode(GxMtxMode mode)
{
REG_GX_MTX_MODE = mode;
}
static inline void gx_mtxPush(void)
{
REG_GX_MTX_PUSH = 0;
}
static inline void gx_mtxPop(int count)
{
REG_GX_MTX_POP = count;
}
static inline void gx_mtxStore(u32 id)
{
REG_GX_MTX_STORE = id;
}
static inline void gx_mtxRestore(u32 id)
{
REG_GX_MTX_RESTORE = id;
}
static inline void gx_mtxIdentity(void)
{
REG_GX_MTX_IDENTITY = 0;
}
static inline void gx_mtxScale(fx32 x, fx32 y, fx32 z)
{
REG_GX_MTX_SCALE = x;
REG_GX_MTX_SCALE = y;
REG_GX_MTX_SCALE = z;
}
static inline void gx_mtxScaleVec(const vec3_t* scale)
{
REG_GX_MTX_SCALE = scale->x;
REG_GX_MTX_SCALE = scale->y;
REG_GX_MTX_SCALE = scale->z;
}
static inline void gx_mtxTranslate(fx32 x, fx32 y, fx32 z)
{
REG_GX_MTX_TRANS = x;
REG_GX_MTX_TRANS = y;
REG_GX_MTX_TRANS = z;
}
static inline void gx_mtxTranslateVec(const vec3_t* translation)
{
REG_GX_MTX_TRANS = translation->x;
REG_GX_MTX_TRANS = translation->y;
REG_GX_MTX_TRANS = translation->z;
}
static inline void gx_polygonAttr(GxLightMask lightMask, GxPolygonMode polygonMode,
GxDisplayMode displayMode, bool xluDepthUpdate, bool clipFarPlane, bool render1Dot,
GxDepthFunc depthFunc, bool fogEnable, u32 alpha, u32 polygonId)
{
REG_GX_POLYGON_ATTR
= lightMask
| (polygonMode << 4)
| (displayMode << 6)
| (xluDepthUpdate << 11)
| (clipFarPlane << 12)
| (render1Dot << 13)
| (depthFunc << 14)
| (fogEnable << 15)
| ((alpha & 31) << 16)
| ((polygonId & 63) << 24);
}
static inline void gx_texImageParam(u16 address, bool repeatS, bool repeatT,
bool flipS, bool flipT, GxTexSize sizeS, GxTexSize sizeT, GxTexFormat format,
bool color0Transparent, GxTexGen texGen)
{
REG_GX_TEXIMAGE_PARAM
= address
| (repeatS << 16)
| (repeatT << 17)
| (flipS << 18)
| (flipT << 19)
| (sizeS << 20)
| (sizeT << 23)
| (format << 26)
| (color0Transparent << 29)
| (texGen << 30);
}
static inline void gx_texPlttBase(u16 address)
{
REG_GX_TEXPLTT_BASE = address;
}
static inline void gx_color(u32 color)
{
REG_GX_COLOR = color;
}
static inline void gx_texCoord(s16 s, s16 t)
{
REG_GX_TEXCOORD = (t << 16) | (u16)s;
}
static inline void gx_vtx16(fx16 x, fx16 y, fx16 z)
{
REG_GX_VTX_16 = GX_VTX_PACK(x, y);
REG_GX_VTX_16 = z;
}
static inline void gx_vtx10(int x, int y, int z)
{
REG_GX_VTX_10 = (x & 0x3FF) | ((y & 0x3FF) << 10) | (z << 20);
}
static inline void gx_vtxXY(fx16 x, fx16 y)
{
REG_GX_VTX_XY = GX_VTX_PACK(x, y);
}
static inline void gx_vtxXZ(fx16 x, fx16 z)
{
REG_GX_VTX_XZ = GX_VTX_PACK(x, z);
}
static inline void gx_vtxYZ(fx16 y, fx16 z)
{
REG_GX_VTX_YZ = GX_VTX_PACK(y, z);
}
static inline void gx_vtxDiff(int x, int y, int z)
{
REG_GX_VTX_10 = (x & 0x3FF) | ((y & 0x3FF) << 10) | (z << 20);
}
static inline void gx_beginVtxs(GxPrimitiveType type)
{
REG_GX_BEGIN_VTXS = type;
}
static inline void gx_endVtxs(void)
{
REG_GX_END_VTXS = 0;
}
static inline void gx_swapBuffers(GxXluSortMode xluSortMode, GxDepthMode depthMode)
{
REG_GX_SWAP_BUFFERS = xluSortMode | (depthMode << 1);
}
static inline void gx_viewport(u8 x1, u8 y1, u8 x2, u8 y2)
{
REG_GX_VIEWPORT = x1 | (y1 << 8) | (x2 << 16) | (y2 << 24);
}

View File

@ -0,0 +1,90 @@
#pragma once
#define GFX_OAM_MAIN ((vu16*)0x07000000)
#define GFX_OAM_SUB ((vu16*)0x07000400)
#define GFX_OAM_ATTR0_Y(y) ((y) & 0xFF)
#define GFX_OAM_ATTR0_AFFINE (1 << 8)
#define GFX_OAM_ATTR0_DOUBLE_AFFINE (3 << 8)
#define GFX_OAM_ATTR0_HIDDEN (2 << 8)
#define GFX_OAM_ATTR0_MODE_NORMAL (0 << 10)
#define GFX_OAM_ATTR0_MODE_TRANSLUCENT (1 << 10)
#define GFX_OAM_ATTR0_MODE_WINDOW (2 << 10)
#define GFX_OAM_ATTR0_MODE_BITMAP (3 << 10)
#define GFX_OAM_ATTR0_MOSAIC (1 << 12)
#define GFX_OAM_ATTR0_PLTT16 (0 << 13)
#define GFX_OAM_ATTR0_PLTT256 (1 << 13)
#define GFX_OAM_ATTR0_SHAPE_SQUARE (0 << 14)
#define GFX_OAM_ATTR0_SHAPE_LONG (1 << 14)
#define GFX_OAM_ATTR0_SHAPE_TALL (2 << 14)
#define GFX_OAM_ATTR0_SHAPE_8_8 GFX_OAM_ATTR0_SHAPE_SQUARE
#define GFX_OAM_ATTR0_SHAPE_16_16 GFX_OAM_ATTR0_SHAPE_SQUARE
#define GFX_OAM_ATTR0_SHAPE_32_32 GFX_OAM_ATTR0_SHAPE_SQUARE
#define GFX_OAM_ATTR0_SHAPE_64_64 GFX_OAM_ATTR0_SHAPE_SQUARE
#define GFX_OAM_ATTR0_SHAPE_16_8 GFX_OAM_ATTR0_SHAPE_LONG
#define GFX_OAM_ATTR0_SHAPE_32_8 GFX_OAM_ATTR0_SHAPE_LONG
#define GFX_OAM_ATTR0_SHAPE_32_16 GFX_OAM_ATTR0_SHAPE_LONG
#define GFX_OAM_ATTR0_SHAPE_64_32 GFX_OAM_ATTR0_SHAPE_LONG
#define GFX_OAM_ATTR0_SHAPE_8_16 GFX_OAM_ATTR0_SHAPE_TALL
#define GFX_OAM_ATTR0_SHAPE_8_32 GFX_OAM_ATTR0_SHAPE_TALL
#define GFX_OAM_ATTR0_SHAPE_16_32 GFX_OAM_ATTR0_SHAPE_TALL
#define GFX_OAM_ATTR0_SHAPE_32_64 GFX_OAM_ATTR0_SHAPE_TALL
#define GFX_OAM_ATTR1_X(x) ((x) & 0x1FF)
#define GFX_OAM_ATTR1_MTX(mtx) (((mtx) & 0x1F) << 9)
#define GFX_OAM_ATTR1_HFLIP (1 << 12)
#define GFX_OAM_ATTR1_VFLIP (1 << 13)
#define GFX_OAM_ATTR1_SIZE_0 (0 << 14)
#define GFX_OAM_ATTR1_SIZE_1 (1 << 14)
#define GFX_OAM_ATTR1_SIZE_2 (2 << 14)
#define GFX_OAM_ATTR1_SIZE_3 (3 << 14)
#define GFX_OAM_ATTR1_SIZE_8_8 GFX_OAM_ATTR1_SIZE_0
#define GFX_OAM_ATTR1_SIZE_16_8 GFX_OAM_ATTR1_SIZE_0
#define GFX_OAM_ATTR1_SIZE_8_16 GFX_OAM_ATTR1_SIZE_0
#define GFX_OAM_ATTR1_SIZE_16_16 GFX_OAM_ATTR1_SIZE_1
#define GFX_OAM_ATTR1_SIZE_32_8 GFX_OAM_ATTR1_SIZE_1
#define GFX_OAM_ATTR1_SIZE_8_32 GFX_OAM_ATTR1_SIZE_1
#define GFX_OAM_ATTR1_SIZE_32_32 GFX_OAM_ATTR1_SIZE_2
#define GFX_OAM_ATTR1_SIZE_32_16 GFX_OAM_ATTR1_SIZE_2
#define GFX_OAM_ATTR1_SIZE_16_32 GFX_OAM_ATTR1_SIZE_2
#define GFX_OAM_ATTR1_SIZE_64_64 GFX_OAM_ATTR1_SIZE_3
#define GFX_OAM_ATTR1_SIZE_64_32 GFX_OAM_ATTR1_SIZE_3
#define GFX_OAM_ATTR1_SIZE_32_64 GFX_OAM_ATTR1_SIZE_3
#define GFX_OAM_ATTR2_VRAM_OFFS(offs) ((offs) & 0x3FF)
#define GFX_OAM_ATTR2_PRIORITY(prio) (((prio) & 3) << 10)
#define GFX_OAM_ATTR2_PLTT(pltt) (((pltt) & 0xF) << 12)
#define GFX_OAM_ATTR2_BMP_ALPHA(alpha) (((alpha) & 0xF) << 12)
typedef struct
{
u16 attr0;
u16 attr1;
u16 attr2;
u16 affine;
} gfx_oam_entry_t;
typedef struct
{
u16 obj0[3];
s16 pa;
u16 obj1[3];
s16 pb;
u16 obj2[3];
s16 pc;
u16 obj3[3];
s16 pd;
} gfx_oam_mtx_t;
typedef union
{
gfx_oam_entry_t objs[128];
gfx_oam_mtx_t mtxs[32];
} gfx_oam_table_t;

View File

@ -0,0 +1,15 @@
#pragma once
#define GFX_PLTT_BG_MAIN ((vu16*)0x05000000)
#define GFX_PLTT_OBJ_MAIN ((vu16*)0x05000200)
#define GFX_PLTT_BG_SUB ((vu16*)0x05000400)
#define GFX_PLTT_OBJ_SUB ((vu16*)0x05000600)
typedef struct
{
u16 r : 5;
u16 g : 5; //g5-g1
u16 b : 5;
u16 g0 : 1;
} gfx_pltt_color_t;

View File

@ -0,0 +1,147 @@
#pragma once
#define REG_DIVCNT (*(vu32*)0x04000280)
#define REG_DIV_NUMER_LO (*(vs32*)0x04000290)
#define REG_DIV_NUMER (*(vs64*)0x04000290)
#define REG_DIV_DENOM_LO (*(vs32*)0x04000298)
#define REG_DIV_DENOM (*(vs64*)0x04000298)
#define REG_DIV_RESULT_LO (*(vs32*)0x040002A0)
#define REG_DIV_RESULT (*(vs64*)0x040002A0)
#define REG_DIVREM_RESULT_LO (*(vs32*)0x040002A8)
#define REG_DIVREM_RESULT (*(vs64*)0x040002A8)
#define MATH_DIVCNT_32_32 0
#define MATH_DIVCNT_64_32 1
#define MATH_DIVCNT_64_64 2
#define MATH_DIVCNT_DIV_BY_ZERO (1 << 14)
#define MATH_DIVCNT_BUSY (1 << 15)
#ifdef __cplusplus
extern "C" {
#endif
static inline void math_waitDiv(void)
{
while (REG_DIVCNT & MATH_DIVCNT_BUSY);
}
static inline void math_div32Async(s32 x, s32 y)
{
REG_DIVCNT = MATH_DIVCNT_32_32;
REG_DIV_NUMER_LO = x;
REG_DIV_DENOM_LO = y;
}
static inline s32 math_getDiv32Result(void)
{
return REG_DIV_RESULT_LO;
}
static inline s32 math_getRem32Result(void)
{
return REG_DIVREM_RESULT_LO;
}
static inline s32 math_div32(s32 x, s32 y)
{
math_div32Async(x, y);
math_waitDiv();
return REG_DIV_RESULT_LO;
}
static inline s32 math_rem32(s32 x, s32 y)
{
math_div32Async(x, y);
math_waitDiv();
return REG_DIVREM_RESULT_LO;
}
static inline s32 math_divRem32(s32 x, s32 y, s32* rem)
{
math_div32Async(x, y);
math_waitDiv();
*rem = REG_DIVREM_RESULT_LO;
return REG_DIV_RESULT_LO;
}
static inline void math_div6432Async(s64 x, s32 y)
{
REG_DIVCNT = MATH_DIVCNT_64_32;
REG_DIV_NUMER = x;
REG_DIV_DENOM_LO = y;
}
static inline s64 math_getDiv6432Result(void)
{
return REG_DIV_RESULT;
}
static inline s32 math_getRem6432Result(void)
{
return REG_DIVREM_RESULT_LO;
}
static inline s64 math_div6432(s64 x, s32 y)
{
math_div6432Async(x, y);
math_waitDiv();
return REG_DIV_RESULT;
}
static inline s32 math_rem6432(s64 x, s32 y)
{
math_div6432Async(x, y);
math_waitDiv();
return REG_DIVREM_RESULT_LO;
}
static inline s64 math_divRem6432(s64 x, s32 y, s32* rem)
{
math_div6432Async(x, y);
math_waitDiv();
*rem = REG_DIVREM_RESULT_LO;
return REG_DIV_RESULT;
}
static inline void math_div64Async(s64 x, s64 y)
{
REG_DIVCNT = MATH_DIVCNT_64_64;
REG_DIV_NUMER = x;
REG_DIV_DENOM = y;
}
static inline s64 math_getDiv64Result(void)
{
return REG_DIV_RESULT;
}
static inline s64 math_getRem64Result(void)
{
return REG_DIVREM_RESULT;
}
static inline s64 math_div64(s64 x, s64 y)
{
math_div64Async(x, y);
math_waitDiv();
return REG_DIV_RESULT;
}
static inline s64 math_rem64(s64 x, s64 y)
{
math_div64Async(x, y);
math_waitDiv();
return REG_DIVREM_RESULT;
}
static inline s64 math_divRem64(s64 x, s64 y, s64* rem)
{
math_div64Async(x, y);
math_waitDiv();
*rem = REG_DIVREM_RESULT;
return REG_DIV_RESULT;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,16 @@
#pragma once
typedef s16 fx16;
#define FX16_SHIFT 12
#define FX16_ONE (1 << FX16_SHIFT)
typedef s32 fx32;
#define FX32_SHIFT 12
#define FX32_ONE (1 << FX32_SHIFT)
static inline fx32 math_mulFx32(fx32 x, fx32 y)
{
return (((s64)x * y) + 0x800) >> FX32_SHIFT;
}

View File

@ -0,0 +1,54 @@
#pragma once
#define REG_SQRTCNT (*(vu32*)0x040002B0)
#define REG_SQRT_RESULT (*(vu32*)0x040002B4)
#define REG_SQRT_PARAM_LO (*(vu32*)0x040002B8)
#define REG_SQRT_PARAM (*(vu64*)0x040002B8)
#define MATH_SQRTCNT_32BIT 0
#define MATH_SQRTCNT_64BIT 1
#define MATH_SQRTCNT_BUSY (1 << 15)
#ifdef __cplusplus
extern "C" {
#endif
static inline void math_waitSqrt(void)
{
while (REG_SQRTCNT & MATH_SQRTCNT_BUSY);
}
static inline void math_sqrt32Async(u32 x)
{
REG_SQRTCNT = MATH_SQRTCNT_32BIT;
REG_SQRT_PARAM_LO = x;
}
static inline u32 math_getSqrtResult(void)
{
return REG_SQRT_RESULT;
}
static inline u32 math_sqrt32(u32 x)
{
math_sqrt32Async(x);
math_waitSqrt();
return REG_SQRT_RESULT;
}
static inline void math_sqrt64Async(u64 x)
{
REG_SQRTCNT = MATH_SQRTCNT_64BIT;
REG_SQRT_PARAM = x;
}
static inline u32 math_sqrt64(u64 x)
{
math_sqrt64Async(x);
math_waitSqrt();
return REG_SQRT_RESULT;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,52 @@
#pragma once
#include "mathFixed.h"
#include "mathSqrt.h"
typedef struct
{
fx32 x, y, z;
} vec3_t;
static inline void math_vecSet(vec3_t* dst, fx32 x, fx32 y, fx32 z)
{
dst->x = x;
dst->y = y;
dst->z = z;
}
static inline void math_vecAdd(vec3_t* dst, const vec3_t* a, const vec3_t* b)
{
dst->x = a->x + b->x;
dst->y = a->y + b->y;
dst->z = a->z + b->z;
}
static inline void math_vecSub(vec3_t* dst, const vec3_t* a, const vec3_t* b)
{
dst->x = a->x - b->x;
dst->y = a->y - b->y;
dst->z = a->z - b->z;
}
static inline void math_vecMul(vec3_t* dst, const vec3_t* a, fx32 b)
{
dst->x = math_mulFx32(a->x, b);
dst->y = math_mulFx32(a->y, b);
dst->z = math_mulFx32(a->z, b);
}
static inline fx32 math_vecDot(const vec3_t* a, const vec3_t* b)
{
return ((s64)a->x * b->x + (s64)a->y * b->y + (s64)a->z * b->z + 0x800) >> FX32_SHIFT;
}
static inline s64 math_vecMagSq64(const vec3_t* vec)
{
return (s64)vec->x * vec->x + (s64)vec->y * vec->y + (s64)vec->z * vec->z;
}
static inline s64 math_vecMag(const vec3_t* vec)
{
return math_sqrt64(math_vecMagSq64(vec));
}

View File

@ -0,0 +1,2 @@
#pragma once

View File

@ -0,0 +1,42 @@
#pragma once
typedef enum
{
MEM_NTR_WRAM_ARM9 = 0,
MEM_NTR_WRAM_ARM7 = 1
} MemNtrWramMapping;
#define REG_WRAMCNT (*(vu8*)0x04000247)
#ifdef __cplusplus
extern "C" {
#endif
static inline void mem_setNtrWram0Mapping(MemNtrWramMapping mapping)
{
REG_WRAMCNT = (REG_WRAMCNT & ~1) | mapping;
}
static inline MemNtrWramMapping mem_getNtrWram0Mapping(void)
{
return (MemNtrWramMapping)(REG_WRAMCNT & 1);
}
static inline void mem_setNtrWram1Mapping(MemNtrWramMapping mapping)
{
REG_WRAMCNT = (REG_WRAMCNT & ~2) | (mapping << 1);
}
static inline MemNtrWramMapping mem_getNtrWram1Mapping(void)
{
return (MemNtrWramMapping)((REG_WRAMCNT >> 1) & 1);
}
static inline void mem_setNtrWramMapping(MemNtrWramMapping block0, MemNtrWramMapping block1)
{
REG_WRAMCNT = block0 | (block1 << 1);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,2 @@
#pragma once

View File

@ -0,0 +1,2 @@
#pragma once

View File

@ -0,0 +1,207 @@
#pragma once
typedef enum
{
MEM_VRAM_AB_NONE = 0,
MEM_VRAM_AB_LCDC = 0x80,
MEM_VRAM_AB_MAIN_BG_00000 = 0x81,
MEM_VRAM_AB_MAIN_BG_20000 = 0x89,
MEM_VRAM_AB_MAIN_BG_40000 = 0x91,
MEM_VRAM_AB_MAIN_BG_60000 = 0x99,
MEM_VRAM_AB_MAIN_OBJ_00000 = 0x82,
MEM_VRAM_AB_MAIN_OBJ_20000 = 0x8A,
MEM_VRAM_AB_TEX_SLOT_0 = 0x83,
MEM_VRAM_AB_TEX_SLOT_1 = 0x8B,
MEM_VRAM_AB_TEX_SLOT_2 = 0x93,
MEM_VRAM_AB_TEX_SLOT_3 = 0x9B
} MemVramABMapping;
typedef enum
{
MEM_VRAM_C_NONE = 0,
MEM_VRAM_C_LCDC = 0x80,
MEM_VRAM_C_MAIN_BG_00000 = 0x81,
MEM_VRAM_C_MAIN_BG_20000 = 0x89,
MEM_VRAM_C_MAIN_BG_40000 = 0x91,
MEM_VRAM_C_MAIN_BG_60000 = 0x99,
MEM_VRAM_C_ARM7_00000 = 0x82,
MEM_VRAM_C_ARM7_20000 = 0x8A,
MEM_VRAM_C_TEX_SLOT_0 = 0x83,
MEM_VRAM_C_TEX_SLOT_1 = 0x8B,
MEM_VRAM_C_TEX_SLOT_2 = 0x93,
MEM_VRAM_C_TEX_SLOT_3 = 0x9B,
MEM_VRAM_C_SUB_BG_00000 = 0x84
} MemVramCMapping;
typedef enum
{
MEM_VRAM_D_NONE = 0,
MEM_VRAM_D_LCDC = 0x80,
MEM_VRAM_D_MAIN_BG_00000 = 0x81,
MEM_VRAM_D_MAIN_BG_20000 = 0x89,
MEM_VRAM_D_MAIN_BG_40000 = 0x91,
MEM_VRAM_D_MAIN_BG_60000 = 0x99,
MEM_VRAM_D_ARM7_00000 = 0x82,
MEM_VRAM_D_ARM7_20000 = 0x8A,
MEM_VRAM_D_TEX_SLOT_0 = 0x83,
MEM_VRAM_D_TEX_SLOT_1 = 0x8B,
MEM_VRAM_D_TEX_SLOT_2 = 0x93,
MEM_VRAM_D_TEX_SLOT_3 = 0x9B,
MEM_VRAM_D_SUB_OBJ_00000 = 0x84
} MemVramDMapping;
typedef enum
{
MEM_VRAM_E_NONE = 0,
MEM_VRAM_E_LCDC = 0x80,
MEM_VRAM_E_MAIN_BG_00000 = 0x81,
MEM_VRAM_E_MAIN_OBJ_00000 = 0x82,
MEM_VRAM_E_TEX_PLTT_SLOT_0123 = 0x83,
MEM_VRAM_E_MAIN_BG_EXT_PLTT_SLOT_0123 = 0x84
} MemVramEMapping;
typedef enum
{
MEM_VRAM_FG_NONE = 0,
MEM_VRAM_FG_LCDC = 0x80,
MEM_VRAM_FG_MAIN_BG_00000 = 0x81,
MEM_VRAM_FG_MAIN_BG_04000 = 0x89,
MEM_VRAM_FG_MAIN_BG_10000 = 0x91,
MEM_VRAM_FG_MAIN_BG_14000 = 0x99,
MEM_VRAM_FG_MAIN_OBJ_00000 = 0x82,
MEM_VRAM_FG_MAIN_OBJ_04000 = 0x8A,
MEM_VRAM_FG_MAIN_OBJ_10000 = 0x92,
MEM_VRAM_FG_MAIN_OBJ_14000 = 0x9A,
MEM_VRAM_FG_TEX_PLTT_SLOT_0 = 0x83,
MEM_VRAM_FG_TEX_PLTT_SLOT_1 = 0x8B,
MEM_VRAM_FG_TEX_PLTT_SLOT_4 = 0x93,
MEM_VRAM_FG_TEX_PLTT_SLOT_5 = 0x9B,
MEM_VRAM_FG_MAIN_BG_EXT_PLTT_SLOT_01 = 0x84,
MEM_VRAM_FG_MAIN_BG_EXT_PLTT_SLOT_23 = 0x8C,
MEM_VRAM_FG_MAIN_OBJ_EXT_PLTT = 0x85
} MemVramFGMapping;
typedef enum
{
MEM_VRAM_H_NONE = 0,
MEM_VRAM_H_LCDC = 0x80,
MEM_VRAM_H_SUB_BG_00000 = 0x81,
MEM_VRAM_H_SUB_BG_EXT_PLTT_SLOT_0123 = 0x82
} MemVramHMapping;
typedef enum
{
MEM_VRAM_I_NONE = 0,
MEM_VRAM_I_LCDC = 0x80,
MEM_VRAM_I_SUB_BG_08000 = 0x81,
MEM_VRAM_I_SUB_OBJ_00000 = 0x82,
MEM_VRAM_I_SUB_OBJ_EXT_PLTT = 0x83
} MemVramIMapping;
#define REG_VRAMCNT_A (*(vu8*)0x04000240)
#define REG_VRAMCNT_B (*(vu8*)0x04000241)
#define REG_VRAMCNT_C (*(vu8*)0x04000242)
#define REG_VRAMCNT_D (*(vu8*)0x04000243)
#define REG_VRAMCNT_E (*(vu8*)0x04000244)
#define REG_VRAMCNT_F (*(vu8*)0x04000245)
#define REG_VRAMCNT_G (*(vu8*)0x04000246)
#define REG_VRAMCNT_H (*(vu8*)0x04000248)
#define REG_VRAMCNT_I (*(vu8*)0x04000249)
#ifdef __cplusplus
extern "C" {
#endif
static inline void mem_setVramAMapping(MemVramABMapping mapping)
{
REG_VRAMCNT_A = (u8)mapping;
}
static inline MemVramABMapping mem_getVramAMapping(void)
{
return (MemVramABMapping)REG_VRAMCNT_A;
}
static inline void mem_setVramBMapping(MemVramABMapping mapping)
{
REG_VRAMCNT_B = (u8)mapping;
}
static inline MemVramABMapping mem_getVramBMapping(void)
{
return (MemVramABMapping)REG_VRAMCNT_B;
}
static inline void mem_setVramCMapping(MemVramCMapping mapping)
{
REG_VRAMCNT_C = (u8)mapping;
}
static inline MemVramCMapping mem_getVramCMapping(void)
{
return (MemVramCMapping)REG_VRAMCNT_C;
}
static inline void mem_setVramDMapping(MemVramDMapping mapping)
{
REG_VRAMCNT_D = (u8)mapping;
}
static inline MemVramDMapping mem_getVramDMapping(void)
{
return (MemVramDMapping)REG_VRAMCNT_D;
}
static inline void mem_setVramEMapping(MemVramEMapping mapping)
{
REG_VRAMCNT_E = (u8)mapping;
}
static inline MemVramEMapping mem_getVramEMapping(void)
{
return (MemVramEMapping)REG_VRAMCNT_E;
}
static inline void mem_setVramFMapping(MemVramFGMapping mapping)
{
REG_VRAMCNT_F = (u8)mapping;
}
static inline MemVramFGMapping mem_getVramFMapping(void)
{
return (MemVramFGMapping)REG_VRAMCNT_F;
}
static inline void mem_setVramGMapping(MemVramFGMapping mapping)
{
REG_VRAMCNT_G = (u8)mapping;
}
static inline MemVramFGMapping mem_getVramGMapping(void)
{
return (MemVramFGMapping)REG_VRAMCNT_G;
}
static inline void mem_setVramHMapping(MemVramHMapping mapping)
{
REG_VRAMCNT_H = (u8)mapping;
}
static inline MemVramHMapping mem_getVramHMapping(void)
{
return (MemVramHMapping)REG_VRAMCNT_H;
}
static inline void mem_setVramIMapping(MemVramIMapping mapping)
{
REG_VRAMCNT_I = (u8)mapping;
}
static inline MemVramIMapping mem_getVramIMapping(void)
{
return (MemVramIMapping)REG_VRAMCNT_I;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,70 @@
#pragma once
#define POWCNT_LCD_ENABLE (1 << 0)
#define POWCNT_2D_GRAPHICS_MAIN_ENABLE (1 << 1)
#define POWCNT_3D_RENDER_ENGINE_ENABLE (1 << 2)
#define POWCNT_3D_GEOMETRY_ENGINE_ENABLE (1 << 3)
#define POWCNT_2D_GRAPHICS_SUB_ENABLE (1 << 9)
#define POWCNT_DISP_SUB_TOP_MAIN_BOTTOM (0 << 15)
#define POWCNT_DISP_MAIN_TOP_SUB_BOTTOM (1 << 15)
#define REG_POWCNT (*(vu16*)0x04000304)
#ifdef __cplusplus
extern "C" {
#endif
static inline void sys_set2DGraphicsMainPower(bool enabled)
{
if (enabled)
REG_POWCNT |= POWCNT_2D_GRAPHICS_MAIN_ENABLE;
else
REG_POWCNT &= ~POWCNT_2D_GRAPHICS_MAIN_ENABLE;
}
static inline void sys_set3DRenderEnginePower(bool enabled)
{
if (enabled)
REG_POWCNT |= POWCNT_3D_RENDER_ENGINE_ENABLE;
else
REG_POWCNT &= ~POWCNT_3D_RENDER_ENGINE_ENABLE;
}
static inline void sys_set3DGeometryEnginePower(bool enabled)
{
if (enabled)
REG_POWCNT |= POWCNT_3D_GEOMETRY_ENGINE_ENABLE;
else
REG_POWCNT &= ~POWCNT_3D_GEOMETRY_ENGINE_ENABLE;
}
static inline void sys_set2DGraphicsSubPower(bool enabled)
{
if (enabled)
REG_POWCNT |= POWCNT_2D_GRAPHICS_SUB_ENABLE;
else
REG_POWCNT &= ~POWCNT_2D_GRAPHICS_SUB_ENABLE;
}
static inline void sys_setMainEngineToTopScreen(void)
{
REG_POWCNT |= POWCNT_DISP_MAIN_TOP_SUB_BOTTOM;
}
static inline void sys_setMainEngineToBottomScreen(void)
{
REG_POWCNT &= ~POWCNT_DISP_MAIN_TOP_SUB_BOTTOM;
}
static inline void sys_setMainEngineScreen(bool topScreen)
{
if (topScreen)
REG_POWCNT |= POWCNT_DISP_MAIN_TOP_SUB_BOTTOM;
else
REG_POWCNT &= ~POWCNT_DISP_MAIN_TOP_SUB_BOTTOM;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,53 @@
#ifdef LIBTWL_ARM9
.section .itcm
#else
.text
#endif
.arm
//r0=dma number
//r1=src
//r2=dst
//r3=control
.global dma_ntrSetParams
dma_ntrSetParams:
ldr r12,= 0x040000B0
add r0, r0, r0, lsl #1 //multiply by 3 (regs)
add r12, r12, r0, lsl #2
stmia r12, {r1,r2,r3}
b 1f //delay for safety
1:
bx lr
//r0=dma number
.global dma_ntrStopSafe
dma_ntrStopSafe:
//disable irqs
mrs r3, cpsr
orr r1, r3, #0x80
msr cpsr_c, r1
ldr r12,= 0x040000BA
add r0, r0, r0, lsl #1 //multiply by 3 (regs)
add r12, r12, r0, lsl #2
ldrh r0, [r12]
bic r0, r0, #0x3A00 //clear mode and repeat bits
strh r0, [r12]
//delay for safety
b 1f
1:
#ifdef LIBTWL_ARM9
b 2f
2:
#endif
ldrh r0, [r12]
bic r0, r0, #0x8000 //clear enable bit
strh r0, [r12]
//restore irqs
msr cpsr_c, r3
bx lr
.pool
.end

View File

@ -0,0 +1,62 @@
#include <nds.h>
#include "libtwl/gfx/gfx3dCmd.h"
#include "libtwl/sys/sysPower.h"
#include "libtwl/gfx/gfx3d.h"
void gx_init(void)
{
sys_set3DGeometryEnginePower(true);
sys_set3DRenderEnginePower(true);
gx_clearFifo();
gx_endVtxs();
gx_waitGeometryEngineBusy();
REG_DISP3DCNT = DISP3DCNT_ANTI_ALIASING | DISP3DCNT_ALPHA_BLENDING | DISP3DCNT_TEXTURE_MAPPING;
REG_GXSTAT = 0;
gx_reset();
REG_CLEAR_COLOR = 0;
REG_CLEAR_DEPTH = 0x7FFF;
REG_CLRIMAGE_OFFSET = 0;
REG_GX_TEXIMAGE_PARAM = 0;
gx_mtxMode(GX_MTX_MODE_PROJECTION);
gx_mtxIdentity();
gx_mtxMode(GX_MTX_MODE_TEXTURE);
gx_mtxIdentity();
gx_mtxMode(GX_MTX_MODE_POSITION_VECTOR);
gx_mtxIdentity();
}
void gx_reset(void)
{
gx_waitGeometryEngineBusy();
gx_ackColorBufferUnderflow();
gx_ackPolyVtxRamOverflow();
gx_resetMatrixStack();
}
void gx_resetMatrixStack(void)
{
gx_ackMtxStackError();
gx_waitMtxStackBusy();
u32 projectionStackLevel = gx_getProjectionMtxStackLevel();
u32 positionVectorStackLevel = gx_getPositionVectorMtxStackLevel();
gx_mtxMode(GX_MTX_MODE_PROJECTION);
if (projectionStackLevel)
gx_mtxPop(projectionStackLevel);
gx_mtxMode(GX_MTX_MODE_POSITION_VECTOR);
if (positionVectorStackLevel)
gx_mtxPop(positionVectorStackLevel);
}
void gx_clearFifo(void)
{
for (u32 i = 0; i < 128; i++)
REG_GXFIFO = 0;
gx_waitGeometryEngineBusy();
}