Skip to content

Commit

Permalink
hb: Use NDMA to clear RAM and clear DSi registers
Browse files Browse the repository at this point in the history
  • Loading branch information
RocketRobz committed Feb 17, 2024
1 parent f6e093e commit ab5ea03
Show file tree
Hide file tree
Showing 3 changed files with 248 additions and 62 deletions.
51 changes: 0 additions & 51 deletions hb/bootloader/source/arm7/arm7clear.s

This file was deleted.

36 changes: 25 additions & 11 deletions hb/bootloader/source/arm7/main.arm7.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ Helpful information:
#define REG_GPIO_WIFI *(vu16*)0x4004C04

#include "tonccpy.h"
#include "dmaTwl.h"
//#include "my_sdmmc.h"
#include "my_fat.h"
#include "dldi_patcher.h"
Expand All @@ -64,8 +65,6 @@ Helpful information:
#include "locations.h"
#include "i2c.h"

void arm7clearRAM();

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Important things
extern unsigned long _start;
Expand Down Expand Up @@ -204,6 +203,12 @@ static void initMBK(void) {
REG_MBK8=0x07403700; // same as dsiware
}

void memset_addrs_arm7(u32 start, u32 end)
{
// toncset((u32*)start, 0, ((int)end - (int)start));
dma_twlFill32(0, 0, (u32*)start, ((int)end - (int)start));
}

/*-------------------------------------------------------------------------
resetMemory_ARM7
Clears all of the NDS's RAM that is visible to the ARM7
Expand All @@ -227,6 +232,13 @@ static void resetMemory_ARM7 (void)
}

REG_SOUNDCNT = 0;
REG_SNDCAP0CNT = 0;
REG_SNDCAP1CNT = 0;

REG_SNDCAP0DAD = 0;
REG_SNDCAP0LEN = 0;
REG_SNDCAP1DAD = 0;
REG_SNDCAP1LEN = 0;

//clear out ARM7 DMA channels and timers
for (i=0; i<4; i++) {
Expand All @@ -245,24 +257,26 @@ static void resetMemory_ARM7 (void)

sdEngineLocation = (*(u32*)0x02FFE1A0 == 0x080037C0) ? SDENGINE_LOCATION_ALT : SDENGINE_LOCATION;

arm7clearRAM(); // clear exclusive IWRAM
memset_addrs_arm7(0x03000000, 0x03800000 + 0x10000);
if (ndsPreloaded) {
toncset((u32*)0x02200000, 0, 0x180000); // clear most of EWRAM (except pre-loaded ARM9 binary)
dma_twlFill32(0, 0, (u32*)0x02200000, 0x180000); // clear most of EWRAM (except pre-loaded ARM9 binary)
} else {
toncset((u32*)0x02004000, 0, 0x37C000); // clear most of EWRAM
dma_twlFill32(0, 0, (u32*)0x02004000, 0x37C000); // clear most of EWRAM
}
toncset((u32*)0x02380000, 0, 0x70000);
toncset((u32*)0x023F1000, 0, 0xF000);
dma_twlFill32(0, 0, (u32*)0x02380000, 0x70000);
dma_twlFill32(0, 0, (u32*)0x023F1000, 0xF000);
if (romIsCompressed) {
toncset((u32*)0x02D00000, 0, 0x300000); // clear other part of EWRAM
dma_twlFill32(0, 0, (u32*)0x02D00000, 0x300000); // clear other part of EWRAM
} else {
toncset((u32*)0x02400000, 0, 0xC00000); // clear other part of EWRAM
dma_twlFill32(0, 0, (u32*)0x02400000, 0xC00000); // clear other part of EWRAM
}

REG_IE = 0;
REG_IF = ~0;
(*(vu32*)(0x04000000-4)) = 0; //IRQ_HANDLER ARM7 version
(*(vu32*)(0x04000000-8)) = ~0; //VBLANK_INTR_WAIT_FLAGS, ARM7 version
REG_AUXIE = 0;
REG_AUXIF = ~0;
*(vu32*)0x0380FFFC = 0; // IRQ_HANDLER ARM7 version
*(vu32*)0x0380FFF8 = 0; // VBLANK_INTR_WAIT_FLAGS, ARM7 version
REG_POWERCNT = 1; //turn off power to stuff

// Get settings location
Expand Down
223 changes: 223 additions & 0 deletions hb/common/include/dmaTwl.h
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit ab5ea03

Please sign in to comment.