New DMA channels of DSi

mrparrot2

Well-Known Member
OP
Member
Joined
Nov 29, 2021
Messages
106
Trophies
0
Age
29
Location
SP, Brazil
XP
568
Country
Brazil
Hello.

I would like to get to know how can I use the additional DSi DMA channels that are described in GBATEK with libnds. Did someone already implement code for those?

I am implementing a BitBlt algorithm using the DMA channels in the case that src or dst are in VRAM, and having 4 more channels has the potential to improve speed by a factor of 4 on DSi.
 

Pk11

A catgirl with a DSi
Member
Joined
Jun 26, 2019
Messages
1,285
Trophies
1
Age
22
Location
米国
Website
xn--rck9c.xn--tckwe
XP
3,904
Country
United States
I don't think libnds has functions for NDMA, but the registers are simple enough, could just make a function along the lines of:
C:
void ndmaCopy(int channel, void *dst, const void *src, int len) {
	REG_NDMASAD(channel)  = (u32)src;   // source RAM/VRAM
	REG_NDMADAD(channel)  = (u32)dst;   // destination RAM/VRAM
	REG_NDMATCNT(channel) = len / 4;    // total length in words
	REG_NDMAWCNT(channel) = 512;        // block length in words
	REG_NDMABCNT(channel) = 0;          // timing interval or so
	REG_NDMACNT(channel)  = 0x8B044000; // start DMA
}

Note: This is based on dsi-camera, linked below, I haven't used NDMA much so not sure exactly what the best values for everything are. iirc the total length needs to be divisible by the block length or something like that, so 512 probably isn't an all purpose number. The 'start DMA' command may also need some variablility, there are decent details on GBATEK. dsi-camera is hardcoded to REG_NDAM1###, but it would be simple enough to make a define where you can specify which one as I used above. I'm not exactly sure what the timing interval does, seems to be some kinda delay dsi-camera had 2 but 0 sounds valid?

Register defines: camera.h:12-20
Relevant code: camera.c:87-92
Relevant GBATEK: DSi New DMA (NDMA)
 

mrparrot2

Well-Known Member
OP
Member
Joined
Nov 29, 2021
Messages
106
Trophies
0
Age
29
Location
SP, Brazil
XP
568
Country
Brazil
Well, I managed to get it to work only to conclude that it is by no means faster than only using the default DS DMA channels.

Here is the code I managed to get to work, if anyone in the future are interested in it:

// DSi exclusive new DMA channels; #define REG_NDMAGCNT *(vu32 *)(0x04004100) #define REG_NDMASAD(n) *(vu32 *)(0x04004104 + ((n)*0x1c)) #define REG_NDMADAD(n) *(vu32 *)(0x04004108 + ((n)*0x1c)) #define REG_NDMATCNT(n) *(vu32 *)(0x0400410c + ((n)*0x1c)) #define REG_NDMAWCNT(n) *(vu32 *)(0x04004110 + ((n)*0x1c)) #define REG_NDMABCNT(n) *(vu32 *)(0x04004114 + ((n)*0x1c)) #define REG_NDMAFDATA(n) *(vu32 *)(0x04004118 + ((n)*0x1c)) #define REG_NDMACNT(n) *(vu32 *)(0x0400411c + ((n)*0x1c)) #define NDMA_DSTADDR_UPDATE(x) (((x) & 0x3) << 10) #define NDMA_DSTADDR_RELOAD(x) (((x) & 0x1) << 12) #define NDMA_SRCADDR_UPDATE(x) (((x) & 0x3) << 13) #define NDMA_SRCADDR_RELOAD(x) (((x) & 0x1) << 15) #define NDMA_PHYSICAL_BLK_SIZE(x) (((x) & 0x7) << 16) #define NDMA_STARTUP_MODE(x) (((x) & 0x1F) << 24) #define NDMA_REPEAT_MODE(x) (((x) & 0x1) << 29) #define NDMA_INTERRUPT_ENABLE(x) (((x) & 0x1) << 30) #define NDMA_ENABLE(x) (((x) & 0x1) << 31) static void ndmaCopyWordsAsynch(int channel, const void *src, void *dst, int len) { u32 opts = NDMA_DSTADDR_UPDATE(0) | NDMA_DSTADDR_RELOAD(0) | NDMA_SRCADDR_UPDATE(0) | NDMA_SRCADDR_RELOAD(0) | NDMA_PHYSICAL_BLK_SIZE(/*4*/ 2) | NDMA_STARTUP_MODE(0x10) | NDMA_INTERRUPT_ENABLE(0) | NDMA_ENABLE(1); REG_NDMAGCNT = 1 << 31; REG_NDMASAD(channel) = (u32)src; // source RAM/VRAM REG_NDMADAD(channel) = (u32)dst; // destination RAM/VRAM REG_NDMATCNT(channel) = len / 4; // total length in words REG_NDMAWCNT(channel) = len / 4; // block length in words REG_NDMABCNT(channel) = 0; // timing interval or so REG_NDMACNT(channel) = opts; //0x8B044000; // start DMA }
 

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    Veho @ Veho: Yeet the cat.