blocksds / sdk

Main BlocksDS SDK repository
https://blocksds.github.io/docs/
157 stars 8 forks source link

Replace the DLDI of the R4 by a FOSS version of it #59

Closed AntonioND closed 11 months ago

AntonioND commented 1 year ago

This DLDI driver is used by DeSmuMe, so it would be nice to replace the prebuilt version of it by the source code. However, there is no FOSS version of that code, so it needs to be created from scratch.

lifehackerhansol commented 1 year ago

The driver is OSS. It's not FOSS. (big difference). The driver is so ridiculously simple I don't even know if it's possible to recreate driver from scratch without basically writing the same thing twice...

Here's a really poor writeup on what exactly the OG R4 is doing:


There is no particular init code. It is all handled by the R4 firmware. But there is a way to validate whether it is an actual OG R4:

REG_CARD_COMMAND[0] = 0xb0;
If REG_CARD_DATA_RD & 0x7 == 0x4, this is an OG R4

You can opt to just not implement snippet and return true on both startup() and isInserted().


readSectors(u32 sector, u32 numSectors, void* buffer) Read and writes only work in 0x200 bytes. Sector addresses must be << 9

Read:

// read 0x200 bytes
// 0xb9: send read target address to cartridge
REG_CARD_COMMAND[0] = 0xb9;
// essentially write the sector address into u8 chunks
REG_CARD_COMMAND[1] = sector >> 24 & 0xff
REG_CARD_COMMAND[2] = sector >> 16 & 0xff;
REG_CARD_COMMAND[3] = sector >> 8  & 0xff;
REG_CARD_COMMAND[4] = sector & 0xff;
5-7 = 0
REG_ROMCTRL = 0xa7586000;
loop command until REG_CARD_DATA_RD == 0

// 0xba: start read
REG_CARD_COMMAND[0] = 0xba;
REG_ROMCTRL = 0xa1586000;
From here you can do a normal cardPolledTransfer.

For every 0x200 bytes needed to read, loop the entire above code.

writeSectors(u32 sector, u32 numSectors, void* buffer) Same restrictions as readSectors(). Write:

// write 0x200 bytes
// 0xbb: send write target address to cartridge and start writing
REG_CARD_COMMAND[0] = 0xbb;
// essentially write the sector address into u8 chunks
REG_CARD_COMMAND[1] = sector >> 24 & 0xff
REG_CARD_COMMAND[2] = sector >> 16 & 0xff;
REG_CARD_COMMAND[3] = sector >> 8  & 0xff;
REG_CARD_COMMAND[4] = sector & 0xff;
5-7 = 0
REG_ROMCTRL = 0xe1586000;
// from here, we need a reverse of cardPolledTransfer that will write u32 chunks to REG_CARD_DATA_RD
// cartridge will return CARD_DATA_READY after processing the u32, afterwards write next u32 chunk
// loop until 0x200 bytes (128 u32s) are written

// 0xbc: end write
REG_CARD_COMMAND[0] = 0xbc;
REG_ROMCTRL = 0xa7586000;
Loop command until REG_CARD_DATA_RD == 0

For every 0x200 bytes needed to write, loop the above.

clearStatus() and shutdown() are unimplemented. No caching of any sort either, so it's just RW to card and be done with it.

Extra REG_CARD_COMMAND[0]s include:

Those need some more documentation on how it's intertwined, I don't know too much about how they work other than that it does.

Let me know if there's anything else needed.

AntonioND commented 1 year ago

Thanks a lot for the documentation! It should be possible to implement an actual FOSS version of the driver now, and I know that @asiekierka had been looking into getting someone to document all DLDI drivers' behaviours. This is a good start.

lifehackerhansol commented 1 year ago

I'm quite poor at documentation, but I do work on reverse-engineering DLDI behaviour. You can see https://github.com/DS-Homebrew/DLDI.

I've recently been rewriting a handful of the drivers to sort of align with the r4tfv2 DLDI. If someone can write an r4tfv3 of sorts, I could try to port it all over to this new one when it happens.

asiekierka commented 1 year ago

I think documentation should come before rewrites, as this will also allow writing independent, more "clean-room" implementations. I'm also somewhat interested in writing emulation support for carts one day...

lifehackerhansol commented 1 year ago

I could try to write some more in the meantime. (and clean up that awful doc above lol)

I just saw this issue and went "omg it's an issue I have something to actually offer!" and wrote on a whim.

asiekierka commented 1 year ago

Might want to start a wiki on the DLDI repository. Just remember to only cover what's necessary to implement a driver, no code citations or anything like that; Asahi Linux's Copyright & Reverse Engineering Policy is a good compromise between "legally perfect" and "feasible in a small FOSS project", and I recommend using it as a guidestone.

AntonioND commented 1 year ago

Wiki page with information by @lifehackerhansol and Gericom: https://github.com/DS-Homebrew/DLDI/wiki/Original-R4-and-M3-Simply

asiekierka commented 1 year ago

Sector addresses must be << 9 (this seems to be a characteristic of non-SDHC drivers).

Yes; SD cards operate at byte-level, SDHC and above cards operate at sector-level. This is to be expected.

lifehackerhansol commented 1 year ago

Sector addresses must be << 9 (this seems to be a characteristic of non-SDHC drivers).

Yes; SD cards operate at byte-level, SDHC and above cards operate at sector-level. This is to be expected.

I didn't make this connection until just now when Gericom explained it, then forgot to remove the now-very-obvious note from my original writeup lol

asiekierka commented 11 months ago

https://github.com/asiekierka/dldi-r4

AntonioND commented 11 months ago

This commit https://github.com/blocksds/sdk/commit/91aaf530d79a5073c2bc1cfe3e6cdb61693c68a0 replaces the previous R4 DLDI blob by asie's repository. Thanks!