From 29fb71cab865b76a2a0700e6e8382c100491c456 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 13 Jun 2019 13:11:33 +0200 Subject: BAHAHAHAHHHH mostly just going to derp around some, so don't hold your breath here --- src/NDS.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/NDS.h') diff --git a/src/NDS.h b/src/NDS.h index 3243337..9b7a10a 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -120,7 +120,8 @@ extern u8 ROMSeed1[2*8]; extern u8 ARM9BIOS[0x1000]; extern u8 ARM7BIOS[0x4000]; -#define MAIN_RAM_SIZE 0x400000 +//#define MAIN_RAM_SIZE 0x400000 +#define MAIN_RAM_SIZE 0x1000000 extern u8 MainRAM[MAIN_RAM_SIZE]; -- cgit v1.2.3 From 0e421ccebd3ebabfbbabcae96acc262b76198ad2 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Thu, 13 Jun 2019 14:41:54 +0200 Subject: add all sorts of shit --- melonDS.cbp | 9 + src/DSi.cpp | 16 ++ src/DSi.h | 14 ++ src/DSiCrypto.h | 7 + src/NDS.cpp | 36 +-- src/NDS.h | 4 +- src/sha1/sha1.c | 276 +++++++++++++++++++++ src/sha1/sha1.h | 17 ++ src/tiny-AES-c/README.md | 80 ++++++ src/tiny-AES-c/aes.c | 572 +++++++++++++++++++++++++++++++++++++++++++ src/tiny-AES-c/aes.h | 90 +++++++ src/tiny-AES-c/aes.hpp | 12 + src/tiny-AES-c/unlicense.txt | 24 ++ 13 files changed, 1141 insertions(+), 16 deletions(-) create mode 100644 src/sha1/sha1.c create mode 100644 src/sha1/sha1.h create mode 100644 src/tiny-AES-c/README.md create mode 100644 src/tiny-AES-c/aes.c create mode 100644 src/tiny-AES-c/aes.h create mode 100644 src/tiny-AES-c/aes.hpp create mode 100644 src/tiny-AES-c/unlicense.txt (limited to 'src/NDS.h') diff --git a/melonDS.cbp b/melonDS.cbp index 59df311..97958f5 100644 --- a/melonDS.cbp +++ b/melonDS.cbp @@ -254,6 +254,15 @@ + + + + + + + diff --git a/src/DSi.cpp b/src/DSi.cpp index 6a524dd..376e6a0 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -15,3 +15,19 @@ You should have received a copy of the GNU General Public License along with melonDS. If not, see http://www.gnu.org/licenses/. */ + +#include "DSi.h" +#include "tiny-AES-c/aes.hpp" +#include "sha1/sha1.h" + +namespace DSi +{ + +bool LoadNAND() +{ + // + + return true; +} + +} diff --git a/src/DSi.h b/src/DSi.h index 6a524dd..2c71ad9 100644 --- a/src/DSi.h +++ b/src/DSi.h @@ -15,3 +15,17 @@ You should have received a copy of the GNU General Public License along with melonDS. If not, see http://www.gnu.org/licenses/. */ + +#ifndef DSI_H +#define DSI_H + +#include "types.h" + +namespace DSi +{ + +bool LoadNAND(); + +} + +#endif // DSI_H diff --git a/src/DSiCrypto.h b/src/DSiCrypto.h index 6a524dd..dc9bfe6 100644 --- a/src/DSiCrypto.h +++ b/src/DSiCrypto.h @@ -15,3 +15,10 @@ You should have received a copy of the GNU General Public License along with melonDS. If not, see http://www.gnu.org/licenses/. */ + +#ifndef DSICRYPTO_H +#define DSICRYPTO_H + +// + +#endif // DSICRYPTO_H diff --git a/src/NDS.cpp b/src/NDS.cpp index ea34103..f00665e 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -31,6 +31,8 @@ #include "Wifi.h" #include "Platform.h" +#include "DSi.h" + namespace NDS { @@ -83,8 +85,8 @@ u32 SchedListMask; u32 CPUStop; -u8 ARM9BIOS[0x1000]; -u8 ARM7BIOS[0x4000]; +u8 ARM9BIOS[0x10000]; +u8 ARM7BIOS[0x10000]; u8 MainRAM[MAIN_RAM_SIZE]; @@ -387,6 +389,9 @@ void Reset() LastSysClockCycles = 0; + memset(ARM9BIOS, 0, 0x10000); + memset(ARM7BIOS, 0, 0x10000); + f = Platform::OpenLocalFile("bios9.bin", "rb"); if (!f) { @@ -421,6 +426,8 @@ void Reset() fclose(f); } + DSi::LoadNAND(); + // TODO for later: configure this when emulating a DSi ARM9ClockShift = 1; @@ -1566,9 +1573,9 @@ void debug(u32 param) u8 ARM9Read8(u32 addr) { - if ((addr & 0xFFFFF000) == 0xFFFF0000) + if ((addr & 0xFFFF0000) == 0xFFFF0000) { - return *(u8*)&ARM9BIOS[addr & 0xFFF]; + return *(u8*)&ARM9BIOS[addr & 0xFFFF]; } switch (addr & 0xFF000000) @@ -1627,9 +1634,9 @@ u8 ARM9Read8(u32 addr) u16 ARM9Read16(u32 addr) { - if ((addr & 0xFFFFF000) == 0xFFFF0000) + if ((addr & 0xFFFF0000) == 0xFFFF0000) { - return *(u16*)&ARM9BIOS[addr & 0xFFF]; + return *(u16*)&ARM9BIOS[addr & 0xFFFF]; } switch (addr & 0xFF000000) @@ -1688,9 +1695,9 @@ u16 ARM9Read16(u32 addr) u32 ARM9Read32(u32 addr) { - if ((addr & 0xFFFFF000) == 0xFFFF0000) + if ((addr & 0xFFFF0000) == 0xFFFF0000) { - return *(u32*)&ARM9BIOS[addr & 0xFFF]; + return *(u32*)&ARM9BIOS[addr & 0xFFFF]; } switch (addr & 0xFF000000) @@ -1896,9 +1903,10 @@ bool ARM9GetMemRegion(u32 addr, bool write, MemRegion* region) u8 ARM7Read8(u32 addr) { - if (addr < 0x00004000) + if (addr < 0x00010000) { - if (ARM7->R[15] >= 0x4000) + // TODO: check the boundary? is it 4000 or higher on regular DS? + if (ARM7->R[15] >= 0x00010000) return 0xFF; if (addr < ARM7BIOSProt && ARM7->R[15] >= ARM7BIOSProt) return 0xFF; @@ -1952,9 +1960,9 @@ u8 ARM7Read8(u32 addr) u16 ARM7Read16(u32 addr) { - if (addr < 0x00004000) + if (addr < 0x00010000) { - if (ARM7->R[15] >= 0x4000) + if (ARM7->R[15] >= 0x00010000) return 0xFFFF; if (addr < ARM7BIOSProt && ARM7->R[15] >= ARM7BIOSProt) return 0xFFFF; @@ -2015,9 +2023,9 @@ u16 ARM7Read16(u32 addr) u32 ARM7Read32(u32 addr) { - if (addr < 0x00004000) + if (addr < 0x00010000) { - if (ARM7->R[15] >= 0x4000) + if (ARM7->R[15] >= 0x00010000) return 0xFFFFFFFF; if (addr < ARM7BIOSProt && ARM7->R[15] >= ARM7BIOSProt) return 0xFFFFFFFF; diff --git a/src/NDS.h b/src/NDS.h index 9b7a10a..e8bb44d 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -117,8 +117,8 @@ extern u16 ExMemCnt[2]; extern u8 ROMSeed0[2*8]; extern u8 ROMSeed1[2*8]; -extern u8 ARM9BIOS[0x1000]; -extern u8 ARM7BIOS[0x4000]; +extern u8 ARM9BIOS[0x10000]; +extern u8 ARM7BIOS[0x10000]; //#define MAIN_RAM_SIZE 0x400000 #define MAIN_RAM_SIZE 0x1000000 diff --git a/src/sha1/sha1.c b/src/sha1/sha1.c new file mode 100644 index 0000000..2c50433 --- /dev/null +++ b/src/sha1/sha1.c @@ -0,0 +1,276 @@ + +/* from valgrind tests */ + +/* ================ sha1.c ================ */ +/* +SHA-1 in C +By Steve Reid +100% Public Domain + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#define SHA1HANDSOFF + +#include +#include +#include /* for u_int*_t */ +#if defined(__sun) +#include "solarisfixes.h" +#endif +#include "sha1.h" + +#ifndef BYTE_ORDER +#if (BSD >= 199103) +# include +#else +#if defined(linux) || defined(__linux__) +# include +#else +#define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */ +#define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ +#define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp)*/ + +#if defined(vax) || defined(ns32000) || defined(sun386) || defined(__i386__) || \ + defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ + defined(__alpha__) || defined(__alpha) +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ + defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ + defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ + defined(apollo) || defined(__convex__) || defined(_CRAY) || \ + defined(__hppa) || defined(__hp9000) || \ + defined(__hp9000s300) || defined(__hp9000s700) || \ + defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc) +#define BYTE_ORDER BIG_ENDIAN +#endif +#endif /* linux */ +#endif /* BSD */ +#endif /* BYTE_ORDER */ + +#if defined(__BYTE_ORDER) && !defined(BYTE_ORDER) +#if (__BYTE_ORDER == __LITTLE_ENDIAN) +#define BYTE_ORDER LITTLE_ENDIAN +#else +#define BYTE_ORDER BIG_ENDIAN +#endif +#endif + +#if !defined(BYTE_ORDER) || \ + (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN && \ + BYTE_ORDER != PDP_ENDIAN) + /* you must determine what the correct bit order is for + * your compiler - the next line is an intentional error + * which will force your compiles to bomb until you fix + * the above macros. + */ +#error "Undefined or invalid BYTE_ORDER" +#endif + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#elif BYTE_ORDER == BIG_ENDIAN +#define blk0(i) block->l[i] +#else +#error "Endianness not defined!" +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]) +{ +u_int32_t a, b, c, d, e; +typedef union { + unsigned char c[64]; + u_int32_t l[16]; +} CHAR64LONG16; +#ifdef SHA1HANDSOFF +CHAR64LONG16 block[1]; /* use array to appear as a pointer */ + memcpy(block, buffer, 64); +#else + /* The following had better never be used because it causes the + * pointer-to-const buffer to be cast into a pointer to non-const. + * And the result is written through. I threw a "const" in, hoping + * this will cause a diagnostic. + */ +CHAR64LONG16* block = (const CHAR64LONG16*)buffer; +#endif + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +#ifdef SHA1HANDSOFF + memset(block, '\0', sizeof(block)); +#endif +} + + +/* SHA1Init - Initialize new context */ + +void SHA1Init(SHA1_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len) +{ +u_int32_t i; +u_int32_t j; + + j = context->count[0]; + if ((context->count[0] += len << 3) < j) + context->count[1]++; + context->count[1] += (len>>29); + j = (j >> 3) & 63; + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +void SHA1Final(unsigned char digest[20], SHA1_CTX* context) +{ +unsigned i; +unsigned char finalcount[8]; +unsigned char c; + +#if 0 /* untested "improvement" by DHR */ + /* Convert context->count to a sequence of bytes + * in finalcount. Second element first, but + * big-endian order within element. + * But we do it all backwards. + */ + unsigned char *fcp = &finalcount[8]; + + for (i = 0; i < 2; i++) + { + u_int32_t t = context->count[i]; + int j; + + for (j = 0; j < 4; t >>= 8, j++) + *--fcp = (unsigned char) t + } +#else + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } +#endif + c = 0200; + SHA1Update(context, &c, 1); + while ((context->count[0] & 504) != 448) { + c = 0000; + SHA1Update(context, &c, 1); + } + SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + memset(context, '\0', sizeof(*context)); + memset(&finalcount, '\0', sizeof(finalcount)); +} +/* ================ end of sha1.c ================ */ + +#if 0 +#define BUFSIZE 4096 + +int +main(int argc, char **argv) +{ + SHA1_CTX ctx; + unsigned char hash[20], buf[BUFSIZE]; + int i; + + for(i=0;i +100% Public Domain +*/ + +typedef struct { + u_int32_t state[5]; + u_int32_t count[2]; + unsigned char buffer[64]; +} SHA1_CTX; + +void SHA1Transform(u_int32_t state[5], const unsigned char buffer[64]); +void SHA1Init(SHA1_CTX* context); +void SHA1Update(SHA1_CTX* context, const unsigned char* data, u_int32_t len); +void SHA1Final(unsigned char digest[20], SHA1_CTX* context); diff --git a/src/tiny-AES-c/README.md b/src/tiny-AES-c/README.md new file mode 100644 index 0000000..e32e25e --- /dev/null +++ b/src/tiny-AES-c/README.md @@ -0,0 +1,80 @@ +### Tiny AES in C + +This is a small and portable implementation of the AES [ECB](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_.28ECB.29), [CTR](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Counter_.28CTR.29) and [CBC](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher_Block_Chaining_.28CBC.29) encryption algorithms written in C. + +You can override the default key-size of 128 bit with 192 or 256 bit by defining the symbols AES192 or AES256 in `aes.h`. + +The API is very simple and looks like this (I am using C99 ``-style annotated types): + +```C +/* Initialize context calling one of: */ +void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key); +void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); + +/* ... or reset IV at random point: */ +void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv); + +/* Then start encrypting and decrypting with the functions below: */ +void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf); +void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf); + +void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); +void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); + +/* Same function for encrypting as for decrypting in CTR mode */ +void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); +``` + +Note: + * No padding is provided so for CBC and ECB all buffers should be multiples of 16 bytes. For padding [PKCS7](https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7) is recommendable. + * ECB mode is considered unsafe for most uses and is not implemented in streaming mode. If you need this mode, call the function for every block of 16 bytes you need encrypted. See [wikipedia's article on ECB](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_Codebook_(ECB)) for more details. + +You can choose to use any or all of the modes-of-operations, by defining the symbols CBC, CTR or ECB. See the header file for clarification. + +C++ users should `#include` [aes.hpp](https://github.com/kokke/tiny-AES-c/blob/master/aes.hpp) instead of [aes.h](https://github.com/kokke/tiny-AES-c/blob/master/aes.h) + +There is no built-in error checking or protection from out-of-bounds memory access errors as a result of malicious input. + +The module uses less than 200 bytes of RAM and 1-2K ROM when compiled for ARM, but YMMV depending on which modes are enabled. + +It is one of the smallest implementations in C I've seen yet, but do contact me if you know of something smaller (or have improvements to the code here). + +I've successfully used the code on 64bit x86, 32bit ARM and 8 bit AVR platforms. + + +GCC size output when only CTR mode is compiled for ARM: + + $ arm-none-eabi-gcc -Os -DCBC=0 -DECB=0 -DCTR=1 -c aes.c + $ size aes.o + text data bss dec hex filename + 1343 0 0 1343 53f aes.o + +.. and when compiling for the THUMB instruction set, we end up just below 1K in code size. + + $ arm-none-eabi-gcc -Os -mthumb -DCBC=0 -DECB=0 -DCTR=1 -c aes.c + $ size aes.o + text data bss dec hex filename + 979 0 0 979 3d3 aes.o + + +I am using the Free Software Foundation, ARM GCC compiler: + + $ arm-none-eabi-gcc --version + arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 8-2018-q4-major) 8.2.1 20181213 (release) + Copyright (C) 2018 Free Software Foundation, Inc. + This is free software; see the source for copying conditions. There is NO + warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + + +This implementation is verified against the data in: + +[National Institute of Standards and Technology Special Publication 800-38A 2001 ED](http://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf) Appendix F: Example Vectors for Modes of Operation of the AES. + +The other appendices in the document are valuable for implementation details on e.g. padding, generation of IVs and nonces in CTR-mode etc. + + +A heartfelt thank-you to all the nice people out there who have contributed to this project. + + +All material in this repository is in the public domain. diff --git a/src/tiny-AES-c/aes.c b/src/tiny-AES-c/aes.c new file mode 100644 index 0000000..313ff71 --- /dev/null +++ b/src/tiny-AES-c/aes.c @@ -0,0 +1,572 @@ +/* + +This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode. +Block size can be chosen in aes.h - available choices are AES128, AES192, AES256. + +The implementation is verified against the test vectors in: + National Institute of Standards and Technology Special Publication 800-38A 2001 ED + +ECB-AES128 +---------- + + plain-text: + 6bc1bee22e409f96e93d7e117393172a + ae2d8a571e03ac9c9eb76fac45af8e51 + 30c81c46a35ce411e5fbc1191a0a52ef + f69f2445df4f9b17ad2b417be66c3710 + + key: + 2b7e151628aed2a6abf7158809cf4f3c + + resulting cipher + 3ad77bb40d7a3660a89ecaf32466ef97 + f5d3d58503b9699de785895a96fdbaaf + 43b1cd7f598ece23881b00e3ed030688 + 7b0c785e27e8ad3f8223207104725dd4 + + +NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) + You should pad the end of the string with zeros if this is not the case. + For AES192/256 the key size is proportionally larger. + +*/ + + +/*****************************************************************************/ +/* Includes: */ +/*****************************************************************************/ +#include +#include // CBC mode, for memset +#include "aes.h" + +/*****************************************************************************/ +/* Defines: */ +/*****************************************************************************/ +// The number of columns comprising a state in AES. This is a constant in AES. Value=4 +#define Nb 4 + +#if defined(AES256) && (AES256 == 1) + #define Nk 8 + #define Nr 14 +#elif defined(AES192) && (AES192 == 1) + #define Nk 6 + #define Nr 12 +#else + #define Nk 4 // The number of 32 bit words in a key. + #define Nr 10 // The number of rounds in AES Cipher. +#endif + +// jcallan@github points out that declaring Multiply as a function +// reduces code size considerably with the Keil ARM compiler. +// See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3 +#ifndef MULTIPLY_AS_A_FUNCTION + #define MULTIPLY_AS_A_FUNCTION 0 +#endif + + + + +/*****************************************************************************/ +/* Private variables: */ +/*****************************************************************************/ +// state - array holding the intermediate results during decryption. +typedef uint8_t state_t[4][4]; + + + +// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM +// The numbers below can be computed dynamically trading ROM for RAM - +// This can be useful in (embedded) bootloader applications, where ROM is often limited. +static const uint8_t sbox[256] = { + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; + +static const uint8_t rsbox[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; + +// The round constant word array, Rcon[i], contains the values given by +// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) +static const uint8_t Rcon[11] = { + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + +/* + * Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12), + * that you can remove most of the elements in the Rcon array, because they are unused. + * + * From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon + * + * "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed), + * up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm." + */ + + +/*****************************************************************************/ +/* Private functions: */ +/*****************************************************************************/ +/* +static uint8_t getSBoxValue(uint8_t num) +{ + return sbox[num]; +} +*/ +#define getSBoxValue(num) (sbox[(num)]) +/* +static uint8_t getSBoxInvert(uint8_t num) +{ + return rsbox[num]; +} +*/ +#define getSBoxInvert(num) (rsbox[(num)]) + +// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. +static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) +{ + unsigned i, j, k; + uint8_t tempa[4]; // Used for the column/row operations + + // The first round key is the key itself. + for (i = 0; i < Nk; ++i) + { + RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; + RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; + RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; + RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; + } + + // All other round keys are found from the previous round keys. + for (i = Nk; i < Nb * (Nr + 1); ++i) + { + { + k = (i - 1) * 4; + tempa[0]=RoundKey[k + 0]; + tempa[1]=RoundKey[k + 1]; + tempa[2]=RoundKey[k + 2]; + tempa[3]=RoundKey[k + 3]; + + } + + if (i % Nk == 0) + { + // This function shifts the 4 bytes in a word to the left once. + // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] + + // Function RotWord() + { + const uint8_t u8tmp = tempa[0]; + tempa[0] = tempa[1]; + tempa[1] = tempa[2]; + tempa[2] = tempa[3]; + tempa[3] = u8tmp; + } + + // SubWord() is a function that takes a four-byte input word and + // applies the S-box to each of the four bytes to produce an output word. + + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + + tempa[0] = tempa[0] ^ Rcon[i/Nk]; + } +#if defined(AES256) && (AES256 == 1) + if (i % Nk == 4) + { + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + } +#endif + j = i * 4; k=(i - Nk) * 4; + RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0]; + RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1]; + RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2]; + RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3]; + } +} + +void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key) +{ + KeyExpansion(ctx->RoundKey, key); +} +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) +void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) +{ + KeyExpansion(ctx->RoundKey, key); + memcpy (ctx->Iv, iv, AES_BLOCKLEN); +} +void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv) +{ + memcpy (ctx->Iv, iv, AES_BLOCKLEN); +} +#endif + +// This function adds the round key to state. +// The round key is added to the state by an XOR function. +static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey) +{ + uint8_t i,j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j]; + } + } +} + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void SubBytes(state_t* state) +{ + uint8_t i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxValue((*state)[j][i]); + } + } +} + +// The ShiftRows() function shifts the rows in the state to the left. +// Each row is shifted with different offset. +// Offset = Row number. So the first row is not shifted. +static void ShiftRows(state_t* state) +{ + uint8_t temp; + + // Rotate first row 1 columns to left + temp = (*state)[0][1]; + (*state)[0][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[3][1]; + (*state)[3][1] = temp; + + // Rotate second row 2 columns to left + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to left + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[3][3]; + (*state)[3][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[1][3]; + (*state)[1][3] = temp; +} + +static uint8_t xtime(uint8_t x) +{ + return ((x<<1) ^ (((x>>7) & 1) * 0x1b)); +} + +// MixColumns function mixes the columns of the state matrix +static void MixColumns(state_t* state) +{ + uint8_t i; + uint8_t Tmp, Tm, t; + for (i = 0; i < 4; ++i) + { + t = (*state)[i][0]; + Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ; + Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ; + Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ; + Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ; + Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ; + } +} + +// Multiply is used to multiply numbers in the field GF(2^8) +// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary +// The compiler seems to be able to vectorize the operation better this way. +// See https://github.com/kokke/tiny-AES-c/pull/34 +#if MULTIPLY_AS_A_FUNCTION +static uint8_t Multiply(uint8_t x, uint8_t y) +{ + return (((y & 1) * x) ^ + ((y>>1 & 1) * xtime(x)) ^ + ((y>>2 & 1) * xtime(xtime(x))) ^ + ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ + ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */ + } +#else +#define Multiply(x, y) \ + ( ((y & 1) * x) ^ \ + ((y>>1 & 1) * xtime(x)) ^ \ + ((y>>2 & 1) * xtime(xtime(x))) ^ \ + ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ + ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ + +#endif + +#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) +// MixColumns function mixes the columns of the state matrix. +// The method used to multiply may be difficult to understand for the inexperienced. +// Please use the references to gain more information. +static void InvMixColumns(state_t* state) +{ + int i; + uint8_t a, b, c, d; + for (i = 0; i < 4; ++i) + { + a = (*state)[i][0]; + b = (*state)[i][1]; + c = (*state)[i][2]; + d = (*state)[i][3]; + + (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); + (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); + (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); + (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); + } +} + + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void InvSubBytes(state_t* state) +{ + uint8_t i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxInvert((*state)[j][i]); + } + } +} + +static void InvShiftRows(state_t* state) +{ + uint8_t temp; + + // Rotate first row 1 columns to right + temp = (*state)[3][1]; + (*state)[3][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[0][1]; + (*state)[0][1] = temp; + + // Rotate second row 2 columns to right + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to right + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[1][3]; + (*state)[1][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[3][3]; + (*state)[3][3] = temp; +} +#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) + +// Cipher is the main function that encrypts the PlainText. +static void Cipher(state_t* state, const uint8_t* RoundKey) +{ + uint8_t round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(0, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr-1 rounds are executed in the loop below. + for (round = 1; round < Nr; ++round) + { + SubBytes(state); + ShiftRows(state); + MixColumns(state); + AddRoundKey(round, state, RoundKey); + } + + // The last round is given below. + // The MixColumns function is not here in the last round. + SubBytes(state); + ShiftRows(state); + AddRoundKey(Nr, state, RoundKey); +} + +#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) +static void InvCipher(state_t* state, const uint8_t* RoundKey) +{ + uint8_t round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(Nr, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr-1 rounds are executed in the loop below. + for (round = (Nr - 1); round > 0; --round) + { + InvShiftRows(state); + InvSubBytes(state); + AddRoundKey(round, state, RoundKey); + InvMixColumns(state); + } + + // The last round is given below. + // The MixColumns function is not here in the last round. + InvShiftRows(state); + InvSubBytes(state); + AddRoundKey(0, state, RoundKey); +} +#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) + +/*****************************************************************************/ +/* Public functions: */ +/*****************************************************************************/ +#if defined(ECB) && (ECB == 1) + + +void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf) +{ + // The next function call encrypts the PlainText with the Key using AES algorithm. + Cipher((state_t*)buf, ctx->RoundKey); +} + +void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf) +{ + // The next function call decrypts the PlainText with the Key using AES algorithm. + InvCipher((state_t*)buf, ctx->RoundKey); +} + + +#endif // #if defined(ECB) && (ECB == 1) + + + + + +#if defined(CBC) && (CBC == 1) + + +static void XorWithIv(uint8_t* buf, const uint8_t* Iv) +{ + uint8_t i; + for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size + { + buf[i] ^= Iv[i]; + } +} + +void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, uint32_t length) +{ + uintptr_t i; + uint8_t *Iv = ctx->Iv; + for (i = 0; i < length; i += AES_BLOCKLEN) + { + XorWithIv(buf, Iv); + Cipher((state_t*)buf, ctx->RoundKey); + Iv = buf; + buf += AES_BLOCKLEN; + //printf("Step %d - %d", i/16, i); + } + /* store Iv in ctx for next call */ + memcpy(ctx->Iv, Iv, AES_BLOCKLEN); +} + +void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length) +{ + uintptr_t i; + uint8_t storeNextIv[AES_BLOCKLEN]; + for (i = 0; i < length; i += AES_BLOCKLEN) + { + memcpy(storeNextIv, buf, AES_BLOCKLEN); + InvCipher((state_t*)buf, ctx->RoundKey); + XorWithIv(buf, ctx->Iv); + memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN); + buf += AES_BLOCKLEN; + } + +} + +#endif // #if defined(CBC) && (CBC == 1) + + + +#if defined(CTR) && (CTR == 1) + +/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */ +void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length) +{ + uint8_t buffer[AES_BLOCKLEN]; + + unsigned i; + int bi; + for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) + { + if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */ + { + + memcpy(buffer, ctx->Iv, AES_BLOCKLEN); + Cipher((state_t*)buffer,ctx->RoundKey); + + /* Increment Iv and handle overflow */ + for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) + { + /* inc will overflow */ + if (ctx->Iv[bi] == 255) + { + ctx->Iv[bi] = 0; + continue; + } + ctx->Iv[bi] += 1; + break; + } + bi = 0; + } + + buf[i] = (buf[i] ^ buffer[bi]); + } +} + +#endif // #if defined(CTR) && (CTR == 1) + diff --git a/src/tiny-AES-c/aes.h b/src/tiny-AES-c/aes.h new file mode 100644 index 0000000..87f1471 --- /dev/null +++ b/src/tiny-AES-c/aes.h @@ -0,0 +1,90 @@ +#ifndef _AES_H_ +#define _AES_H_ + +#include + +// #define the macros below to 1/0 to enable/disable the mode of operation. +// +// CBC enables AES encryption in CBC-mode of operation. +// CTR enables encryption in counter-mode. +// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously. + +// The #ifndef-guard allows it to be configured before #include'ing or at compile time. +#ifndef CBC + #define CBC 1 +#endif + +#ifndef ECB + #define ECB 1 +#endif + +#ifndef CTR + #define CTR 1 +#endif + + +#define AES128 1 +//#define AES192 1 +//#define AES256 1 + +#define AES_BLOCKLEN 16 //Block length in bytes AES is 128b block only + +#if defined(AES256) && (AES256 == 1) + #define AES_KEYLEN 32 + #define AES_keyExpSize 240 +#elif defined(AES192) && (AES192 == 1) + #define AES_KEYLEN 24 + #define AES_keyExpSize 208 +#else + #define AES_KEYLEN 16 // Key length in bytes + #define AES_keyExpSize 176 +#endif + +struct AES_ctx +{ + uint8_t RoundKey[AES_keyExpSize]; +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) + uint8_t Iv[AES_BLOCKLEN]; +#endif +}; + +void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key); +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) +void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); +void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv); +#endif + +#if defined(ECB) && (ECB == 1) +// buffer size is exactly AES_BLOCKLEN bytes; +// you need only AES_init_ctx as IV is not used in ECB +// NB: ECB is considered insecure for most uses +void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf); +void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf); + +#endif // #if defined(ECB) && (ECB == !) + + +#if defined(CBC) && (CBC == 1) +// buffer size MUST be mutile of AES_BLOCKLEN; +// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme +// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv() +// no IV should ever be reused with the same key +void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); +void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); + +#endif // #if defined(CBC) && (CBC == 1) + + +#if defined(CTR) && (CTR == 1) + +// Same function for encrypting as for decrypting. +// IV is incremented for every block, and used after encryption as XOR-compliment for output +// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme +// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv() +// no IV should ever be reused with the same key +void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); + +#endif // #if defined(CTR) && (CTR == 1) + + +#endif //_AES_H_ diff --git a/src/tiny-AES-c/aes.hpp b/src/tiny-AES-c/aes.hpp new file mode 100644 index 0000000..ade1642 --- /dev/null +++ b/src/tiny-AES-c/aes.hpp @@ -0,0 +1,12 @@ +#ifndef _AES_HPP_ +#define _AES_HPP_ + +#ifndef __cplusplus +#error Do not include the hpp header in a c project! +#endif //__cplusplus + +extern "C" { +#include "aes.h" +} + +#endif //_AES_HPP_ diff --git a/src/tiny-AES-c/unlicense.txt b/src/tiny-AES-c/unlicense.txt new file mode 100644 index 0000000..68a49da --- /dev/null +++ b/src/tiny-AES-c/unlicense.txt @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to -- cgit v1.2.3 From 566a8df6cd5af057a77cf8bed091e1b7a18bfecd Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 16 Jun 2019 15:05:18 +0200 Subject: add IE2/IF2 --- src/DSi.cpp | 10 ++++++++++ src/NDS.cpp | 16 ++++++++++++++++ src/NDS.h | 41 ++++++++++++++++++++++++++++++++++++++--- 3 files changed, 64 insertions(+), 3 deletions(-) (limited to 'src/NDS.h') diff --git a/src/DSi.cpp b/src/DSi.cpp index ae1bed2..206c253 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -897,6 +897,9 @@ u16 ARM7IORead16(u32 addr) { switch (addr) { + case 0x04000218: return NDS::IE2; + case 0x0400021C: return NDS::IF2; + case 0x04004004: return 0x0187; case 0x04004006: return 0; // JTAG register } @@ -908,6 +911,9 @@ u32 ARM7IORead32(u32 addr) { switch (addr) { + case 0x04000218: return NDS::IE2; + case 0x0400021C: return NDS::IF2; + case 0x04004008: return 0x80000000; // HAX } @@ -929,6 +935,8 @@ void ARM7IOWrite16(u32 addr, u16 val) { switch (addr) { + case 0x04000218: NDS::IE2 = (val & 0x7FF7); NDS::UpdateIRQ(1); return; + case 0x0400021C: NDS::IF2 &= ~(val & 0x7FF7); NDS::UpdateIRQ(1); return; } return NDS::ARM7IOWrite16(addr, val); @@ -938,6 +946,8 @@ void ARM7IOWrite32(u32 addr, u32 val) { switch (addr) { + case 0x04000218: NDS::IE2 = (val & 0x7FF7); NDS::UpdateIRQ(1); return; + case 0x0400021C: NDS::IF2 &= ~(val & 0x7FF7); NDS::UpdateIRQ(1); return; } return NDS::ARM7IOWrite32(addr, val); diff --git a/src/NDS.cpp b/src/NDS.cpp index c285910..5ca55f3 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -107,6 +107,7 @@ u8 ROMSeed1[2*8]; // IO shit u32 IME[2]; u32 IE[2], IF[2]; +u32 IE2, IF2; u8 PostFlag9; u8 PostFlag7; @@ -462,6 +463,8 @@ void Reset() IME[1] = 0; IE[1] = 0; IF[1] = 0; + IE2 = 0; + IF2 = 0; PostFlag9 = 0x00; PostFlag7 = 0x00; @@ -1067,6 +1070,7 @@ void UpdateIRQ(u32 cpu) if (IME[cpu] & 0x1) { arm->IRQ = IE[cpu] & IF[cpu]; + if (cpu) arm->IRQ |= (IE2 & IF2); } else { @@ -1086,6 +1090,18 @@ void ClearIRQ(u32 cpu, u32 irq) UpdateIRQ(cpu); } +void SetIRQ2(u32 irq) +{ + IF2 |= (1 << irq); + UpdateIRQ(1); +} + +void ClearIRQ2(u32 irq) +{ + IF2 &= ~(1 << irq); + UpdateIRQ(1); +} + bool HaltInterrupted(u32 cpu) { if (cpu == 0) diff --git a/src/NDS.h b/src/NDS.h index e8bb44d..e6cd2ee 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -74,12 +74,42 @@ enum IRQ_IPCSync, IRQ_IPCSendDone, IRQ_IPCRecv, - IRQ_CartSendDone, - IRQ_CartIREQMC, + IRQ_CartSendDone, // TODO: less misleading name + IRQ_CartIREQMC, // IRQ triggered by game cart (example: Pokémon Typing Adventure, BT controller) IRQ_GXFIFO, IRQ_LidOpen, IRQ_SPI, - IRQ_Wifi + IRQ_Wifi, + + // DSi IRQs + IRQ_DSi_DSP = 24, + IRQ_DSi_Camera, + IRQ_DSi_Unk26, + IRQ_DSi_Unk27, + IRQ_DSi_NDMA0, + IRQ_DSi_NDMA1, + IRQ_DSi_NDMA2, + IRQ_DSi_NDMA3, +}; + +enum +{ + // DSi ARM7-side IE2/IF2 + IRQ2_DSi_GPIO18_0 = 0, + IRQ2_DSi_GPIO18_1, + IRQ2_DSi_GPIO18_2, + IRQ2_DSi_Unused35, + IRQ2_DSi_GPIO33_0, + IRQ2_DSi_Headphone, + IRQ2_DSi_PowerButton, + IRQ2_DSi_GPIO33_3, // "sound enable input" + IRQ2_DSi_SDMMC, + IRQ2_DSi_SD_Data1, + IRQ2_DSi_SDIO, + IRQ2_DSi_SDIO_Data1, + IRQ2_DSi_AES, + IRQ2_DSi_I2C, + IRQ2_DSi_MicExt }; typedef struct @@ -109,6 +139,8 @@ extern u32 ARM9ClockShift; extern u32 IME[2]; extern u32 IE[2]; extern u32 IF[2]; +extern u32 IE2; +extern u32 IF2; extern Timer Timers[8]; extern u16 PowerControl9; @@ -162,8 +194,11 @@ void Halt(); void MapSharedWRAM(u8 val); +void UpdateIRQ(u32 cpu); void SetIRQ(u32 cpu, u32 irq); void ClearIRQ(u32 cpu, u32 irq); +void SetIRQ2(u32 irq); +void ClearIRQ2(u32 irq); bool HaltInterrupted(u32 cpu); void StopCPU(u32 cpu, u32 mask); void ResumeCPU(u32 cpu, u32 mask); -- cgit v1.2.3 From dc3c9f5bf8d86dfa11ecf239a28ca50f7bfe3fe6 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Tue, 18 Jun 2019 14:12:37 +0200 Subject: take all the SDMMC shit further. now it's completing MMC init and trying to read shit. --- src/DSi.h | 5 ++ src/DSi_SD.cpp | 196 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/DSi_SD.h | 25 ++++++++ src/NDS.h | 3 + 4 files changed, 218 insertions(+), 11 deletions(-) (limited to 'src/NDS.h') diff --git a/src/DSi.h b/src/DSi.h index 3ebee37..efd533a 100644 --- a/src/DSi.h +++ b/src/DSi.h @@ -20,12 +20,17 @@ #define DSI_H #include "NDS.h" +#include "DSi_SD.h" namespace DSi { extern u8 eMMC_CID[16]; +extern DSi_SDHost* SDMMC; +extern DSi_SDHost* SDIO; + + bool Init(); void DeInit(); void Reset(); diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index 35859cc..76c2676 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -30,12 +30,18 @@ DSi_SDHost::DSi_SDHost(u32 num) { Num = num; + DataFIFO[0] = new FIFO(0x100); + DataFIFO[1] = new FIFO(0x100); + Ports[0] = NULL; Ports[1] = NULL; } DSi_SDHost::~DSi_SDHost() { + delete DataFIFO[0]; + delete DataFIFO[1]; + if (Ports[0]) delete Ports[0]; if (Ports[1]) delete Ports[1]; } @@ -53,14 +59,26 @@ void DSi_SDHost::Reset() SoftReset = 0x0007; // CHECKME SDClock = 0; + SDOption = 0; Command = 0; Param = 0; memset(ResponseBuffer, 0, sizeof(ResponseBuffer)); + DataFIFO[0]->Clear(); + DataFIFO[1]->Clear(); + CurFIFO = 0; + IRQStatus = 0; IRQMask = 0x8B7F031D; + DataCtl = 0; + Data32IRQ = 0; + DataMode = 0; + BlockCount16 = 0; BlockCount32 = 0; BlockCountInternal = 0; + BlockLen16 = 0; BlockLen32 = 0; + StopAction = 0; + if (Ports[0]) delete Ports[0]; if (Ports[1]) delete Ports[1]; Ports[0] = NULL; @@ -86,6 +104,11 @@ void DSi_SDHost::DoSavestate(Savestate* file) } +void DSi_SDHost::ClearIRQ(u32 irq) +{ + IRQStatus &= ~(1<CurFIFO ^= 1; + + host->ClearIRQ(25); + host->SetIRQ(24); + if (param & 0x2) host->SetIRQ(2); +} + +void DSi_SDHost::SendData(u8* data, u32 len, bool last) +{ + printf("%s: data RX, len=%d, blkcnt=%d blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockLen16, IRQMask); + if (len != BlockLen16) printf("!! BAD BLOCKLEN\n"); + + u32 f = CurFIFO ^ 1; + for (u32 i = 0; i < len; i += 2) + DataFIFO[f]->Write(*(u16*)&data[i]); + + //CurFIFO = f; + //SetIRQ(24); + // TODO: determine what the delay should be! + // for now, this is a placeholder + // we need a delay because DSi boot2 will send a command and then wait for IRQ0 + // but if IRQ24 is thrown instantly, the handler clears IRQ0 before the + // send-command function starts polling IRQ status + u32 param = Num | (last << 1); + NDS::ScheduleEvent(NDS::Event_DSi_SDTransfer, false, 512, FinishSend, param); +} + u16 DSi_SDHost::Read(u32 addr) { @@ -119,6 +173,9 @@ u16 DSi_SDHost::Read(u32 addr) case 0x004: return Param & 0xFFFF; case 0x006: return Param >> 16; + case 0x008: return StopAction; + case 0x00A: return BlockCount16; + case 0x00C: return ResponseBuffer[0]; case 0x00E: return ResponseBuffer[1]; case 0x010: return ResponseBuffer[2]; @@ -128,14 +185,70 @@ u16 DSi_SDHost::Read(u32 addr) case 0x018: return ResponseBuffer[6]; case 0x01A: return ResponseBuffer[7]; - case 0x01C: return IRQStatus & 0x031D; - case 0x01E: return (IRQStatus >> 16) & 0x8B7F; + case 0x01C: return (IRQStatus & 0x031D) | 0x0030; // TODO: adjust insert flags for SD card + case 0x01E: return ((IRQStatus >> 16) & 0x8B7F); case 0x020: return IRQMask & 0x031D; case 0x022: return (IRQMask >> 16) & 0x8B7F; case 0x024: return SDClock; + case 0x026: return BlockLen16; + case 0x028: return SDOption; + + case 0x030: // FIFO16 + { + // TODO: decrement BlockLen???? + + u32 f = CurFIFO; + if (DataFIFO[f]->IsEmpty()) + { + // TODO + return 0; + } + + DSi_SDDevice* dev = Ports[PortSelect & 0x1]; + u16 ret = DataFIFO[f]->Read(); + + if (DataFIFO[f]->IsEmpty()) + { + ClearIRQ(24); + + if (BlockCountInternal == 0) + { + printf("%s: data RX complete", SD_DESC); + + if (StopAction & (1<<8)) + { + printf(", sending CMD12"); + if (dev) dev->SendCMD(12, 0); + } + + printf("\n"); + + // CHECKME: presumably IRQ2 should not trigger here, but rather + // when the data transfer is done + //SetIRQ(0); + //SetIRQ(2); + } + else + { + BlockCountInternal--; + + if (dev) dev->ContinueTransfer(); + } + + SetIRQ(25); + } + + return ret; + } + + case 0x0D8: return DataCtl; case 0x0E0: return SoftReset; + + case 0x100: return Data32IRQ; + case 0x104: return BlockLen32; + case 0x108: return BlockCount32; } printf("unknown %s read %08X\n", SD_DESC, addr); @@ -171,32 +284,55 @@ void DSi_SDHost::Write(u32 addr, u16 val) } return; - case 0x002: PortSelect = val; return; + case 0x002: PortSelect = val; printf("%s: PORT SELECT %04X\n", SD_DESC, val); return; case 0x004: Param = (Param & 0xFFFF0000) | val; return; case 0x006: Param = (Param & 0x0000FFFF) | (val << 16); return; - case 0x01C: IRQStatus &= ~(u32)val; return; - case 0x01E: IRQStatus &= ~((u32)val << 16); return; + case 0x008: StopAction = val & 0x0101; return; + case 0x00A: BlockCount16 = val; BlockCountInternal = val; return; + + case 0x01C: IRQStatus &= (val | 0xFFFF0000); return; + case 0x01E: IRQStatus &= ((val << 16) | 0xFFFF); return; case 0x020: IRQMask = (IRQMask & 0x8B7F0000) | (val & 0x031D); return; case 0x022: IRQMask = (IRQMask & 0x0000031D) | ((val & 0x8B7F) << 16); return; case 0x024: SDClock = val & 0x03FF; return; + case 0x026: + BlockLen16 = val & 0x03FF; + if (BlockLen16 > 0x200) BlockLen16 = 0x200; + return; + case 0x028: SDOption = val & 0xC1FF; return; + + case 0x0D8: + DataCtl = (val & 0x0022); + DataMode = ((DataCtl >> 1) & 0x1) & ((Data32IRQ >> 1) & 0x1); + printf("%s: data mode %d-bit\n", SD_DESC, DataMode?32:16); + return; case 0x0E0: if ((SoftReset & 0x0001) && !(val & 0x0001)) { printf("%s: RESET\n", SD_DESC); - // TODO: STOP_INTERNAL_ACTION - // TODO: SD_RESPONSE + StopAction = 0; + memset(ResponseBuffer, 0, sizeof(ResponseBuffer)); IRQStatus = 0; // TODO: ERROR_DETAIL_STATUS - // TODO: CARD_CLK_CTL - // TODO: CARD_OPTION + SDClock &= ~0x0500; + SDOption = 0x40EE; // TODO: CARD_IRQ_STAT // TODO: FIFO16 shit } SoftReset = 0x0006 | (val & 0x0001); return; + + case 0x100: + Data32IRQ = (val & 0x1802) | (Data32IRQ & 0x0300); + if (val & (1<<10)) printf("TODO: SD/MMC: CLEAR FIFO32\n"); + DataMode = ((DataCtl >> 1) & 0x1) & ((Data32IRQ >> 1) & 0x1); + printf("%s: data mode %d-bit\n", SD_DESC, DataMode?32:16); + return; + case 0x104: BlockLen32 = val & 0x03FF; return; + case 0x108: BlockCount32 = val; return; } printf("unknown %s write %08X %04X\n", SD_DESC, addr, val); @@ -210,7 +346,7 @@ DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, const char* path File = Platform::OpenLocalFile(path, "r+b"); - CSR = 0x00; // checkme + CSR = 0x00000100; // checkme // TODO: busy bit // TODO: SDHC/SDXC bit @@ -219,6 +355,12 @@ DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, const char* path // TODO: customize based on card size etc u8 csd_template[16] = {0x40, 0x40, 0x96, 0xE9, 0x7F, 0xDB, 0xF6, 0xDF, 0x01, 0x59, 0x0F, 0x2A, 0x01, 0x26, 0x90, 0x00}; memcpy(CSD, csd_template, 16); + + // checkme + memset(SCR, 0, 8); + *(u32*)&SCR[0] = 0x012A0000; + + memset(SSR, 0, 64); } DSi_MMCStorage::~DSi_MMCStorage() @@ -277,8 +419,16 @@ void DSi_MMCStorage::SendCMD(u8 cmd, u32 param) Host->SendResponse(*(u32*)&CSD[3], true); return; + case 12: // stop operation + Host->SendResponse(CSR, true); + return; + + case 16: // set block size + BlockSize = param; + Host->SendResponse(CSR, true); + return; + case 55: // ?? - printf("CMD55 %08X\n", param); CSR |= (1<<5); Host->SendResponse(CSR, true); return; @@ -291,13 +441,37 @@ void DSi_MMCStorage::SendACMD(u8 cmd, u32 param) { switch (cmd) { + case 6: // set bus width (TODO?) + printf("SET BUS WIDTH %08X\n", param); + Host->SendResponse(CSR, true); + return; + + case 13: // get SSR + Host->SendResponse(CSR, true); + Host->SendData(SSR, 64, true); + return; + case 41: // set operating conditions OCR &= 0xBF000000; OCR |= (param & 0x40FFFFFF); Host->SendResponse(OCR, true); SetState(0x01); return; + + case 42: // ??? + Host->SendResponse(CSR, true); + return; + + case 51: // get SCR + Host->SendResponse(CSR, true); + Host->SendData(SCR, 8, true); + return; } printf("MMC: unknown ACMD %d %08X\n", cmd, param); } + +void DSi_MMCStorage::ContinueTransfer() +{ + // +} diff --git a/src/DSi_SD.h b/src/DSi_SD.h index d223fac..ae8cd11 100644 --- a/src/DSi_SD.h +++ b/src/DSi_SD.h @@ -19,6 +19,10 @@ #ifndef DSI_SD_H #define DSI_SD_H +#include +#include "FIFO.h" + + class DSi_SDDevice; @@ -32,7 +36,9 @@ public: void DoSavestate(Savestate* file); + static void FinishSend(u32 param); void SendResponse(u32 val, bool last); + void SendData(u8* data, u32 len, bool last); u16 Read(u32 addr); void Write(u32 addr, u16 val); @@ -43,16 +49,28 @@ private: u16 PortSelect; u16 SoftReset; u16 SDClock; + u16 SDOption; u32 IRQStatus; // IF u32 IRQMask; // ~IE + u16 DataCtl; + u16 Data32IRQ; + u32 DataMode; // 0=16bit 1=32bit + u16 BlockCount16, BlockCount32, BlockCountInternal; + u16 BlockLen16, BlockLen32; + u16 StopAction; + u16 Command; u32 Param; u16 ResponseBuffer[8]; + FIFO* DataFIFO[2]; + u32 CurFIFO; // FIFO accessible for read/write + DSi_SDDevice* Ports[2]; + void ClearIRQ(u32 irq); void SetIRQ(u32 irq); }; @@ -64,6 +82,7 @@ public: ~DSi_SDDevice() {} virtual void SendCMD(u8 cmd, u32 param) = 0; + virtual void ContinueTransfer() = 0; protected: DSi_SDHost* Host; @@ -81,6 +100,8 @@ public: void SendCMD(u8 cmd, u32 param); void SendACMD(u8 cmd, u32 param); + void ContinueTransfer(); + private: bool Internal; char FilePath[1024]; @@ -92,6 +113,10 @@ private: u32 CSR; u32 OCR; u32 RCA; + u8 SCR[8]; + u8 SSR[64]; + + u32 BlockSize; void SetState(u32 state) { CSR &= ~(0xF << 9); CSR |= (state << 9); } }; diff --git a/src/NDS.h b/src/NDS.h index e6cd2ee..f87ffed 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -42,6 +42,9 @@ enum Event_Div, Event_Sqrt, + // DSi + Event_DSi_SDTransfer, + Event_MAX }; -- cgit v1.2.3 From d6bbc6f0f1ede57f0805137617ba670a49f7506f Mon Sep 17 00:00:00 2001 From: Arisotura Date: Tue, 18 Jun 2019 22:54:07 +0200 Subject: tremble upon the NDMA implementation that doesn't do much beyond getting stuck --- src/DMA.cpp | 6 -- src/DSi.cpp | 171 +++++++++++++++++++++++++++++++ src/DSi.h | 4 + src/DSi_NDMA.cpp | 301 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/DSi_NDMA.h | 74 +++++++++++++- src/NDS.cpp | 4 + src/NDS.h | 5 +- 7 files changed, 556 insertions(+), 9 deletions(-) (limited to 'src/NDS.h') diff --git a/src/DMA.cpp b/src/DMA.cpp index 2814264..0826d7a 100644 --- a/src/DMA.cpp +++ b/src/DMA.cpp @@ -20,15 +20,9 @@ #include "NDS.h" #include "DSi.h" #include "DMA.h" -#include "NDSCart.h" #include "GPU.h" -// NOTES ON DMA SHIT -// -// * could use optimized code paths for common types of DMA transfers. for example, VRAM -// have to profile it to see if it's actually worth doing - // DMA TIMINGS // diff --git a/src/DSi.cpp b/src/DSi.cpp index abd3bd6..0c9c26c 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -25,6 +25,7 @@ #include "sha1/sha1.h" #include "Platform.h" +#include "DSi_NDMA.h" #include "DSi_I2C.h" #include "DSi_SD.h" @@ -57,6 +58,9 @@ u32 NWRAMStart[2][3]; u32 NWRAMEnd[2][3]; u32 NWRAMMask[2][3]; +u32 NDMACnt[2]; +DSi_NDMA* NDMAs[8]; + DSi_SDHost* SDMMC; DSi_SDHost* SDIO; @@ -68,6 +72,15 @@ bool Init() { if (!DSi_I2C::Init()) return false; + NDMAs[0] = new DSi_NDMA(0, 0); + NDMAs[1] = new DSi_NDMA(0, 1); + NDMAs[2] = new DSi_NDMA(0, 2); + NDMAs[3] = new DSi_NDMA(0, 3); + NDMAs[4] = new DSi_NDMA(1, 0); + NDMAs[5] = new DSi_NDMA(1, 1); + NDMAs[6] = new DSi_NDMA(1, 2); + NDMAs[7] = new DSi_NDMA(1, 3); + SDMMC = new DSi_SDHost(0); SDIO = new DSi_SDHost(1); @@ -78,6 +91,8 @@ void DeInit() { DSi_I2C::DeInit(); + for (int i = 0; i < 8; i++) delete NDMAs[i]; + delete SDMMC; delete SDIO; } @@ -91,6 +106,9 @@ void Reset() NDS::ARM9->JumpTo(BootAddr[0]); NDS::ARM7->JumpTo(BootAddr[1]); + NDMACnt[0] = 0; NDMACnt[1] = 0; + for (int i = 0; i < 8; i++) NDMAs[i]->Reset(); + DSi_I2C::Reset(); SDMMC->Reset(); @@ -279,6 +297,40 @@ bool LoadNAND() } +void RunNDMAs(u32 cpu) +{ + // TODO: round-robin mode (requires DMA channels to have a subblock delay set) + + if (cpu == 0) + { + if (NDS::ARM9Timestamp >= NDS::ARM9Target) return; + + // + } + else + { + if (NDS::ARM7Timestamp >= NDS::ARM7Target) return; + + // + } +} + +void StallNDMAs() +{ + // TODO +} + +bool NDMAsRunning(u32 cpu) +{ + cpu <<= 2; + if (NDMAs[cpu+0]->IsRunning()) return true; + if (NDMAs[cpu+1]->IsRunning()) return true; + if (NDMAs[cpu+2]->IsRunning()) return true; + if (NDMAs[cpu+3]->IsRunning()) return true; + return false; +} + + // new WRAM mapping // TODO: find out what happens upon overlapping slots!! @@ -872,6 +924,36 @@ u32 ARM9IORead32(u32 addr) switch (addr) { case 0x04004010: return 1; // todo + + case 0x04004100: return NDMACnt[0]; + case 0x04004104: return NDMAs[0]->SrcAddr; + case 0x04004108: return NDMAs[0]->DstAddr; + case 0x0400410C: return NDMAs[0]->TotalLength; + case 0x04004110: return NDMAs[0]->BlockLength; + case 0x04004114: return NDMAs[0]->SubblockTimer; + case 0x04004118: return NDMAs[0]->FillData; + case 0x0400411C: return NDMAs[0]->Cnt; + case 0x04004120: return NDMAs[1]->SrcAddr; + case 0x04004124: return NDMAs[1]->DstAddr; + case 0x04004128: return NDMAs[1]->TotalLength; + case 0x0400412C: return NDMAs[1]->BlockLength; + case 0x04004130: return NDMAs[1]->SubblockTimer; + case 0x04004134: return NDMAs[1]->FillData; + case 0x04004138: return NDMAs[1]->Cnt; + case 0x0400413C: return NDMAs[2]->SrcAddr; + case 0x04004140: return NDMAs[2]->DstAddr; + case 0x04004144: return NDMAs[2]->TotalLength; + case 0x04004148: return NDMAs[2]->BlockLength; + case 0x0400414C: return NDMAs[2]->SubblockTimer; + case 0x04004150: return NDMAs[2]->FillData; + case 0x04004154: return NDMAs[2]->Cnt; + case 0x04004158: return NDMAs[3]->SrcAddr; + case 0x0400415C: return NDMAs[3]->DstAddr; + case 0x04004160: return NDMAs[3]->TotalLength; + case 0x04004164: return NDMAs[3]->BlockLength; + case 0x04004168: return NDMAs[3]->SubblockTimer; + case 0x0400416C: return NDMAs[3]->FillData; + case 0x04004170: return NDMAs[3]->Cnt; } return NDS::ARM9IORead32(addr); @@ -899,6 +981,35 @@ void ARM9IOWrite32(u32 addr, u32 val) { switch (addr) { + case 0x04004100: NDMACnt[0] = val & 0x800F0000; return; + case 0x04004104: NDMAs[0]->SrcAddr = val & 0xFFFFFFFC; return; + case 0x04004108: NDMAs[0]->DstAddr = val & 0xFFFFFFFC; return; + case 0x0400410C: NDMAs[0]->TotalLength = val & 0x0FFFFFFF; return; + case 0x04004110: NDMAs[0]->BlockLength = val & 0x00FFFFFF; return; + case 0x04004114: NDMAs[0]->SubblockTimer = val & 0x0003FFFF; return; + case 0x04004118: NDMAs[0]->FillData = val; return; + case 0x0400411C: NDMAs[0]->WriteCnt(val); return; + case 0x04004120: NDMAs[1]->SrcAddr = val & 0xFFFFFFFC; return; + case 0x04004124: NDMAs[1]->DstAddr = val & 0xFFFFFFFC; return; + case 0x04004128: NDMAs[1]->TotalLength = val & 0x0FFFFFFF; return; + case 0x0400412C: NDMAs[1]->BlockLength = val & 0x00FFFFFF; return; + case 0x04004130: NDMAs[1]->SubblockTimer = val & 0x0003FFFF; return; + case 0x04004134: NDMAs[1]->FillData = val; return; + case 0x04004138: NDMAs[1]->WriteCnt(val); return; + case 0x0400413C: NDMAs[2]->SrcAddr = val & 0xFFFFFFFC; return; + case 0x04004140: NDMAs[2]->DstAddr = val & 0xFFFFFFFC; return; + case 0x04004144: NDMAs[2]->TotalLength = val & 0x0FFFFFFF; return; + case 0x04004148: NDMAs[2]->BlockLength = val & 0x00FFFFFF; return; + case 0x0400414C: NDMAs[2]->SubblockTimer = val & 0x0003FFFF; return; + case 0x04004150: NDMAs[2]->FillData = val; return; + case 0x04004154: NDMAs[2]->WriteCnt(val); return; + case 0x04004158: NDMAs[3]->SrcAddr = val & 0xFFFFFFFC; return; + case 0x0400415C: NDMAs[3]->DstAddr = val & 0xFFFFFFFC; return; + case 0x04004160: NDMAs[3]->TotalLength = val & 0x0FFFFFFF; return; + case 0x04004164: NDMAs[3]->BlockLength = val & 0x00FFFFFF; return; + case 0x04004168: NDMAs[3]->SubblockTimer = val & 0x0003FFFF; return; + case 0x0400416C: NDMAs[3]->FillData = val; return; + case 0x04004170: NDMAs[3]->WriteCnt(val); return; } return NDS::ARM9IOWrite32(addr, val); @@ -950,6 +1061,36 @@ u32 ARM7IORead32(u32 addr) case 0x0400021C: return NDS::IF2; case 0x04004008: return 0x80000000; // HAX + + case 0x04004100: return NDMACnt[1]; + case 0x04004104: return NDMAs[4]->SrcAddr; + case 0x04004108: return NDMAs[4]->DstAddr; + case 0x0400410C: return NDMAs[4]->TotalLength; + case 0x04004110: return NDMAs[4]->BlockLength; + case 0x04004114: return NDMAs[4]->SubblockTimer; + case 0x04004118: return NDMAs[4]->FillData; + case 0x0400411C: return NDMAs[4]->Cnt; + case 0x04004120: return NDMAs[5]->SrcAddr; + case 0x04004124: return NDMAs[5]->DstAddr; + case 0x04004128: return NDMAs[5]->TotalLength; + case 0x0400412C: return NDMAs[5]->BlockLength; + case 0x04004130: return NDMAs[5]->SubblockTimer; + case 0x04004134: return NDMAs[5]->FillData; + case 0x04004138: return NDMAs[5]->Cnt; + case 0x0400413C: return NDMAs[6]->SrcAddr; + case 0x04004140: return NDMAs[6]->DstAddr; + case 0x04004144: return NDMAs[6]->TotalLength; + case 0x04004148: return NDMAs[6]->BlockLength; + case 0x0400414C: return NDMAs[6]->SubblockTimer; + case 0x04004150: return NDMAs[6]->FillData; + case 0x04004154: return NDMAs[6]->Cnt; + case 0x04004158: return NDMAs[7]->SrcAddr; + case 0x0400415C: return NDMAs[7]->DstAddr; + case 0x04004160: return NDMAs[7]->TotalLength; + case 0x04004164: return NDMAs[7]->BlockLength; + case 0x04004168: return NDMAs[7]->SubblockTimer; + case 0x0400416C: return NDMAs[7]->FillData; + case 0x04004170: return NDMAs[7]->Cnt; } if (addr >= 0x04004800 && addr < 0x04004A00) @@ -1003,6 +1144,36 @@ void ARM7IOWrite32(u32 addr, u32 val) { case 0x04000218: NDS::IE2 = (val & 0x7FF7); NDS::UpdateIRQ(1); return; case 0x0400021C: NDS::IF2 &= ~(val & 0x7FF7); NDS::UpdateIRQ(1); return; + + case 0x04004100: NDMACnt[1] = val & 0x800F0000; return; + case 0x04004104: NDMAs[4]->SrcAddr = val & 0xFFFFFFFC; return; + case 0x04004108: NDMAs[4]->DstAddr = val & 0xFFFFFFFC; return; + case 0x0400410C: NDMAs[4]->TotalLength = val & 0x0FFFFFFF; return; + case 0x04004110: NDMAs[4]->BlockLength = val & 0x00FFFFFF; return; + case 0x04004114: NDMAs[4]->SubblockTimer = val & 0x0003FFFF; return; + case 0x04004118: NDMAs[4]->FillData = val; return; + case 0x0400411C: NDMAs[4]->WriteCnt(val); return; + case 0x04004120: NDMAs[5]->SrcAddr = val & 0xFFFFFFFC; return; + case 0x04004124: NDMAs[5]->DstAddr = val & 0xFFFFFFFC; return; + case 0x04004128: NDMAs[5]->TotalLength = val & 0x0FFFFFFF; return; + case 0x0400412C: NDMAs[5]->BlockLength = val & 0x00FFFFFF; return; + case 0x04004130: NDMAs[5]->SubblockTimer = val & 0x0003FFFF; return; + case 0x04004134: NDMAs[5]->FillData = val; return; + case 0x04004138: NDMAs[5]->WriteCnt(val); return; + case 0x0400413C: NDMAs[6]->SrcAddr = val & 0xFFFFFFFC; return; + case 0x04004140: NDMAs[6]->DstAddr = val & 0xFFFFFFFC; return; + case 0x04004144: NDMAs[6]->TotalLength = val & 0x0FFFFFFF; return; + case 0x04004148: NDMAs[6]->BlockLength = val & 0x00FFFFFF; return; + case 0x0400414C: NDMAs[6]->SubblockTimer = val & 0x0003FFFF; return; + case 0x04004150: NDMAs[6]->FillData = val; return; + case 0x04004154: NDMAs[6]->WriteCnt(val); return; + case 0x04004158: NDMAs[7]->SrcAddr = val & 0xFFFFFFFC; return; + case 0x0400415C: NDMAs[7]->DstAddr = val & 0xFFFFFFFC; return; + case 0x04004160: NDMAs[7]->TotalLength = val & 0x0FFFFFFF; return; + case 0x04004164: NDMAs[7]->BlockLength = val & 0x00FFFFFF; return; + case 0x04004168: NDMAs[7]->SubblockTimer = val & 0x0003FFFF; return; + case 0x0400416C: NDMAs[7]->FillData = val; return; + case 0x04004170: NDMAs[7]->WriteCnt(val); return; } if (addr >= 0x04004800 && addr < 0x04004A00) diff --git a/src/DSi.h b/src/DSi.h index efd533a..32253a7 100644 --- a/src/DSi.h +++ b/src/DSi.h @@ -38,6 +38,10 @@ void Reset(); bool LoadBIOS(); bool LoadNAND(); +void RunNDMAs(u32 cpu); +void StallNDMAs(); +bool NDMAsRunning(u32 cpu); + void MapNWRAM_A(u32 num, u8 val); void MapNWRAM_B(u32 num, u8 val); void MapNWRAM_C(u32 num, u8 val); diff --git a/src/DSi_NDMA.cpp b/src/DSi_NDMA.cpp index 6a524dd..a8055eb 100644 --- a/src/DSi_NDMA.cpp +++ b/src/DSi_NDMA.cpp @@ -15,3 +15,304 @@ You should have received a copy of the GNU General Public License along with melonDS. If not, see http://www.gnu.org/licenses/. */ + +#include +#include "NDS.h" +#include "DSi.h" +#include "DSi_NDMA.h" +#include "GPU.h" + + + +DSi_NDMA::DSi_NDMA(u32 cpu, u32 num) +{ + CPU = cpu; + Num = num; + + Reset(); +} + +DSi_NDMA::~DSi_NDMA() +{ +} + +void DSi_NDMA::Reset() +{ + SrcAddr = 0; + DstAddr = 0; + TotalLength = 0; + BlockLength = 0; + SubblockTimer = 0; + FillData = 0; + Cnt = 0; + + StartMode = 0; + CurSrcAddr = 0; + CurDstAddr = 0; + SubblockLength = 0; + RemCount = 0; + IterCount = 0; + TotalRemCount = 0; + SrcAddrInc = 0; + DstAddrInc = 0; + + Running = false; + InProgress = false; +} + +void DSi_NDMA::DoSavestate(Savestate* file) +{ + // TODO! +} + +void DSi_NDMA::WriteCnt(u32 val) +{ + u32 oldcnt = Cnt; + Cnt = val; + + if ((!(oldcnt & 0x80000000)) && (val & 0x80000000)) // checkme + { + CurSrcAddr = SrcAddr; + CurDstAddr = DstAddr; + TotalRemCount = TotalLength; + + switch ((Cnt >> 10) & 0x3) + { + case 0: DstAddrInc = 1; break; + case 1: DstAddrInc = -1; break; + case 2: DstAddrInc = 0; break; + case 3: DstAddrInc = 1; printf("BAD NDMA DST INC MODE 3\n"); break; + } + + switch ((Cnt >> 13) & 0x3) + { + case 0: SrcAddrInc = 1; break; + case 1: SrcAddrInc = -1; break; + case 2: SrcAddrInc = 0; break; + case 3: SrcAddrInc = 0; break; // fill mode + } + + StartMode = (Cnt >> 24) & 0x1F; + if (StartMode > 0x10) StartMode = 0x10; + if (CPU == 1) StartMode |= 0x20; + + if ((StartMode & 0x1F) == 0x10) + Start(); + + if (StartMode != 0x10 && StartMode != 0x30) + printf("UNIMPLEMENTED ARM%d NDMA%d START MODE %02X, %08X->%08X\n", CPU?7:9, Num, StartMode, SrcAddr, DstAddr); + } +} + +void DSi_NDMA::Start() +{ + if (Running) return; + + if (!InProgress) + { + RemCount = BlockLength; + if (!RemCount) + RemCount = 0x1000000; + } + + // TODO: how does GXFIFO DMA work with all the block shito? + IterCount = RemCount; + + if (IterCount > TotalRemCount) + IterCount = TotalRemCount; + + if (Cnt & (1<<12)) CurDstAddr = DstAddr; + if (Cnt & (1<<15)) CurSrcAddr = SrcAddr; + + printf("ARM%d NDMA%d %08X %02X %08X->%08X %d bytes\n", CPU?7:9, Num, Cnt, StartMode, CurSrcAddr, CurDstAddr, RemCount*4); + + //IsGXFIFODMA = (CPU == 0 && (CurSrcAddr>>24) == 0x02 && CurDstAddr == 0x04000400 && DstAddrInc == 0); + + // TODO eventually: not stop if we're running code in ITCM + + if (SubblockTimer & 0xFFFF) + printf("TODO! NDMA SUBBLOCK TIMER: %08X\n", SubblockTimer); + + if (NDS::DMAsRunning(CPU)) + Running = 1; + else + Running = 2; + + InProgress = true; + NDS::StopCPU(CPU, 1<<(Num+4)); +} + +void DSi_NDMA::Run() +{ + if (!Running) return; + if (CPU == 0) return Run9(); + else return Run7(); +} + +void DSi_NDMA::Run9() +{ + if (NDS::ARM9Timestamp >= NDS::ARM9Target) return; + + Executing = true; + + // add NS penalty for first accesses in burst + bool burststart = (Running == 2); + Running = 1; + + s32 unitcycles; + //s32 lastcycles = cycles; + + bool dofill = ((Cnt >> 13) & 0x3) == 3; + + if ((CurSrcAddr >> 24) == 0x02 && (CurDstAddr >> 24) == 0x02) + { + unitcycles = NDS::ARM9MemTimings[CurSrcAddr >> 14][2] + NDS::ARM9MemTimings[CurDstAddr >> 14][2]; + } + else + { + unitcycles = NDS::ARM9MemTimings[CurSrcAddr >> 14][3] + NDS::ARM9MemTimings[CurDstAddr >> 14][3]; + if ((CurSrcAddr >> 24) == (CurDstAddr >> 24)) + unitcycles++; + else if ((CurSrcAddr >> 24) == 0x02) + unitcycles--; + + /*if (burststart) + { + cycles -= 2; + cycles -= (NDS::ARM9MemTimings[CurSrcAddr >> 14][2] + NDS::ARM9MemTimings[CurDstAddr >> 14][2]); + cycles += unitcycles; + }*/ + } + + while (IterCount > 0 && !Stall) + { + NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift); + + if (dofill) + DSi::ARM9Write32(CurDstAddr, FillData); + else + DSi::ARM9Write32(CurDstAddr, DSi::ARM9Read32(CurSrcAddr)); + + CurSrcAddr += SrcAddrInc<<2; + CurDstAddr += DstAddrInc<<2; + IterCount--; + RemCount--; + TotalRemCount--; + + if (NDS::ARM9Timestamp >= NDS::ARM9Target) break; + } + + Executing = false; + Stall = false; + + if (RemCount) + { + if (IterCount == 0) + { + Running = 0; + NDS::ResumeCPU(0, 1<<(Num+4)); + + //if (StartMode == 0x07) + // GPU3D::CheckFIFODMA(); + } + + return; + } + + if ((StartMode & 0x1F) == 0x10) // CHECKME + Cnt &= ~(1<<31); + else if (!(Cnt & (1<<29))) + { + if (TotalRemCount == 0) + Cnt &= ~(1<<31); + } + + if (Cnt & (1<<30)) + NDS::SetIRQ(0, NDS::IRQ_DSi_NDMA0 + Num); + + Running = 0; + InProgress = false; + NDS::ResumeCPU(0, 1<<(Num+4)); +} + +void DSi_NDMA::Run7() +{ + if (NDS::ARM7Timestamp >= NDS::ARM7Target) return; + + Executing = true; + + // add NS penalty for first accesses in burst + bool burststart = (Running == 2); + Running = 1; + + s32 unitcycles; + //s32 lastcycles = cycles; + + bool dofill = ((Cnt >> 13) & 0x3) == 3; + + if ((CurSrcAddr >> 24) == 0x02 && (CurDstAddr >> 24) == 0x02) + { + unitcycles = NDS::ARM7MemTimings[CurSrcAddr >> 15][2] + NDS::ARM7MemTimings[CurDstAddr >> 15][2]; + } + else + { + unitcycles = NDS::ARM7MemTimings[CurSrcAddr >> 15][3] + NDS::ARM7MemTimings[CurDstAddr >> 15][3]; + if ((CurSrcAddr >> 23) == (CurDstAddr >> 23)) + unitcycles++; + else if ((CurSrcAddr >> 24) == 0x02) + unitcycles--; + + /*if (burststart) + { + cycles -= 2; + cycles -= (NDS::ARM7MemTimings[CurSrcAddr >> 15][2] + NDS::ARM7MemTimings[CurDstAddr >> 15][2]); + cycles += unitcycles; + }*/ + } + + while (IterCount > 0 && !Stall) + { + NDS::ARM7Timestamp += unitcycles; + + if (dofill) + DSi::ARM7Write32(CurDstAddr, FillData); + else + DSi::ARM7Write32(CurDstAddr, DSi::ARM7Read32(CurSrcAddr)); + + CurSrcAddr += SrcAddrInc<<2; + CurDstAddr += DstAddrInc<<2; + IterCount--; + RemCount--; + + if (NDS::ARM7Timestamp >= NDS::ARM7Target) break; + } + + Executing = false; + Stall = false; + + if (RemCount) + { + if (IterCount == 0) + { + Running = 0; + NDS::ResumeCPU(1, 1<<(Num+4)); + } + + return; + } + + if ((StartMode & 0x1F) == 0x10) // CHECKME + Cnt &= ~(1<<31); + else if (!(Cnt & (1<<29))) + { + if (TotalRemCount == 0) + Cnt &= ~(1<<31); + } + + if (Cnt & (1<<30)) + NDS::SetIRQ(1, NDS::IRQ_DSi_NDMA0 + Num); + + Running = 0; + InProgress = false; + NDS::ResumeCPU(1, 1<<(Num+4)); +} diff --git a/src/DSi_NDMA.h b/src/DSi_NDMA.h index 6661652..d7b7483 100644 --- a/src/DSi_NDMA.h +++ b/src/DSi_NDMA.h @@ -19,6 +19,78 @@ #ifndef DSI_NDMA_H #define DSI_NDMA_H -// +#include "types.h" + +class DSi_NDMA +{ +public: + DSi_NDMA(u32 cpu, u32 num); + ~DSi_NDMA(); + + void Reset(); + + void DoSavestate(Savestate* file); + + void WriteCnt(u32 val); + void Start(); + + void Run(); + + void Run9(); + void Run7(); + + bool IsInMode(u32 mode) + { + return ((mode == StartMode) && (Cnt & 0x80000000)); + } + + bool IsRunning() { return Running!=0; } + + void StartIfNeeded(u32 mode) + { + if ((mode == StartMode) && (Cnt & 0x80000000)) + Start(); + } + + void StopIfNeeded(u32 mode) + { + if (mode == StartMode) + Cnt &= ~0x80000000; + } + + void StallIfRunning() + { + if (Executing) Stall = true; + } + + u32 SrcAddr; + u32 DstAddr; + u32 TotalLength; // total length, when transferring multiple blocks + u32 BlockLength; // length of one transfer + u32 SubblockTimer; // optional delay between subblocks (only in round-robin mode) + u32 FillData; + u32 Cnt; + +private: + u32 CPU, Num; + + u32 StartMode; + u32 CurSrcAddr; + u32 CurDstAddr; + u32 SubblockLength; // length transferred per run when delay is used + u32 RemCount; + u32 IterCount; + u32 TotalRemCount; + u32 SrcAddrInc; + u32 DstAddrInc; + + u32 Running; + bool InProgress; + + bool Executing; + bool Stall; + + bool IsGXFIFODMA; +}; #endif // DSI_NDMA_H diff --git a/src/NDS.cpp b/src/NDS.cpp index 414f87c..e20f62f 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -827,6 +827,7 @@ u32 RunFrame() if (!(CPUStop & 0x80000000)) DMAs[1]->Run(); if (!(CPUStop & 0x80000000)) DMAs[2]->Run(); if (!(CPUStop & 0x80000000)) DMAs[3]->Run(); + DSi::RunNDMAs(0); } else { @@ -849,6 +850,7 @@ u32 RunFrame() DMAs[5]->Run(); DMAs[6]->Run(); DMAs[7]->Run(); + DSi::RunNDMAs(1); } else { @@ -1153,6 +1155,7 @@ void GXFIFOStall() DMAs[1]->StallIfRunning(); DMAs[2]->StallIfRunning(); DMAs[3]->StallIfRunning(); + DSi::StallNDMAs(); } } @@ -1367,6 +1370,7 @@ bool DMAsRunning(u32 cpu) if (DMAs[cpu+1]->IsRunning()) return true; if (DMAs[cpu+2]->IsRunning()) return true; if (DMAs[cpu+3]->IsRunning()) return true; + if (DSi::NDMAsRunning(cpu>>2)) return true; return false; } diff --git a/src/NDS.h b/src/NDS.h index f87ffed..850e829 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -101,7 +101,7 @@ enum IRQ2_DSi_GPIO18_0 = 0, IRQ2_DSi_GPIO18_1, IRQ2_DSi_GPIO18_2, - IRQ2_DSi_Unused35, + IRQ2_DSi_Unused3, IRQ2_DSi_GPIO33_0, IRQ2_DSi_Headphone, IRQ2_DSi_PowerButton, @@ -138,7 +138,6 @@ extern u64 ARM9Timestamp, ARM9Target; extern u64 ARM7Timestamp, ARM7Target; extern u32 ARM9ClockShift; -// hax extern u32 IME[2]; extern u32 IE[2]; extern u32 IF[2]; @@ -146,6 +145,8 @@ extern u32 IE2; extern u32 IF2; extern Timer Timers[8]; +extern u32 CPUStop; + extern u16 PowerControl9; extern u16 ExMemCnt[2]; -- cgit v1.2.3 From 06716794a1d69512312e1dc251b9762d27b15c8d Mon Sep 17 00:00:00 2001 From: Arisotura Date: Wed, 24 Jul 2019 18:48:52 +0200 Subject: lots of things. attempting to make wifi init work. not there yet. --- src/DSi.cpp | 55 ++++++++++---- src/DSi_AES.cpp | 23 ++++++ src/DSi_NWifi.cpp | 214 +++++++++++++++++++++++++++++++++++++++++++++++++----- src/DSi_NWifi.h | 27 +++++++ src/DSi_SD.cpp | 70 ++++++++++++++---- src/DSi_SD.h | 2 +- src/NDS.h | 3 +- 7 files changed, 344 insertions(+), 50 deletions(-) (limited to 'src/NDS.h') diff --git a/src/DSi.cpp b/src/DSi.cpp index 26a67f4..aed6b89 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -73,6 +73,7 @@ u64 ConsoleID; u8 eMMC_CID[16]; u8 ITCMInit[0x8000]; +u8 ARM7Init[0x3C00]; bool Init() @@ -120,6 +121,9 @@ void Reset() memcpy(NDS::ARM9->ITCM, ITCMInit, 0x8000); + for (u32 i = 0; i < 0x3C00; i+=4) + ARM7Write32(0x03FFC400+i, *(u32*)&ARM7Init[i]); + DSi_I2C::Reset(); DSi_AES::Reset(); @@ -138,9 +142,16 @@ void Reset() NDS::MapSharedWRAM(3); - // TEST - u8 derp[16] = {0xE5, 0xCC, 0x5A, 0x8B, 0x56, 0xD0, 0xC9, 0x72, 0x9C, 0x17, 0xE8, 0xDC, 0x39, 0x12, 0x36, 0xA9}; - for (int i = 0; i < 16; i+=4) ARM7Write32(0x03FFC580+i, *(u32*)&derp[i]); + u32 eaddr = 0x03FFE6E4; + ARM7Write32(eaddr+0x00, *(u32*)&eMMC_CID[0]); + ARM7Write32(eaddr+0x04, *(u32*)&eMMC_CID[4]); + ARM7Write32(eaddr+0x08, *(u32*)&eMMC_CID[8]); + ARM7Write32(eaddr+0x0C, *(u32*)&eMMC_CID[12]); + ARM7Write16(eaddr+0x2C, 0x0001); + ARM7Write16(eaddr+0x2E, 0x0001); + ARM7Write16(eaddr+0x3C, 0x0100); + ARM7Write16(eaddr+0x3E, 0x40E0); + ARM7Write16(eaddr+0x42, 0x0001); } bool LoadBIOS() @@ -328,19 +339,31 @@ bool LoadNAND() } memset(ITCMInit, 0, 0x8000); + memset(ARM7Init, 0, 0x3C00); - f = fopen("dsikeys.bin", "rb"); + f = fopen("initmem9.bin", "rb"); if (f) { // first 0x2524 bytes are loaded to 0x01FFC400 u32 dstaddr = 0x01FFC400; - fread(&ITCMInit[dstaddr & 0x7FFF], 0x2524, 1, f); + fread(&ITCMInit[dstaddr & 0x7FFF], /*0x2524*/0x3C00, 1, f); + fclose(f); + } + else + { + printf("DSi ARM9 meminit not found\n"); + } + + f = fopen("initmem7.bin", "rb"); + if (f) + { + fread(ARM7Init, 0x3C00, 1, f); fclose(f); } else { - printf("DSi keys not found\n"); + printf("DSi ARM7 meminit not found\n"); } return true; @@ -559,7 +582,7 @@ void MapNWRAMRange(u32 cpu, u32 num, u32 val) u8 ARM9Read8(u32 addr) -{ +{if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 8 9 %08X %08X\n", addr, NDS::GetPC(0)); switch (addr & 0xFF000000) { case 0x03000000: @@ -588,7 +611,7 @@ u8 ARM9Read8(u32 addr) } u16 ARM9Read16(u32 addr) -{ +{if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 16 9 %08X %08X\n", addr, NDS::GetPC(0)); switch (addr & 0xFF000000) { case 0x03000000: @@ -617,7 +640,8 @@ u16 ARM9Read16(u32 addr) } u32 ARM9Read32(u32 addr) -{ +{if(addr==0x029D02D8) printf("READ SHITTY VTABLE: %08X\n", NDS::GetPC(0)); +if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 32 9 %08X %08X\n", addr, NDS::GetPC(0)); switch (addr & 0xFF000000) { case 0x03000000: @@ -712,7 +736,7 @@ void ARM9Write16(u32 addr, u16 val) } void ARM9Write32(u32 addr, u32 val) -{ +{if(addr==0x02B05E34) printf("VGONP. %08X, %08X\n", val, NDS::GetPC(0)); switch (addr & 0xFF000000) { case 0x03000000: @@ -768,7 +792,8 @@ bool ARM9GetMemRegion(u32 addr, bool write, NDS::MemRegion* region) u8 ARM7Read8(u32 addr) -{ +{if(addr>=0x3FFC400 && addr<0x3FFE728) printf("OGON 8 %08X %08X\n", addr, NDS::GetPC(1)); +if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 8 7 %08X %08X\n", addr, NDS::GetPC(1)); switch (addr & 0xFF800000) { case 0x03000000: @@ -797,7 +822,8 @@ u8 ARM7Read8(u32 addr) } u16 ARM7Read16(u32 addr) -{ +{if(addr>=0x3FFC400 && addr<0x3FFE728) printf("OGON 16 %08X %08X\n", addr, NDS::GetPC(1)); +if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 16 7 %08X %08X\n", addr, NDS::GetPC(1)); switch (addr & 0xFF800000) { case 0x03000000: @@ -826,7 +852,8 @@ u16 ARM7Read16(u32 addr) } u32 ARM7Read32(u32 addr) -{ +{if(addr>=0x3FFC400 && addr<0x3FFE728) printf("OGON 32 %08X %08X\n", addr, NDS::GetPC(1)); +if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 32 7 %08X %08X\n", addr, NDS::GetPC(1)); switch (addr & 0xFF800000) { case 0x03000000: @@ -855,7 +882,7 @@ u32 ARM7Read32(u32 addr) } void ARM7Write8(u32 addr, u8 val) -{ +{if(addr==0x0228CD74) printf("RAKAKA %02X %08X\n", val, NDS::GetPC(1)); switch (addr & 0xFF800000) { case 0x03000000: diff --git a/src/DSi_AES.cpp b/src/DSi_AES.cpp index 8ae9082..4aa97bc 100644 --- a/src/DSi_AES.cpp +++ b/src/DSi_AES.cpp @@ -22,6 +22,7 @@ #include "DSi_AES.h" #include "FIFO.h" #include "tiny-AES-c/aes.hpp" +#include "Platform.h" namespace DSi_AES @@ -130,6 +131,7 @@ void Reset() // initialize keys, as per GBAtek +#if 0 // slot 0: modcrypt *(u32*)&KeyX[0][0] = 0x746E694E; *(u32*)&KeyX[0][4] = 0x6F646E65; @@ -148,6 +150,27 @@ void Reset() *(u32*)&KeyY[3][0] = 0x0AB9DC76; *(u32*)&KeyY[3][4] = 0xBD4DC4D3; *(u32*)&KeyY[3][8] = 0x202DDD1D; +#endif + FILE* f = Platform::OpenLocalFile("aeskeys.bin", "rb"); + if (f) + { + fread(KeyNormal[0], 16, 1, f); + fread(KeyX[0], 16, 1, f); + fread(KeyY[0], 16, 1, f); + fread(KeyNormal[1], 16, 1, f); + fread(KeyX[1], 16, 1, f); + fread(KeyY[1], 16, 1, f); + fread(KeyNormal[2], 16, 1, f); + fread(KeyX[2], 16, 1, f); + fread(KeyY[2], 16, 1, f); + fread(KeyNormal[3], 16, 1, f); + fread(KeyX[3], 16, 1, f); + fread(KeyY[3], 16, 1, f); + + fclose(f); + } + else + printf("AES: aeskeys.bin not found\n"); } diff --git a/src/DSi_NWifi.cpp b/src/DSi_NWifi.cpp index 5236551..e0591fb 100644 --- a/src/DSi_NWifi.cpp +++ b/src/DSi_NWifi.cpp @@ -114,11 +114,20 @@ DSi_NWifi::DSi_NWifi(DSi_SDHost* host) : DSi_SDDevice(host) { TransferCmd = 0xFFFFFFFF; RemSize = 0; + + WindowData = 0; + WindowReadAddr = 0; + WindowWriteAddr = 0; + + // TODO: check the actual mailbox size (presumably 0x200) + for (int i = 0; i < 8; i++) + Mailbox[i] = new FIFO(0x200); } DSi_NWifi::~DSi_NWifi() { - // + for (int i = 0; i < 8; i++) + delete Mailbox[i]; } @@ -165,9 +174,54 @@ void DSi_NWifi::F0_Write(u32 addr, u8 val) u8 DSi_NWifi::F1_Read(u32 addr) -{ - switch (addr) +{printf("F1 READ %05X\n", addr); + if (addr < 0x100) + { + return Mailbox[4]->Read(); + } + else if (addr < 0x200) + { + return Mailbox[5]->Read(); + } + else if (addr < 0x300) + { + return Mailbox[6]->Read(); + } + else if (addr < 0x400) + { + return Mailbox[7]->Read(); + } + else if (addr < 0x800) + { + switch (addr) + { + case 0x00450: return 1; // HAX!! + + case 0x00474: return WindowData & 0xFF; + case 0x00475: return (WindowData >> 8) & 0xFF; + case 0x00476: return (WindowData >> 16) & 0xFF; + case 0x00477: return WindowData >> 24; + } + } + else if (addr < 0x1000) + { + return Mailbox[4]->Read(); + } + else if (addr < 0x1800) + { + return Mailbox[5]->Read(); + } + else if (addr < 0x2000) + { + return Mailbox[6]->Read(); + } + else if (addr < 0x2800) + { + return Mailbox[7]->Read(); + } + else { + return Mailbox[4]->Read(); } printf("NWIFI: unknown func1 read %05X\n", addr); @@ -175,7 +229,91 @@ u8 DSi_NWifi::F1_Read(u32 addr) } void DSi_NWifi::F1_Write(u32 addr, u8 val) -{ +{printf("F1 WRITE %05X %02X\n", addr, val); + if (addr < 0x100) + { + if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n"); + Mailbox[0]->Write(val); + if (addr == 0xFF) BMI_Command(); + return; + } + else if (addr < 0x200) + { + if (Mailbox[1]->IsFull()) printf("!!! NWIFI: MBOX1 FULL\n"); + Mailbox[1]->Write(val); + return; + } + else if (addr < 0x300) + { + if (Mailbox[2]->IsFull()) printf("!!! NWIFI: MBOX2 FULL\n"); + Mailbox[2]->Write(val); + return; + } + else if (addr < 0x400) + { + if (Mailbox[3]->IsFull()) printf("!!! NWIFI: MBOX3 FULL\n"); + Mailbox[3]->Write(val); + return; + } + else if (addr < 0x800) + { + switch (addr) + { + case 0x00474: WindowData = (WindowData & 0xFFFFFF00) | val; return; + case 0x00475: WindowData = (WindowData & 0xFFFF00FF) | (val << 8); return; + case 0x00476: WindowData = (WindowData & 0xFF00FFFF) | (val << 16); return; + case 0x00477: WindowData = (WindowData & 0x00FFFFFF) | (val << 24); return; + + case 0x00478: + WindowWriteAddr = (WindowWriteAddr & 0xFFFFFF00) | val; + WindowWrite(); + return; + case 0x00479: WindowWriteAddr = (WindowWriteAddr & 0xFFFF00FF) | (val << 8); return; + case 0x0047A: WindowWriteAddr = (WindowWriteAddr & 0xFF00FFFF) | (val << 16); return; + case 0x0047B: WindowWriteAddr = (WindowWriteAddr & 0x00FFFFFF) | (val << 24); return; + + case 0x0047C: + WindowReadAddr = (WindowReadAddr & 0xFFFFFF00) | val; + WindowRead(); + return; + case 0x0047D: WindowReadAddr = (WindowReadAddr & 0xFFFF00FF) | (val << 8); return; + case 0x0047E: WindowReadAddr = (WindowReadAddr & 0xFF00FFFF) | (val << 16); return; + case 0x0047F: WindowReadAddr = (WindowReadAddr & 0x00FFFFFF) | (val << 24); return; + } + } + else if (addr < 0x1000) + { + if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n"); + Mailbox[0]->Write(val); + if (addr == 0xFFF) BMI_Command(); + return; + } + else if (addr < 0x1800) + { + if (Mailbox[1]->IsFull()) printf("!!! NWIFI: MBOX1 FULL\n"); + Mailbox[1]->Write(val); + return; + } + else if (addr < 0x2000) + { + if (Mailbox[2]->IsFull()) printf("!!! NWIFI: MBOX2 FULL\n"); + Mailbox[2]->Write(val); + return; + } + else if (addr < 0x2800) + { + if (Mailbox[3]->IsFull()) printf("!!! NWIFI: MBOX3 FULL\n"); + Mailbox[3]->Write(val); + return; + } + else + { + if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n"); + Mailbox[0]->Write(val); + if (addr == 0x3FFF) BMI_Command(); // CHECKME + return; + } + printf("NWIFI: unknown func1 write %05X %02X\n", addr, val); } @@ -185,6 +323,7 @@ u8 DSi_NWifi::SDIO_Read(u32 func, u32 addr) switch (func) { case 0: return F0_Read(addr); + case 1: return F1_Read(addr); } printf("NWIFI: unknown SDIO read %d %05X\n", func, addr); @@ -196,6 +335,7 @@ void DSi_NWifi::SDIO_Write(u32 func, u32 addr, u8 val) switch (func) { case 0: return F0_Write(addr, val); + case 1: return F1_Write(addr, val); } printf("NWIFI: unknown SDIO write %d %05X %02X\n", func, addr, val); @@ -203,7 +343,7 @@ void DSi_NWifi::SDIO_Write(u32 func, u32 addr, u8 val) void DSi_NWifi::SendCMD(u8 cmd, u32 param) -{ +{printf("NWIFI CMD %d %08X %08X\n", cmd, param, NDS::GetPC(1)); switch (cmd) { case 52: // IO_RW_DIRECT @@ -315,24 +455,62 @@ void DSi_NWifi::WriteBlock() u32 len = (TransferCmd & (1<<27)) ? 0x200 : RemSize; u8 data[0x200]; - Host->ReceiveData(data, len); - - for (u32 i = 0; i < len; i++) + if (Host->ReceiveData(data, len)) { - SDIO_Write(func, TransferAddr, data[i]); - if (TransferCmd & (1<<26)) + for (u32 i = 0; i < len; i++) { - TransferAddr++; - TransferAddr &= 0x1FFFF; // checkme + SDIO_Write(func, TransferAddr, data[i]); + if (TransferCmd & (1<<26)) + { + TransferAddr++; + TransferAddr &= 0x1FFFF; // checkme + } } - } - if (RemSize > 0) - { - RemSize -= len; - if (RemSize == 0) + if (RemSize > 0) { - // TODO? + RemSize -= len; + if (RemSize == 0) + { + // TODO? + } } } } + + +void DSi_NWifi::BMI_Command() +{ + // HLE command handling stub + u32 cmd = MB_Read32(0); + printf("BMI: cmd %08X\n", cmd); + + switch (cmd) + { + case 0x08: // BMI_GET_TARGET_ID + MB_Write32(4, 0xFFFFFFFF); + MB_Write32(4, 0x0000000C); + MB_Write32(4, 0x20000118); + MB_Write32(4, 0x00000002); + return; + } +} + + +void DSi_NWifi::WindowRead() +{ + printf("NWifi: window read %08X\n", WindowReadAddr); + + switch (WindowReadAddr) + { + case 0x40EC: WindowData = 0x02000001; return; + + // SOC_RESET_CAUSE + case 0x40C0: WindowData = 2; return; + } +} + +void DSi_NWifi::WindowWrite() +{ + printf("NWifi: window write %08X %08X\n", WindowWriteAddr, WindowData); +} diff --git a/src/DSi_NWifi.h b/src/DSi_NWifi.h index 5d61951..4ec010e 100644 --- a/src/DSi_NWifi.h +++ b/src/DSi_NWifi.h @@ -20,6 +20,7 @@ #define DSI_NWIFI_H #include "DSi_SD.h" +#include "FIFO.h" class DSi_NWifi : public DSi_SDDevice { @@ -48,6 +49,32 @@ private: void ReadBlock(); void WriteBlock(); + + void BMI_Command(); + + void WindowRead(); + void WindowWrite(); + + u32 MB_Read32(int n) + { + u32 ret = Mailbox[n]->Read(); + ret |= (Mailbox[n]->Read() << 8); + ret |= (Mailbox[n]->Read() << 16); + ret |= (Mailbox[n]->Read() << 24); + return ret; + } + + void MB_Write32(int n, u32 val) + { + Mailbox[n]->Write(val & 0xFF); val >>= 8; + Mailbox[n]->Write(val & 0xFF); val >>= 8; + Mailbox[n]->Write(val & 0xFF); val >>= 8; + Mailbox[n]->Write(val & 0xFF); + } + + FIFO* Mailbox[8]; + + u32 WindowData, WindowReadAddr, WindowWriteAddr; }; #endif // DSI_NWIFI_H diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index 6e73df5..c9edd78 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -185,7 +185,8 @@ void DSi_SDHost::SendData(u8* data, u32 len) // but if IRQ24 is thrown instantly, the handler clears IRQ0 before the // send-command function starts polling IRQ status u32 param = Num | (last << 1); - NDS::ScheduleEvent(NDS::Event_DSi_SDTransfer, false, 512, FinishSend, param); + NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, + false, 512, FinishSend, param); } void DSi_SDHost::FinishReceive(u32 param) @@ -199,13 +200,19 @@ void DSi_SDHost::FinishReceive(u32 param) if (dev) dev->ContinueTransfer(); } -void DSi_SDHost::ReceiveData(u8* data, u32 len) +bool DSi_SDHost::ReceiveData(u8* data, u32 len) { printf("%s: data TX, len=%d, blkcnt=%d (%d) blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockCountInternal, BlockLen16, IRQMask); if (len != BlockLen16) printf("!! BAD BLOCKLEN\n"); - DSi_SDDevice* dev = Ports[PortSelect & 0x1]; u32 f = CurFIFO; + if ((DataFIFO[f]->Level() << 1) < len) + { + printf("%s: FIFO not full enough for a transfer (%d / %d)\n", SD_DESC, DataFIFO[f]->Level()<<1, len); + return false; + } + + DSi_SDDevice* dev = Ports[PortSelect & 0x1]; for (u32 i = 0; i < len; i += 2) *(u16*)&data[i] = DataFIFO[f]->Read(); @@ -213,7 +220,7 @@ void DSi_SDHost::ReceiveData(u8* data, u32 len) if (BlockCountInternal <= 1) { - printf("%s: data32 TX complete", SD_DESC); + printf("%s: data TX complete", SD_DESC); if (StopAction & (1<<8)) { @@ -232,12 +239,14 @@ void DSi_SDHost::ReceiveData(u8* data, u32 len) { BlockCountInternal--; } + + return true; } u16 DSi_SDHost::Read(u32 addr) { - //printf("SDMMC READ %08X %08X\n", addr, NDS::GetPC(1)); + //if(Num)printf("SDIO READ %08X %08X\n", addr, NDS::GetPC(1)); switch (addr & 0x1FF) { @@ -383,7 +392,7 @@ u32 DSi_SDHost::ReadFIFO32() void DSi_SDHost::Write(u32 addr, u16 val) { - //printf("SDMMC WRITE %08X %04X %08X\n", addr, val, NDS::GetPC(1)); + //if(Num)printf("SDIO WRITE %08X %04X %08X\n", addr, val, NDS::GetPC(1)); switch (addr & 0x1FF) { @@ -421,7 +430,11 @@ void DSi_SDHost::Write(u32 addr, u16 val) case 0x01C: IRQStatus &= (val | 0xFFFF0000); return; case 0x01E: IRQStatus &= ((val << 16) | 0xFFFF); return; case 0x020: IRQMask = (IRQMask & 0x8B7F0000) | (val & 0x031D); return; - case 0x022: IRQMask = (IRQMask & 0x0000031D) | ((val & 0x8B7F) << 16); return; + case 0x022: + IRQMask = (IRQMask & 0x0000031D) | ((val & 0x8B7F) << 16); + if (!DataFIFO[CurFIFO]->IsEmpty()) SetIRQ(24); // checkme + if (DataFIFO[CurFIFO]->IsEmpty()) SetIRQ(25); // checkme + return; case 0x024: SDClock = val & 0x03FF; return; case 0x026: @@ -430,6 +443,33 @@ void DSi_SDHost::Write(u32 addr, u16 val) return; case 0x028: SDOption = val & 0xC1FF; return; + case 0x030: // FIFO16 + { + DSi_SDDevice* dev = Ports[PortSelect & 0x1]; + u32 f = CurFIFO; + if (DataFIFO[f]->IsFull()) + { + // TODO + printf("!!!! %s FIFO FULL\n", SD_DESC); + return; + } + + DataFIFO[f]->Write(val); + + if (DataFIFO[f]->Level() < (BlockLen16>>1)) + { + ClearIRQ(25); + SetIRQ(24); + return; + } + + // we completed one block, send it to the SD card + // TODO measure the actual delay!! + NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, + false, 2048, FinishReceive, Num); + } + return; + case 0x0D8: DataCtl = (val & 0x0022); DataMode = ((DataCtl >> 1) & 0x1) & ((Data32IRQ >> 1) & 0x1); @@ -494,13 +534,9 @@ void DSi_SDHost::WriteFIFO32(u32 val) } // we completed one block, send it to the SD card - - //ClearIRQ(24); - //SetIRQ(25); - - //if (dev) dev->ContinueTransfer(); // TODO measure the actual delay!! - NDS::ScheduleEvent(NDS::Event_DSi_SDTransfer, false, 2048, FinishReceive, Num); + NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, + false, 2048, FinishReceive, Num); } @@ -726,7 +762,9 @@ void DSi_MMCStorage::WriteBlock(u64 addr) printf("SD/MMC: write block @ %08X, len=%08X\n", addr, BlockSize); u8 data[0x200]; - Host->ReceiveData(data, BlockSize); - fseek(File, addr, SEEK_SET); - fwrite(data, 1, BlockSize, File); + if (Host->ReceiveData(data, BlockSize)) + { + fseek(File, addr, SEEK_SET); + fwrite(data, 1, BlockSize, File); + } } diff --git a/src/DSi_SD.h b/src/DSi_SD.h index 855dd5e..22475d6 100644 --- a/src/DSi_SD.h +++ b/src/DSi_SD.h @@ -40,7 +40,7 @@ public: static void FinishReceive(u32 param); void SendResponse(u32 val, bool last); void SendData(u8* data, u32 len); - void ReceiveData(u8* data, u32 len); + bool ReceiveData(u8* data, u32 len); u16 Read(u32 addr); void Write(u32 addr, u16 val); diff --git a/src/NDS.h b/src/NDS.h index 850e829..e32908b 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -43,7 +43,8 @@ enum Event_Sqrt, // DSi - Event_DSi_SDTransfer, + Event_DSi_SDMMCTransfer, + Event_DSi_SDIOTransfer, Event_MAX }; -- cgit v1.2.3 From f7f4ff0519309669e78b994e7c759d13808f0a87 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 4 Aug 2019 02:16:16 +0200 Subject: wifi: take this shit further. complete wifi init --- src/DSi.cpp | 20 ++-- src/DSi_NWifi.cpp | 328 +++++++++++++++++++++++++++++++++++++++++++++++++++--- src/DSi_NWifi.h | 41 +++++++ src/DSi_SD.cpp | 105 +++++++++++++---- src/DSi_SD.h | 19 +++- src/FIFO.h | 9 ++ src/NDS.h | 1 + src/SPI.cpp | 1 + src/SPI.h | 1 + 9 files changed, 468 insertions(+), 57 deletions(-) (limited to 'src/NDS.h') diff --git a/src/DSi.cpp b/src/DSi.cpp index aed6b89..17d7f0d 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -582,7 +582,7 @@ void MapNWRAMRange(u32 cpu, u32 num, u32 val) u8 ARM9Read8(u32 addr) -{if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 8 9 %08X %08X\n", addr, NDS::GetPC(0)); +{ switch (addr & 0xFF000000) { case 0x03000000: @@ -611,7 +611,7 @@ u8 ARM9Read8(u32 addr) } u16 ARM9Read16(u32 addr) -{if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 16 9 %08X %08X\n", addr, NDS::GetPC(0)); +{ switch (addr & 0xFF000000) { case 0x03000000: @@ -640,8 +640,7 @@ u16 ARM9Read16(u32 addr) } u32 ARM9Read32(u32 addr) -{if(addr==0x029D02D8) printf("READ SHITTY VTABLE: %08X\n", NDS::GetPC(0)); -if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 32 9 %08X %08X\n", addr, NDS::GetPC(0)); +{ switch (addr & 0xFF000000) { case 0x03000000: @@ -736,7 +735,7 @@ void ARM9Write16(u32 addr, u16 val) } void ARM9Write32(u32 addr, u32 val) -{if(addr==0x02B05E34) printf("VGONP. %08X, %08X\n", val, NDS::GetPC(0)); +{ switch (addr & 0xFF000000) { case 0x03000000: @@ -792,8 +791,7 @@ bool ARM9GetMemRegion(u32 addr, bool write, NDS::MemRegion* region) u8 ARM7Read8(u32 addr) -{if(addr>=0x3FFC400 && addr<0x3FFE728) printf("OGON 8 %08X %08X\n", addr, NDS::GetPC(1)); -if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 8 7 %08X %08X\n", addr, NDS::GetPC(1)); +{ switch (addr & 0xFF800000) { case 0x03000000: @@ -822,8 +820,7 @@ if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 8 7 %08X %08X\n", addr, } u16 ARM7Read16(u32 addr) -{if(addr>=0x3FFC400 && addr<0x3FFE728) printf("OGON 16 %08X %08X\n", addr, NDS::GetPC(1)); -if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 16 7 %08X %08X\n", addr, NDS::GetPC(1)); +{ switch (addr & 0xFF800000) { case 0x03000000: @@ -852,8 +849,7 @@ if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 16 7 %08X %08X\n", addr, } u32 ARM7Read32(u32 addr) -{if(addr>=0x3FFC400 && addr<0x3FFE728) printf("OGON 32 %08X %08X\n", addr, NDS::GetPC(1)); -if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 32 7 %08X %08X\n", addr, NDS::GetPC(1)); +{ switch (addr & 0xFF800000) { case 0x03000000: @@ -882,7 +878,7 @@ if (addr>=0x2FFD7BC && addr<0x2FFD800) printf("EMMCGONP 32 7 %08X %08X\n", addr, } void ARM7Write8(u32 addr, u8 val) -{if(addr==0x0228CD74) printf("RAKAKA %02X %08X\n", val, NDS::GetPC(1)); +{ switch (addr & 0xFF800000) { case 0x03000000: diff --git a/src/DSi_NWifi.cpp b/src/DSi_NWifi.cpp index 6f23740..013173f 100644 --- a/src/DSi_NWifi.cpp +++ b/src/DSi_NWifi.cpp @@ -20,6 +20,7 @@ #include #include "DSi.h" #include "DSi_NWifi.h" +#include "SPI.h" const u8 CIS0[256] = @@ -110,11 +111,25 @@ const u8 CIS1[256] = }; +// hax +DSi_NWifi* hax_wifi; +void triggerirq(u32 param) +{ + hax_wifi->SetIRQ_F1_Counter(0); +} + + DSi_NWifi::DSi_NWifi(DSi_SDHost* host) : DSi_SDDevice(host) { TransferCmd = 0xFFFFFFFF; RemSize = 0; + F0_IRQEnable = 0; + F0_IRQStatus = 0; + + F1_IRQEnable = 0; F1_IRQEnable_CPU = 0; F1_IRQEnable_Error = 0; F1_IRQEnable_Counter = 0; + F1_IRQStatus = 0; F1_IRQStatus_CPU = 0; F1_IRQStatus_Error = 0; F1_IRQStatus_Counter = 0; + WindowData = 0; WindowReadAddr = 0; WindowWriteAddr = 0; @@ -122,6 +137,30 @@ DSi_NWifi::DSi_NWifi(DSi_SDHost* host) : DSi_SDDevice(host) // TODO: check the actual mailbox size (presumably 0x200) for (int i = 0; i < 8; i++) Mailbox[i] = new FIFO(0x200); + + u8* mac = SPI_Firmware::GetWifiMAC(); + printf("NWifi MAC: %02X:%02X:%02X:%02X:%02X:%02X\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + memset(EEPROM, 0, 0x400); + + *(u32*)&EEPROM[0x000] = 0x300; + *(u16*)&EEPROM[0x008] = 0x8348; // TODO: determine properly (country code) + memcpy(&EEPROM[0x00A], mac, 6); + *(u32*)&EEPROM[0x010] = 0x60000000; + + memset(&EEPROM[0x03C], 0xFF, 0x70); + memset(&EEPROM[0x140], 0xFF, 0x8); + + u16 chk = 0xFFFF; + for (int i = 0; i < 0x300; i+=2) + chk ^= *(u16*)&EEPROM[i]; + + *(u16*)&EEPROM[0x004] = chk; + + EEPROMReady = 0; + + BootPhase = 0; } DSi_NWifi::~DSi_NWifi() @@ -131,6 +170,61 @@ DSi_NWifi::~DSi_NWifi() } +// CHECKME +// can IRQ status bits be set when the corresponding IRQs are disabled in the enable register? +// otherwise, does disabling them clear the status register? + +void DSi_NWifi::UpdateIRQ() +{ + F0_IRQStatus = 0; + IRQ = false; + + if (F1_IRQStatus & F1_IRQEnable) + F0_IRQStatus |= (1<<1); + + if (F0_IRQEnable & (1<<0)) + { + if (F0_IRQStatus & F0_IRQEnable) + IRQ = true; + } + + Host->SetCardIRQ(); +} + +void DSi_NWifi::UpdateIRQ_F1() +{ + F1_IRQStatus = 0; + + if (!Mailbox[4]->IsEmpty()) F1_IRQStatus |= (1<<0); + if (!Mailbox[5]->IsEmpty()) F1_IRQStatus |= (1<<1); + if (!Mailbox[6]->IsEmpty()) F1_IRQStatus |= (1<<2); + if (!Mailbox[7]->IsEmpty()) F1_IRQStatus |= (1<<3); + if (F1_IRQStatus_Counter & F1_IRQEnable_Counter) F1_IRQStatus |= (1<<4); + if (F1_IRQStatus_CPU & F1_IRQEnable_CPU) F1_IRQStatus |= (1<<6); + if (F1_IRQStatus_Error & F1_IRQEnable_Error) F1_IRQStatus |= (1<<7); + + UpdateIRQ(); +} + +void DSi_NWifi::SetIRQ_F1_Counter(u32 n) +{ + F1_IRQStatus_Counter |= (1<Read(); + u8 ret = Mailbox[4]->Read(); + UpdateIRQ_F1(); + return ret; } else if (addr < 0x200) { - return Mailbox[5]->Read(); + u8 ret = Mailbox[5]->Read(); + UpdateIRQ_F1(); + return ret; } else if (addr < 0x300) { - return Mailbox[6]->Read(); + u8 ret = Mailbox[6]->Read(); + UpdateIRQ_F1(); + return ret; } else if (addr < 0x400) { - return Mailbox[7]->Read(); + u8 ret = Mailbox[7]->Read(); + UpdateIRQ_F1(); + return ret; } else if (addr < 0x800) { switch (addr) { + case 0x00400: return F1_IRQStatus; + case 0x00401: return F1_IRQStatus_CPU; + case 0x00402: return F1_IRQStatus_Error; + case 0x00403: return F1_IRQStatus_Counter; + + case 0x00405: + { + u8 ret = 0; + + if (Mailbox[4]->Level() >= 4) ret |= (1<<0); + if (Mailbox[5]->Level() >= 4) ret |= (1<<1); + if (Mailbox[6]->Level() >= 4) ret |= (1<<2); + if (Mailbox[7]->Level() >= 4) ret |= (1<<3); + + return ret; + } + + case 0x00408: return Mailbox[4]->Peek(0); + case 0x00409: return Mailbox[4]->Peek(1); + case 0x0040A: return Mailbox[4]->Peek(2); + case 0x0040B: return Mailbox[4]->Peek(3); + + case 0x00418: return F1_IRQEnable; + case 0x00419: return F1_IRQEnable_CPU; + case 0x0041A: return F1_IRQEnable_Error; + case 0x0041B: return F1_IRQEnable_Counter; + + // GROSS FUCKING HACK + case 0x00440: ClearIRQ_F1_Counter(0); return 0; case 0x00450: return 1; // HAX!! case 0x00474: return WindowData & 0xFF; @@ -205,23 +347,33 @@ u8 DSi_NWifi::F1_Read(u32 addr) } else if (addr < 0x1000) { - return Mailbox[4]->Read(); + u8 ret = Mailbox[4]->Read(); + UpdateIRQ_F1(); + return ret; } else if (addr < 0x1800) { - return Mailbox[5]->Read(); + u8 ret = Mailbox[5]->Read(); + UpdateIRQ_F1(); + return ret; } else if (addr < 0x2000) { - return Mailbox[6]->Read(); + u8 ret = Mailbox[6]->Read(); + UpdateIRQ_F1(); + return ret; } else if (addr < 0x2800) { - return Mailbox[7]->Read(); + u8 ret = Mailbox[7]->Read(); + UpdateIRQ_F1(); + return ret; } else { - return Mailbox[4]->Read(); + u8 ret = Mailbox[4]->Read(); + UpdateIRQ_F1(); + return ret; } printf("NWIFI: unknown func1 read %05X\n", addr); @@ -229,36 +381,48 @@ u8 DSi_NWifi::F1_Read(u32 addr) } void DSi_NWifi::F1_Write(u32 addr, u8 val) -{printf("F1 WRITE %05X %02X\n", addr, val); +{ if (addr < 0x100) { if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n"); Mailbox[0]->Write(val); - if (addr == 0xFF) BMI_Command(); + if (addr == 0xFF) HandleCommand(); + UpdateIRQ_F1(); return; } else if (addr < 0x200) { if (Mailbox[1]->IsFull()) printf("!!! NWIFI: MBOX1 FULL\n"); Mailbox[1]->Write(val); + UpdateIRQ_F1(); return; } else if (addr < 0x300) { if (Mailbox[2]->IsFull()) printf("!!! NWIFI: MBOX2 FULL\n"); Mailbox[2]->Write(val); + UpdateIRQ_F1(); return; } else if (addr < 0x400) { if (Mailbox[3]->IsFull()) printf("!!! NWIFI: MBOX3 FULL\n"); Mailbox[3]->Write(val); + UpdateIRQ_F1(); return; } else if (addr < 0x800) { switch (addr) { + case 0x00418: F1_IRQEnable = val; UpdateIRQ_F1(); return; + case 0x00419: F1_IRQEnable_CPU = val; UpdateIRQ_F1(); return; + case 0x0041A: F1_IRQEnable_Error = val; UpdateIRQ_F1(); return; + case 0x0041B: F1_IRQEnable_Counter = val; UpdateIRQ_F1(); return; + + // GROSS FUCKING HACK + case 0x00440: ClearIRQ_F1_Counter(0); return; + case 0x00474: WindowData = (WindowData & 0xFFFFFF00) | val; return; case 0x00475: WindowData = (WindowData & 0xFFFF00FF) | (val << 8); return; case 0x00476: WindowData = (WindowData & 0xFF00FFFF) | (val << 16); return; @@ -285,32 +449,37 @@ void DSi_NWifi::F1_Write(u32 addr, u8 val) { if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n"); Mailbox[0]->Write(val); - if (addr == 0xFFF) BMI_Command(); + if (addr == 0xFFF) HandleCommand(); + UpdateIRQ_F1(); return; } else if (addr < 0x1800) { if (Mailbox[1]->IsFull()) printf("!!! NWIFI: MBOX1 FULL\n"); Mailbox[1]->Write(val); + UpdateIRQ_F1(); return; } else if (addr < 0x2000) { if (Mailbox[2]->IsFull()) printf("!!! NWIFI: MBOX2 FULL\n"); Mailbox[2]->Write(val); + UpdateIRQ_F1(); return; } else if (addr < 0x2800) { if (Mailbox[3]->IsFull()) printf("!!! NWIFI: MBOX3 FULL\n"); Mailbox[3]->Write(val); + UpdateIRQ_F1(); return; } else { if (Mailbox[0]->IsFull()) printf("!!! NWIFI: MBOX0 FULL\n"); Mailbox[0]->Write(val); - if (addr == 0x3FFF) BMI_Command(); // CHECKME + if (addr == 0x3FFF) HandleCommand(); // CHECKME + UpdateIRQ_F1(); return; } @@ -343,7 +512,7 @@ void DSi_NWifi::SDIO_Write(u32 func, u32 addr, u8 val) void DSi_NWifi::SendCMD(u8 cmd, u32 param) -{printf("NWIFI CMD %d %08X %08X\n", cmd, param, NDS::GetPC(1)); +{ switch (cmd) { case 52: // IO_RW_DIRECT @@ -426,6 +595,8 @@ void DSi_NWifi::ReadBlock() u32 func = (TransferCmd >> 28) & 0x7; u32 len = (TransferCmd & (1<<27)) ? 0x200 : RemSize; + len = Host->GetTransferrableLen(len); + u8 data[0x200]; for (u32 i = 0; i < len; i++) @@ -437,7 +608,7 @@ void DSi_NWifi::ReadBlock() TransferAddr &= 0x1FFFF; // checkme } } - Host->SendData(data, len); + len = Host->SendData(data, len); if (RemSize > 0) { @@ -454,8 +625,10 @@ void DSi_NWifi::WriteBlock() u32 func = (TransferCmd >> 28) & 0x7; u32 len = (TransferCmd & (1<<27)) ? 0x200 : RemSize; + len = Host->GetTransferrableLen(len); + u8 data[0x200]; - if (Host->ReceiveData(data, len)) + if (len = Host->ReceiveData(data, len)) { for (u32 i = 0; i < len; i++) { @@ -479,14 +652,32 @@ void DSi_NWifi::WriteBlock() } +void DSi_NWifi::HandleCommand() +{ + switch (BootPhase) + { + case 0: return BMI_Command(); + case 1: return WMI_Command(); + } +} + void DSi_NWifi::BMI_Command() { // HLE command handling stub u32 cmd = MB_Read32(0); - printf("BMI: cmd %08X\n", cmd); switch (cmd) { + case 0x01: // BMI_DONE + { + printf("BMI_DONE\n"); + EEPROMReady = 1; // GROSS FUCKING HACK + u8 ready_msg[8] = {0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00}; + SendWMIFrame(ready_msg, 8, 0, 0x00, 0x0000); + BootPhase = 1; + } + return; + case 0x03: // BMI_WRITE_MEMORY { u32 addr = MB_Read32(0); @@ -546,16 +737,94 @@ void DSi_NWifi::BMI_Command() { u32 len = MB_Read32(0); printf("BMI LZ write %08X\n", len); + //FILE* f = fopen("wififirm.bin", "ab"); for (int i = 0; i < len; i++) { u8 val = Mailbox[0]->Read(); // TODO: do something with it!! + //fwrite(&val, 1, 1, f); } + //fclose(f); } return; + + default: + printf("unknown BMI command %08X\n", cmd); + return; + } +} + +void DSi_NWifi::WMI_Command() +{ + // HLE command handling stub + u16 h0 = MB_Read16(0); + u16 len = MB_Read16(0); + u16 h2 = MB_Read16(0); + + u16 cmd = MB_Read16(0); + printf("WMI: cmd %04X\n", cmd); + + switch (cmd) + { + case 0x0002: // service connect + { + u16 svc_id = MB_Read16(0); + u16 conn_flags = MB_Read16(0); + + u8 svc_resp[10]; + *(u16*)&svc_resp[0] = 0x0003; + *(u16*)&svc_resp[2] = svc_id; + svc_resp[4] = 0; + svc_resp[5] = (svc_id & 0xFF) + 1; + *(u16*)&svc_resp[6] = 0x0001; + *(u16*)&svc_resp[8] = 0x0001; + SendWMIFrame(svc_resp, 10, 0, 0x00, 0x0000); + } + break; + + case 0x0004: // setup complete + { + u8 ready_evt[14]; + memset(ready_evt, 0, 14); + *(u16*)&ready_evt[0] = 0x1001; + memcpy(&ready_evt[2], SPI_Firmware::GetWifiMAC(), 6); + ready_evt[8] = 0x02; + *(u32*)&ready_evt[10] = 0x23000024; + // ctrl[0] = trailer size + // trailer[1] = trailer extra size + // trailer[0] = trailer type??? + SendWMIFrame(ready_evt, 14, 1, 0x00, 0x0000); + } + break; + + default: + printf("unknown WMI command %04X\n", cmd); + break; + } + + MB_Drain(0); +} + +void DSi_NWifi::SendWMIFrame(u8* data, u32 len, u8 ep, u8 flags, u16 ctrl) +{ + u32 wlen = 0; + + Mailbox[4]->Write(ep); // eid + Mailbox[4]->Write(flags); // flags + MB_Write16(4, len); // payload length + MB_Write16(4, ctrl); // ctrl + wlen += 6; + + for (int i = 0; i < len; i++) + { + Mailbox[4]->Write(data[i]); + wlen++; } + + for (; wlen & 0x7F; wlen++) + Mailbox[4]->Write(0); } @@ -563,6 +832,29 @@ u32 DSi_NWifi::WindowRead(u32 addr) { printf("NWifi: window read %08X\n", addr); + if ((addr & 0xFFFF00) == 0x520000) + { + // RAM host interest area + // TODO: different base based on hardware version + + switch (addr & 0xFF) + { + case 0x54: + // base address of EEPROM data + // TODO find what the actual address is! + return 0x1FFC00; + case 0x58: return EEPROMReady; // hax + } + + return 0; + } + + // hax + if ((addr & 0x1FFC00) == 0x1FFC00) + { + return *(u32*)&EEPROM[addr & 0x3FF]; + } + switch (addr) { case 0x40EC: // chip ID diff --git a/src/DSi_NWifi.h b/src/DSi_NWifi.h index 0a36705..e5fe637 100644 --- a/src/DSi_NWifi.h +++ b/src/DSi_NWifi.h @@ -33,11 +33,19 @@ public: void ContinueTransfer(); + void SetIRQ_F1_Counter(u32 n); + private: u32 TransferCmd; u32 TransferAddr; u32 RemSize; + void UpdateIRQ(); + void UpdateIRQ_F1(); + //void SetIRQ_F1_Counter(u32 n); + void ClearIRQ_F1_Counter(u32 n); + void SetIRQ_F1_CPU(u32 n); + u8 F0_Read(u32 addr); void F0_Write(u32 addr, u8 val); @@ -50,11 +58,28 @@ private: void ReadBlock(); void WriteBlock(); + void HandleCommand(); void BMI_Command(); + void WMI_Command(); + + void SendWMIFrame(u8* data, u32 len, u8 ep, u8 flags, u16 ctrl); u32 WindowRead(u32 addr); void WindowWrite(u32 addr, u32 val); + u16 MB_Read16(int n) + { + u16 ret = Mailbox[n]->Read(); + ret |= (Mailbox[n]->Read() << 8); + return ret; + } + + void MB_Write16(int n, u16 val) + { + Mailbox[n]->Write(val & 0xFF); val >>= 8; + Mailbox[n]->Write(val & 0xFF); + } + u32 MB_Read32(int n) { u32 ret = Mailbox[n]->Read(); @@ -72,9 +97,25 @@ private: Mailbox[n]->Write(val & 0xFF); } + void MB_Drain(int n) + { + while (!Mailbox[n]->IsEmpty()) Mailbox[n]->Read(); + } + FIFO* Mailbox[8]; + u8 F0_IRQEnable; + u8 F0_IRQStatus; + + u8 F1_IRQEnable, F1_IRQEnable_CPU, F1_IRQEnable_Error, F1_IRQEnable_Counter; + u8 F1_IRQStatus, F1_IRQStatus_CPU, F1_IRQStatus_Error, F1_IRQStatus_Counter; + u32 WindowData, WindowReadAddr, WindowWriteAddr; + + u8 EEPROM[0x400]; + u32 EEPROMReady; + + u32 BootPhase; }; #endif // DSI_NWIFI_H diff --git a/src/DSi_SD.cpp b/src/DSi_SD.cpp index c9edd78..07eca83 100644 --- a/src/DSi_SD.cpp +++ b/src/DSi_SD.cpp @@ -73,6 +73,10 @@ void DSi_SDHost::Reset() IRQStatus = 0; IRQMask = 0x8B7F031D; + CardIRQStatus = 0; + CardIRQMask = 0xC007; + CardIRQCtl = 0; + DataCtl = 0; Data32IRQ = 0; DataMode = 0; @@ -145,6 +149,25 @@ void DSi_SDHost::SetIRQ(u32 irq) if (irq == 24 || irq == 25) UpdateData32IRQ(); } +void DSi_SDHost::SetCardIRQ() +{ + if (!(CardIRQCtl & (1<<0))) return; + + u16 oldflags = CardIRQStatus & ~CardIRQMask; + DSi_SDDevice* dev = Ports[PortSelect & 0x1]; + + if (dev->IRQ) CardIRQStatus |= (1<<0); + else CardIRQStatus &= ~(1<<0); + + u16 newflags = CardIRQStatus & ~CardIRQMask; + + if ((oldflags == 0) && (newflags != 0)) // checkme + { + NDS::SetIRQ2(Num ? NDS::IRQ2_DSi_SDIO : NDS::IRQ2_DSi_SDMMC); + NDS::SetIRQ2(Num ? NDS::IRQ2_DSi_SDIO_Data1 : NDS::IRQ2_DSi_SD_Data1); + } +} + void DSi_SDHost::SendResponse(u32 val, bool last) { *(u32*)&ResponseBuffer[6] = *(u32*)&ResponseBuffer[4]; @@ -166,10 +189,10 @@ void DSi_SDHost::FinishSend(u32 param) //if (param & 0x2) host->SetIRQ(2); } -void DSi_SDHost::SendData(u8* data, u32 len) +u32 DSi_SDHost::SendData(u8* data, u32 len) { printf("%s: data RX, len=%d, blkcnt=%d (%d) blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockCountInternal, BlockLen16, IRQMask); - if (len != BlockLen16) printf("!! BAD BLOCKLEN\n"); + if (len != BlockLen16) { printf("!! BAD BLOCKLEN\n"); len = BlockLen16; } bool last = (BlockCountInternal == 0); @@ -187,6 +210,8 @@ void DSi_SDHost::SendData(u8* data, u32 len) u32 param = Num | (last << 1); NDS::ScheduleEvent(Num ? NDS::Event_DSi_SDIOTransfer : NDS::Event_DSi_SDMMCTransfer, false, 512, FinishSend, param); + + return len; } void DSi_SDHost::FinishReceive(u32 param) @@ -200,16 +225,16 @@ void DSi_SDHost::FinishReceive(u32 param) if (dev) dev->ContinueTransfer(); } -bool DSi_SDHost::ReceiveData(u8* data, u32 len) +u32 DSi_SDHost::ReceiveData(u8* data, u32 len) { printf("%s: data TX, len=%d, blkcnt=%d (%d) blklen=%d, irq=%08X\n", SD_DESC, len, BlockCount16, BlockCountInternal, BlockLen16, IRQMask); - if (len != BlockLen16) printf("!! BAD BLOCKLEN\n"); + if (len != BlockLen16) { printf("!! BAD BLOCKLEN\n"); len = BlockLen16; } u32 f = CurFIFO; if ((DataFIFO[f]->Level() << 1) < len) { printf("%s: FIFO not full enough for a transfer (%d / %d)\n", SD_DESC, DataFIFO[f]->Level()<<1, len); - return false; + return 0; } DSi_SDDevice* dev = Ports[PortSelect & 0x1]; @@ -240,7 +265,13 @@ bool DSi_SDHost::ReceiveData(u8* data, u32 len) BlockCountInternal--; } - return true; + return len; +} + +u32 DSi_SDHost::GetTransferrableLen(u32 len) +{ + if (len > BlockLen16) len = BlockLen16; // checkme + return len; } @@ -278,6 +309,10 @@ u16 DSi_SDHost::Read(u32 addr) case 0x02C: return 0; // TODO + case 0x034: return CardIRQCtl; + case 0x036: return CardIRQStatus; + case 0x038: return CardIRQMask; + case 0x030: // FIFO16 { // TODO: decrement BlockLen???? @@ -389,7 +424,7 @@ u32 DSi_SDHost::ReadFIFO32() return ret; } - +int morp = 0; void DSi_SDHost::Write(u32 addr, u16 val) { //if(Num)printf("SDIO WRITE %08X %04X %08X\n", addr, val, NDS::GetPC(1)); @@ -470,6 +505,20 @@ void DSi_SDHost::Write(u32 addr, u16 val) } return; + case 0x034: + CardIRQCtl = val & 0x0305; + printf("[%d] CardIRQCtl = %04X\n", Num, val); + SetCardIRQ(); + return; + case 0x036: + CardIRQStatus &= val; + return; + case 0x038: + CardIRQMask = val & 0xC007; + printf("[%d] CardIRQMask = %04X\n", Num, val); + SetCardIRQ(); + return; + case 0x0D8: DataCtl = (val & 0x0022); DataMode = ((DataCtl >> 1) & 0x1) & ((Data32IRQ >> 1) & 0x1); @@ -729,42 +778,54 @@ void DSi_MMCStorage::ContinueTransfer() { if (RWCommand == 0) return; + u32 len = 0; + switch (RWCommand) { case 18: - ReadBlock(RWAddress); + len = ReadBlock(RWAddress); break; case 25: - WriteBlock(RWAddress); + len = WriteBlock(RWAddress); break; } - RWAddress += BlockSize; + RWAddress += len; } -void DSi_MMCStorage::ReadBlock(u64 addr) +u32 DSi_MMCStorage::ReadBlock(u64 addr) { - if (!File) return; - printf("SD/MMC: reading block @ %08X, len=%08X\n", addr, BlockSize); + u32 len = BlockSize; + len = Host->GetTransferrableLen(len); + u8 data[0x200]; - fseek(File, addr, SEEK_SET); - fread(data, 1, BlockSize, File); - Host->SendData(data, BlockSize); + if (File) + { + fseek(File, addr, SEEK_SET); + fread(data, 1, len, File); + } + return Host->SendData(data, len); } -void DSi_MMCStorage::WriteBlock(u64 addr) +u32 DSi_MMCStorage::WriteBlock(u64 addr) { - if (!File) return; - printf("SD/MMC: write block @ %08X, len=%08X\n", addr, BlockSize); + u32 len = BlockSize; + len = Host->GetTransferrableLen(len); + u8 data[0x200]; - if (Host->ReceiveData(data, BlockSize)) + if (len = Host->ReceiveData(data, len)) { - fseek(File, addr, SEEK_SET); - fwrite(data, 1, BlockSize, File); + if (File) + { + fseek(File, addr, SEEK_SET); + fwrite(data, 1, len, File); + } } + + return len; } diff --git a/src/DSi_SD.h b/src/DSi_SD.h index 22475d6..149b72a 100644 --- a/src/DSi_SD.h +++ b/src/DSi_SD.h @@ -39,8 +39,11 @@ public: static void FinishSend(u32 param); static void FinishReceive(u32 param); void SendResponse(u32 val, bool last); - void SendData(u8* data, u32 len); - bool ReceiveData(u8* data, u32 len); + u32 SendData(u8* data, u32 len); + u32 ReceiveData(u8* data, u32 len); + u32 GetTransferrableLen(u32 len); + + void SetCardIRQ(); u16 Read(u32 addr); void Write(u32 addr, u16 val); @@ -58,6 +61,10 @@ private: u32 IRQStatus; // IF u32 IRQMask; // ~IE + u16 CardIRQStatus; + u16 CardIRQMask; + u16 CardIRQCtl; + u16 DataCtl; u16 Data32IRQ; u32 DataMode; // 0=16bit 1=32bit @@ -83,12 +90,14 @@ private: class DSi_SDDevice { public: - DSi_SDDevice(DSi_SDHost* host) { Host = host; } + DSi_SDDevice(DSi_SDHost* host) { Host = host; IRQ = false; } ~DSi_SDDevice() {} virtual void SendCMD(u8 cmd, u32 param) = 0; virtual void ContinueTransfer() = 0; + bool IRQ; + protected: DSi_SDHost* Host; }; @@ -127,8 +136,8 @@ private: void SetState(u32 state) { CSR &= ~(0xF << 9); CSR |= (state << 9); } - void ReadBlock(u64 addr); - void WriteBlock(u64 addr); + u32 ReadBlock(u64 addr); + u32 WriteBlock(u64 addr); }; #endif // DSI_SD_H diff --git a/src/FIFO.h b/src/FIFO.h index a9e9ed8..213db7a 100644 --- a/src/FIFO.h +++ b/src/FIFO.h @@ -89,6 +89,15 @@ public: return Entries[ReadPos]; } + T Peek(u32 offset) + { + u32 pos = ReadPos + offset; + if (pos >= NumEntries) + pos -= NumEntries; + + return Entries[pos]; + } + u32 Level() { return NumOccupied; } bool IsEmpty() { return NumOccupied == 0; } bool IsFull() { return NumOccupied >= NumEntries; } diff --git a/src/NDS.h b/src/NDS.h index e32908b..fd94a01 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -45,6 +45,7 @@ enum // DSi Event_DSi_SDMMCTransfer, Event_DSi_SDIOTransfer, + Event_DSi_NWifi, Event_MAX }; diff --git a/src/SPI.cpp b/src/SPI.cpp index 8bee66f..783e638 100644 --- a/src/SPI.cpp +++ b/src/SPI.cpp @@ -225,6 +225,7 @@ void SetupDirectBoot() u8 GetConsoleType() { return Firmware[0x1D]; } u8 GetWifiVersion() { return Firmware[0x2F]; } u8 GetRFVersion() { return Firmware[0x40]; } +u8* GetWifiMAC() { return &Firmware[0x36]; } u8 Read() { diff --git a/src/SPI.h b/src/SPI.h index 21ad9a6..44de876 100644 --- a/src/SPI.h +++ b/src/SPI.h @@ -29,6 +29,7 @@ void SetupDirectBoot(); u8 GetConsoleType(); u8 GetWifiVersion(); u8 GetRFVersion(); +u8* GetWifiMAC(); } -- cgit v1.2.3 From a6a9f74acc2fe1c0645dae7b06816d7fc6a67f81 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 4 Aug 2019 11:44:36 +0200 Subject: lay base for DSi-mode TSC --- melonDS.cbp | 2 + src/DSi_SPI_TSC.cpp | 113 +++++++++++++++++++++++++++++++++++++++++++++++++ src/DSi_SPI_TSC.h | 40 +++++++++++++++++ src/NDS.cpp | 32 ++++++++------ src/NDS.h | 2 - src/SPI.cpp | 14 ++++-- src/libui_sdl/main.cpp | 2 - 7 files changed, 186 insertions(+), 19 deletions(-) create mode 100644 src/DSi_SPI_TSC.cpp create mode 100644 src/DSi_SPI_TSC.h (limited to 'src/NDS.h') diff --git a/melonDS.cbp b/melonDS.cbp index 2fd6ed0..cc5357b 100644 --- a/melonDS.cbp +++ b/melonDS.cbp @@ -114,6 +114,8 @@ + + diff --git a/src/DSi_SPI_TSC.cpp b/src/DSi_SPI_TSC.cpp new file mode 100644 index 0000000..253cef8 --- /dev/null +++ b/src/DSi_SPI_TSC.cpp @@ -0,0 +1,113 @@ +/* + Copyright 2016-2019 Arisotura + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include +#include +#include "DSi.h" +#include "DSi_SPI_TSC.h" + + +namespace DSi_SPI_TSC +{ + +u32 DataPos; +u8 Index; +u8 Mode; +u8 Data; + +u16 TouchX, TouchY; + + +bool Init() +{ + return true; +} + +void DeInit() +{ +} + +void Reset() +{ + DataPos = 0; + + Mode = 0; + Index = 0; + Data = 0; +} + +void DoSavestate(Savestate* file) +{ + /*file->Section("SPTi"); + + file->Var32(&DataPos); + file->Var8(&ControlByte); + file->Var8(&Data); + + file->Var16(&ConvResult);*/ + // TODO!! +} + +void SetTouchCoords(u16 x, u16 y) +{ + TouchX = x; + TouchY = y; + + if (y == 0xFFF) return; + + TouchX <<= 4; + TouchY <<= 4; +} + +void MicInputFrame(s16* data, int samples) +{ + // TODO: forward to DS-mode TSC if needed +} + +u8 Read() +{ + return Data; +} + +void Write(u8 val, u32 hold) +{ +#define READWRITE(var) { if (Index & 0x01) Data = var; else var = val; } +printf("TSC: %02X %d\n", val, hold?1:0); + if (DataPos == 0) + { + Index = val; + } + else + { + if ((Index & 0xFE) == 0) + { + READWRITE(Mode); + } + else + { + printf("DSi_SPI_TSC: unknown IO, mode=%02X, index=%02X (%02X %s)\n", Mode, Index, Index>>1, (Index&1)?"read":"write"); + } + + Index += (1<<1); // increment index + } + + if (hold) DataPos++; + else DataPos = 0; +} + +} diff --git a/src/DSi_SPI_TSC.h b/src/DSi_SPI_TSC.h new file mode 100644 index 0000000..f3ffc32 --- /dev/null +++ b/src/DSi_SPI_TSC.h @@ -0,0 +1,40 @@ +/* + Copyright 2016-2019 Arisotura + + This file is part of melonDS. + + melonDS is free software: you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef DSI_SPI_TSC +#define DSI_SPI_TSC + +namespace DSi_SPI_TSC +{ + +extern u32 DataPos; + +bool Init(); +void DeInit(); +void Reset(); +void DoSavestate(Savestate* file); + +void SetTouchCoords(u16 x, u16 y); +void MicInputFrame(s16* data, int samples); + +u8 Read(); +void Write(u8 val, u32 hold); + +} + +#endif // DSI_SPI_TSC diff --git a/src/NDS.cpp b/src/NDS.cpp index 61cf547..da7f9f9 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -32,6 +32,7 @@ #include "Platform.h" #include "DSi.h" +#include "DSi_SPI_TSC.h" namespace NDS @@ -519,6 +520,7 @@ void Reset() Wifi::Reset(); DSi::Reset(); + KeyInput &= ~(1 << (16+6)); // TODO } void Stop() @@ -932,24 +934,30 @@ void CancelEvent(u32 id) } -void PressKey(u32 key) -{ - KeyInput &= ~(1 << key); -} - -void ReleaseKey(u32 key) -{ - KeyInput |= (1 << key); -} - void TouchScreen(u16 x, u16 y) { - SPI_TSC::SetTouchCoords(x, y); + if (true) // TODO!! + { + DSi_SPI_TSC::SetTouchCoords(x, y); + } + else + { + SPI_TSC::SetTouchCoords(x, y); + KeyInput &= ~(1 << (16+6)); + } } void ReleaseScreen() { - SPI_TSC::SetTouchCoords(0x000, 0xFFF); + if (true) // TODO!! + { + DSi_SPI_TSC::SetTouchCoords(0x000, 0xFFF); + } + else + { + SPI_TSC::SetTouchCoords(0x000, 0xFFF); + KeyInput |= (1 << (16+6)); + } } diff --git a/src/NDS.h b/src/NDS.h index fd94a01..d391cf7 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -180,8 +180,6 @@ void RelocateSave(const char* path, bool write); u32 RunFrame(); -void PressKey(u32 key); -void ReleaseKey(u32 key); void TouchScreen(u16 x, u16 y); void ReleaseScreen(); diff --git a/src/SPI.cpp b/src/SPI.cpp index 783e638..e21ad0c 100644 --- a/src/SPI.cpp +++ b/src/SPI.cpp @@ -22,6 +22,7 @@ #include "Config.h" #include "NDS.h" #include "SPI.h" +#include "DSi_SPI_TSC.h" #include "Platform.h" @@ -590,6 +591,7 @@ bool Init() if (!SPI_Firmware::Init()) return false; if (!SPI_Powerman::Init()) return false; if (!SPI_TSC::Init()) return false; + if (!DSi_SPI_TSC::Init()) return false; return true; } @@ -599,6 +601,7 @@ void DeInit() SPI_Firmware::DeInit(); SPI_Powerman::DeInit(); SPI_TSC::DeInit(); + DSi_SPI_TSC::DeInit(); } void Reset() @@ -608,6 +611,7 @@ void Reset() SPI_Firmware::Reset(); SPI_Powerman::Reset(); SPI_TSC::Reset(); + DSi_SPI_TSC::Reset(); } void DoSavestate(Savestate* file) @@ -620,6 +624,7 @@ void DoSavestate(Savestate* file) SPI_Firmware::DoSavestate(file); SPI_Powerman::DoSavestate(file); SPI_TSC::DoSavestate(file); + DSi_SPI_TSC::DoSavestate(file); } @@ -633,7 +638,8 @@ void WriteCnt(u16 val) { case 0x0000: SPI_Powerman::Hold = 0; break; case 0x0100: SPI_Firmware::Hold = 0; break; - case 0x0200: SPI_TSC::DataPos = 0; break; + //case 0x0200: SPI_TSC::DataPos = 0; break; + case 0x0200: DSi_SPI_TSC::DataPos = 0; break; } } @@ -659,7 +665,8 @@ u8 ReadData() { case 0x0000: return SPI_Powerman::Read(); case 0x0100: return SPI_Firmware::Read(); - case 0x0200: return SPI_TSC::Read(); + //case 0x0200: return SPI_TSC::Read(); + case 0x0200: return DSi_SPI_TSC::Read(); default: return 0; } } @@ -675,7 +682,8 @@ void WriteData(u8 val) { case 0x0000: SPI_Powerman::Write(val, Cnt&(1<<11)); break; case 0x0100: SPI_Firmware::Write(val, Cnt&(1<<11)); break; - case 0x0200: SPI_TSC::Write(val, Cnt&(1<<11)); break; + //case 0x0200: SPI_TSC::Write(val, Cnt&(1<<11)); break; + case 0x0200: DSi_SPI_TSC::Write(val, Cnt&(1<<11)); break; default: printf("SPI to unknown device %04X %02X\n", Cnt, val); break; } diff --git a/src/libui_sdl/main.cpp b/src/libui_sdl/main.cpp index 86949eb..34e838c 100644 --- a/src/libui_sdl/main.cpp +++ b/src/libui_sdl/main.cpp @@ -1088,7 +1088,6 @@ void OnAreaMouseEvent(uiAreaHandler* handler, uiArea* area, uiAreaMouseEvent* ev if (Touching && (evt->Up == 1)) { Touching = false; - NDS::ReleaseKey(16+6); NDS::ReleaseScreen(); } else if (!Touching && (evt->Down == 1) && @@ -1096,7 +1095,6 @@ void OnAreaMouseEvent(uiAreaHandler* handler, uiArea* area, uiAreaMouseEvent* ev (x < (BottomScreenRect.X+BottomScreenRect.Width)) && (y < (BottomScreenRect.Y+BottomScreenRect.Height))) { Touching = true; - NDS::PressKey(16+6); } if (Touching) -- cgit v1.2.3 From a9f36929e05e40abc9e91567443199b07530638f Mon Sep 17 00:00:00 2001 From: Arisotura Date: Sun, 4 Aug 2019 14:34:33 +0200 Subject: TSC: add backwards-compatibility --- src/DSi_SPI_TSC.cpp | 98 ++++++++++++++++++++++++++++++++++++++--------------- src/NDS.cpp | 4 +-- src/NDS.h | 2 ++ src/SPI.h | 3 ++ 4 files changed, 77 insertions(+), 30 deletions(-) (limited to 'src/NDS.h') diff --git a/src/DSi_SPI_TSC.cpp b/src/DSi_SPI_TSC.cpp index 2ec9858..507005b 100644 --- a/src/DSi_SPI_TSC.cpp +++ b/src/DSi_SPI_TSC.cpp @@ -19,6 +19,7 @@ #include #include #include "DSi.h" +#include "SPI.h" #include "DSi_SPI_TSC.h" @@ -27,10 +28,11 @@ namespace DSi_SPI_TSC u32 DataPos; u8 Index; -u8 Mode; +u8 Bank; u8 Data; -u8 Mode3Regs[0x80]; +u8 Bank3Regs[0x80]; +u8 TSCMode; u16 TouchX, TouchY; @@ -48,21 +50,23 @@ void Reset() { DataPos = 0; - Mode = 0; + Bank = 0; Index = 0; Data = 0; - memset(Mode3Regs, 0, 0x80); - Mode3Regs[0x02] = 0x18; - Mode3Regs[0x03] = 0x87; - Mode3Regs[0x04] = 0x22; - Mode3Regs[0x05] = 0x04; - Mode3Regs[0x06] = 0x20; - Mode3Regs[0x09] = 0x40; - Mode3Regs[0x0E] = 0xAD; - Mode3Regs[0x0F] = 0xA0; - Mode3Regs[0x10] = 0x88; - Mode3Regs[0x11] = 0x81; + memset(Bank3Regs, 0, 0x80); + Bank3Regs[0x02] = 0x18; + Bank3Regs[0x03] = 0x87; + Bank3Regs[0x04] = 0x22; + Bank3Regs[0x05] = 0x04; + Bank3Regs[0x06] = 0x20; + Bank3Regs[0x09] = 0x40; + Bank3Regs[0x0E] = 0xAD; + Bank3Regs[0x0F] = 0xA0; + Bank3Regs[0x10] = 0x88; + Bank3Regs[0x11] = 0x81; + + TSCMode = 0x01; // DSi mode } void DoSavestate(Savestate* file) @@ -79,10 +83,17 @@ void DoSavestate(Savestate* file) void SetTouchCoords(u16 x, u16 y) { + if (TSCMode == 0x00) + { + if (y == 0xFFF) NDS::KeyInput |= (1 << (16+6)); + else NDS::KeyInput &= ~(1 << (16+6)); + return SPI_TSC::SetTouchCoords(x, y); + } + TouchX = x; TouchY = y; -printf("touching: %d/%d\n", x, y); - u8 oldpress = Mode3Regs[0x0E] & 0x01; + + u8 oldpress = Bank3Regs[0x0E] & 0x01; if (y == 0xFFF) { @@ -92,8 +103,9 @@ printf("touching: %d/%d\n", x, y); TouchX = 0x7000; TouchY = 0x7000; - Mode3Regs[0x09] = 0x40; - Mode3Regs[0x0E] |= 0x01; + Bank3Regs[0x09] = 0x40; + //Bank3Regs[0x09] &= ~0x80; + Bank3Regs[0x0E] |= 0x01; } else { @@ -102,11 +114,12 @@ printf("touching: %d/%d\n", x, y); TouchX <<= 4; TouchY <<= 4; - Mode3Regs[0x09] = 0x80; - Mode3Regs[0x0E] &= ~0x01; + Bank3Regs[0x09] = 0x80; + //Bank3Regs[0x09] |= 0x80; + Bank3Regs[0x0E] &= ~0x01; } - if (oldpress ^ (Mode3Regs[0x0E] & 0x01)) + if (oldpress ^ (Bank3Regs[0x0E] & 0x01)) { TouchX |= 0x8000; TouchY |= 0x8000; @@ -115,16 +128,23 @@ printf("touching: %d/%d\n", x, y); void MicInputFrame(s16* data, int samples) { - // TODO: forward to DS-mode TSC if needed + if (TSCMode == 0x00) return SPI_TSC::MicInputFrame(data, samples); + + // otherwise we don't handle mic input + // TODO: handle it where it needs to be } u8 Read() { + if (TSCMode == 0x00) return SPI_TSC::Read(); + return Data; } void Write(u8 val, u32 hold) { + if (TSCMode == 0x00) return SPI_TSC::Write(val, hold); + #define READWRITE(var) { if (Index & 0x01) Data = var; else var = val; } if (DataPos == 0) @@ -137,18 +157,18 @@ void Write(u8 val, u32 hold) if (id == 0) { - READWRITE(Mode); + READWRITE(Bank); } - else if (Mode == 0x03) + else if (Bank == 0x03) { - if (Index & 0x01) Data = Mode3Regs[id]; + if (Index & 0x01) Data = Bank3Regs[id]; else { if (id == 0x0D || id == 0x0E) - Mode3Regs[id] = (Mode3Regs[id] & 0x03) | (val & 0xFC); + Bank3Regs[id] = (Bank3Regs[id] & 0x03) | (val & 0xFC); } } - else if ((Mode == 0xFC) && (Index & 0x01)) + else if ((Bank == 0xFC) && (Index & 0x01)) { if (id < 0x0B) { @@ -174,9 +194,31 @@ void Write(u8 val, u32 hold) Data = 0; } } + else if (Bank == 0xFF) + { + if (id == 0x05) + { + // TSC mode register + // 01: normal (DSi) mode + // 00: compatibility (DS) mode + + if (Index & 0x01) Data = TSCMode; + else + { + TSCMode = val; + if (TSCMode == 0x00) + { + printf("DSi_SPI_TSC: DS-compatibility mode\n"); + DataPos = 0; + NDS::KeyInput |= (1 << (16+6)); + return; + } + } + } + } else { - printf("DSi_SPI_TSC: unknown IO, mode=%02X, index=%02X (%02X %s)\n", Mode, Index, Index>>1, (Index&1)?"read":"write"); + printf("DSi_SPI_TSC: unknown IO, bank=%02X, index=%02X (%02X %s)\n", Bank, Index, Index>>1, (Index&1)?"read":"write"); } Index += (1<<1); // increment index diff --git a/src/NDS.cpp b/src/NDS.cpp index da7f9f9..42b5d9f 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -580,7 +580,7 @@ bool DoSavestate_Scheduler(Savestate* file) } if (funcid == -1) { - printf("savestate: VERY BAD!!!!! FUNCTION POINTER FOR EVENT %d NOT IN HACKY LIST. CANNOT SAVE. SMACK STAPLEBUTTER.\n", i); + printf("savestate: VERY BAD!!!!! FUNCTION POINTER FOR EVENT %d NOT IN HACKY LIST. CANNOT SAVE. SMACK ARISOTURA.\n", i); return false; } } @@ -694,7 +694,7 @@ bool DoSavestate(Savestate* file) for (int i = 0; i < 8; i++) DMAs[i]->DoSavestate(file); - file->Var8(&WRAMCnt); + file->Var8(&WRAMCnt); // FIXME!!!!! if (!file->Saving) { diff --git a/src/NDS.h b/src/NDS.h index d391cf7..309b16a 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -163,6 +163,8 @@ extern u8 ARM7BIOS[0x10000]; extern u8 MainRAM[MAIN_RAM_SIZE]; +extern u32 KeyInput; + bool Init(); void DeInit(); void Reset(); diff --git a/src/SPI.h b/src/SPI.h index 44de876..73fd57e 100644 --- a/src/SPI.h +++ b/src/SPI.h @@ -39,6 +39,9 @@ namespace SPI_TSC void SetTouchCoords(u16 x, u16 y); void MicInputFrame(s16* data, int samples); +u8 Read(); +void Write(u8 val, u32 hold); + } namespace SPI -- cgit v1.2.3 From 4d3d8433cbfc7916a344c18c491da401f6e32bfb Mon Sep 17 00:00:00 2001 From: Arisotura Date: Mon, 5 Aug 2019 19:52:03 +0200 Subject: * add old DS BIOSes and 04004000 BIOS-switch fixes audio issues when running DS games * attempt adding other fun shit like dynamic RAM size, but that mostly went nowhere for now --- src/DSi.cpp | 191 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- src/DSi.h | 3 + src/NDS.cpp | 154 ++++++++++++++++++++++++++---------------------- src/NDS.h | 11 ++-- 4 files changed, 251 insertions(+), 108 deletions(-) (limited to 'src/NDS.h') diff --git a/src/DSi.cpp b/src/DSi.cpp index 771f67b..9f07fa1 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -45,11 +45,15 @@ namespace DSi u32 BootAddr[2]; +u16 SCFG_BIOS; u16 SCFG_Clock9; u16 SCFG_Clock7; u32 SCFG_EXT[2]; u32 SCFG_MC; +u8 ARM9iBIOS[0x10000]; +u8 ARM7iBIOS[0x10000]; + u32 MBK[2][9]; u8 NWRAM_A[0x40000]; @@ -131,6 +135,7 @@ void Reset() SDMMC->Reset(); SDIO->Reset(); + SCFG_BIOS = 0x0101; // TODO: should be zero when booting from BIOS SCFG_Clock9 = 0x0187; // CHECKME SCFG_Clock7 = 0x0187; SCFG_EXT[0] = 0x8307F100; @@ -160,18 +165,21 @@ bool LoadBIOS() FILE* f; u32 i; + memset(ARM9iBIOS, 0, 0x10000); + memset(ARM7iBIOS, 0, 0x10000); + f = Platform::OpenLocalFile("bios9i.bin", "rb"); if (!f) { printf("ARM9i BIOS not found\n"); for (i = 0; i < 16; i++) - ((u32*)NDS::ARM9BIOS)[i] = 0xE7FFDEFF; + ((u32*)ARM9iBIOS)[i] = 0xE7FFDEFF; } else { fseek(f, 0, SEEK_SET); - fread(NDS::ARM9BIOS, 0x10000, 1, f); + fread(ARM9iBIOS, 0x10000, 1, f); printf("ARM9i BIOS loaded\n"); fclose(f); @@ -183,22 +191,25 @@ bool LoadBIOS() printf("ARM7i BIOS not found\n"); for (i = 0; i < 16; i++) - ((u32*)NDS::ARM7BIOS)[i] = 0xE7FFDEFF; + ((u32*)ARM7iBIOS)[i] = 0xE7FFDEFF; } else { // TODO: check if the first 32 bytes are crapoed fseek(f, 0, SEEK_SET); - fread(NDS::ARM7BIOS, 0x10000, 1, f); + fread(ARM7iBIOS, 0x10000, 1, f); printf("ARM7i BIOS loaded\n"); fclose(f); } // herp - *(u32*)&NDS::ARM9BIOS[0] = 0xEAFFFFFE; - *(u32*)&NDS::ARM7BIOS[0] = 0xEAFFFFFE; + *(u32*)&ARM9iBIOS[0] = 0xEAFFFFFE; + *(u32*)&ARM7iBIOS[0] = 0xEAFFFFFE; + + // TODO!!!! + // hax the upper 32K out of the goddamn DSi return true; } @@ -582,6 +593,22 @@ void MapNWRAMRange(u32 cpu, u32 num, u32 val) } +void Set_SCFG_Clock9(u16 val) +{ + SCFG_Clock9 = val & 0x0187; + return; + + NDS::ARM9Timestamp >>= NDS::ARM9ClockShift; + + printf("CLOCK9=%04X\n", val); + SCFG_Clock9 = val & 0x0187; + + if (SCFG_Clock9 & (1<<0)) NDS::ARM9ClockShift = 2; + else NDS::ARM9ClockShift = 1; + NDS::ARM9Timestamp <<= NDS::ARM9ClockShift; + NDS::ARM9->UpdateRegionTimings(0x00000000, 0xFFFFFFFF); +} + void Set_SCFG_MC(u32 val) { u32 oldslotstatus = SCFG_MC & 0xC; @@ -600,6 +627,14 @@ void Set_SCFG_MC(u32 val) u8 ARM9Read8(u32 addr) { + if ((addr >= 0xFFFF0000) && (!(SCFG_BIOS & (1<<1)))) + { + if ((addr >= 0xFFFF8000) && (SCFG_BIOS & (1<<0))) + return 0xFF; + + return *(u8*)&ARM9iBIOS[addr & 0xFFFF]; + } + switch (addr & 0xFF000000) { case 0x03000000: @@ -629,6 +664,14 @@ u8 ARM9Read8(u32 addr) u16 ARM9Read16(u32 addr) { + if ((addr >= 0xFFFF0000) && (!(SCFG_BIOS & (1<<1)))) + { + if ((addr >= 0xFFFF8000) && (SCFG_BIOS & (1<<0))) + return 0xFFFF; + + return *(u16*)&ARM9iBIOS[addr & 0xFFFF]; + } + switch (addr & 0xFF000000) { case 0x03000000: @@ -658,6 +701,14 @@ u16 ARM9Read16(u32 addr) u32 ARM9Read32(u32 addr) { + if ((addr >= 0xFFFF0000) && (!(SCFG_BIOS & (1<<1)))) + { + if ((addr >= 0xFFFF8000) && (SCFG_BIOS & (1<<0))) + return 0xFFFFFFFF; + + return *(u32*)&ARM9iBIOS[addr & 0xFFFF]; + } + switch (addr & 0xFF000000) { case 0x03000000: @@ -790,14 +841,28 @@ bool ARM9GetMemRegion(u32 addr, bool write, NDS::MemRegion* region) { case 0x02000000: region->Mem = NDS::MainRAM; - region->Mask = MAIN_RAM_SIZE-1; + region->Mask = NDS::MainRAMMask; return true; } if ((addr & 0xFFFF0000) == 0xFFFF0000 && !write) { - region->Mem = NDS::ARM9BIOS; - region->Mask = 0xFFFF; + if (SCFG_BIOS & (1<<1)) + { + if (addr >= 0xFFFF1000) + { + region->Mem = NULL; + return false; + } + + region->Mem = NDS::ARM9BIOS; + region->Mask = 0xFFF; + } + else + { + region->Mem = ARM9iBIOS; + region->Mask = 0xFFFF; + } return true; } @@ -809,6 +874,18 @@ bool ARM9GetMemRegion(u32 addr, bool write, NDS::MemRegion* region) u8 ARM7Read8(u32 addr) { + if ((addr < 0x00010000) && (!(SCFG_BIOS & (1<<9)))) + { + if ((addr >= 0x00008000) && (SCFG_BIOS & (1<<8))) + return 0xFF; + if (NDS::ARM7->R[15] >= 0x00010000) + return 0xFF; + if (addr < NDS::ARM7BIOSProt && NDS::ARM7->R[15] >= NDS::ARM7BIOSProt) + return 0xFF; + + return *(u8*)&ARM7iBIOS[addr]; + } + switch (addr & 0xFF800000) { case 0x03000000: @@ -838,6 +915,18 @@ u8 ARM7Read8(u32 addr) u16 ARM7Read16(u32 addr) { + if ((addr < 0x00010000) && (!(SCFG_BIOS & (1<<9)))) + { + if ((addr >= 0x00008000) && (SCFG_BIOS & (1<<8))) + return 0xFFFF; + if (NDS::ARM7->R[15] >= 0x00010000) + return 0xFFFF; + if (addr < NDS::ARM7BIOSProt && NDS::ARM7->R[15] >= NDS::ARM7BIOSProt) + return 0xFFFF; + + return *(u16*)&ARM7iBIOS[addr]; + } + switch (addr & 0xFF800000) { case 0x03000000: @@ -867,6 +956,18 @@ u16 ARM7Read16(u32 addr) u32 ARM7Read32(u32 addr) { + if ((addr < 0x00010000) && (!(SCFG_BIOS & (1<<9)))) + { + if ((addr >= 0x00008000) && (SCFG_BIOS & (1<<8))) + return 0xFFFFFFFF; + if (NDS::ARM7->R[15] >= 0x00010000) + return 0xFFFFFFFF; + if (addr < NDS::ARM7BIOSProt && NDS::ARM7->R[15] >= NDS::ARM7BIOSProt) + return 0xFFFFFFFF; + + return *(u32*)&ARM7iBIOS[addr]; + } + switch (addr & 0xFF800000) { case 0x03000000: @@ -1000,7 +1101,7 @@ bool ARM7GetMemRegion(u32 addr, bool write, NDS::MemRegion* region) case 0x02000000: case 0x02800000: region->Mem = NDS::MainRAM; - region->Mask = MAIN_RAM_SIZE-1; + region->Mask = NDS::MainRAMMask; return true; } @@ -1040,7 +1141,7 @@ u8 ARM9IORead8(u32 addr) { switch (addr) { - case 0x04004000: return 1; + case 0x04004000: return SCFG_BIOS & 0xFF; CASE_READ8_32BIT(0x04004040, MBK[0][0]) CASE_READ8_32BIT(0x04004044, MBK[0][1]) @@ -1060,6 +1161,7 @@ u16 ARM9IORead16(u32 addr) { switch (addr) { + case 0x04004000: return SCFG_BIOS & 0xFF; case 0x04004004: return SCFG_Clock9; case 0x04004010: return SCFG_MC & 0xFFFF; @@ -1081,6 +1183,7 @@ u32 ARM9IORead32(u32 addr) { switch (addr) { + case 0x04004000: return SCFG_BIOS & 0xFF; case 0x04004008: return SCFG_EXT[0]; case 0x04004010: return SCFG_MC & 0xFFFF; @@ -1172,9 +1275,7 @@ void ARM9IOWrite16(u32 addr, u16 val) switch (addr) { case 0x04004004: - // TODO: actually change clock! - printf("CLOCK9=%04X\n", val); - SCFG_Clock9 = val & 0x0187; + Set_SCFG_Clock9(val); return; case 0x04004040: @@ -1232,6 +1333,20 @@ void ARM9IOWrite32(u32 addr, u32 val) SCFG_EXT[1] &= ~0x0000F080; SCFG_EXT[1] |= (val & 0x0000F080); printf("SCFG_EXT = %08X / %08X (val9 %08X)\n", SCFG_EXT[0], SCFG_EXT[1], val); + /*switch ((SCFG_EXT[0] >> 14) & 0x3) + { + case 0: + case 1: + NDS::MainRAMMask = 0x3FFFFF; + printf("RAM: 4MB\n"); + break; + case 2: + case 3: // TODO: debug console w/ 32MB? + NDS::MainRAMMask = 0xFFFFFF; + printf("RAM: 16MB\n"); + break; + }*/ + printf("from %08X, ARM7 %08X, %08X\n", NDS::GetPC(0), NDS::GetPC(1), NDS::ARM7->R[1]); return; case 0x04004040: @@ -1307,8 +1422,8 @@ u8 ARM7IORead8(u32 addr) { switch (addr) { - case 0x04004000: return 0x01; - case 0x04004001: return 0x01; + case 0x04004000: return SCFG_BIOS & 0xFF; + case 0x04004001: return SCFG_BIOS >> 8; CASE_READ8_32BIT(0x04004040, MBK[1][0]) CASE_READ8_32BIT(0x04004044, MBK[1][1]) @@ -1323,14 +1438,14 @@ u8 ARM7IORead8(u32 addr) case 0x04004500: return DSi_I2C::ReadData(); case 0x04004501: return DSi_I2C::Cnt; - case 0x04004D00: return ConsoleID & 0xFF; - case 0x04004D01: return (ConsoleID >> 8) & 0xFF; - case 0x04004D02: return (ConsoleID >> 16) & 0xFF; - case 0x04004D03: return (ConsoleID >> 24) & 0xFF; - case 0x04004D04: return (ConsoleID >> 32) & 0xFF; - case 0x04004D05: return (ConsoleID >> 40) & 0xFF; - case 0x04004D06: return (ConsoleID >> 48) & 0xFF; - case 0x04004D07: return ConsoleID >> 56; + case 0x04004D00: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID & 0xFF; + case 0x04004D01: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 8) & 0xFF; + case 0x04004D02: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 16) & 0xFF; + case 0x04004D03: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 24) & 0xFF; + case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 32) & 0xFF; + case 0x04004D05: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 40) & 0xFF; + case 0x04004D06: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 48) & 0xFF; + case 0x04004D07: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID >> 56; case 0x04004D08: return 0; } @@ -1344,6 +1459,7 @@ u16 ARM7IORead16(u32 addr) case 0x04000218: return NDS::IE2; case 0x0400021C: return NDS::IF2; + case 0x04004000: return SCFG_BIOS; case 0x04004004: return SCFG_Clock7; case 0x04004006: return 0; // JTAG register case 0x04004010: return SCFG_MC & 0xFFFF; @@ -1358,10 +1474,10 @@ u16 ARM7IORead16(u32 addr) CASE_READ16_32BIT(0x0400405C, MBK[1][7]) CASE_READ16_32BIT(0x04004060, MBK[1][8]) - case 0x04004D00: return ConsoleID & 0xFFFF; - case 0x04004D02: return (ConsoleID >> 16) & 0xFFFF; - case 0x04004D04: return (ConsoleID >> 32) & 0xFFFF; - case 0x04004D06: return ConsoleID >> 48; + case 0x04004D00: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID & 0xFFFF; + case 0x04004D02: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 16) & 0xFFFF; + case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return (ConsoleID >> 32) & 0xFFFF; + case 0x04004D06: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID >> 48; case 0x04004D08: return 0; } @@ -1384,6 +1500,7 @@ u32 ARM7IORead32(u32 addr) case 0x04000218: return NDS::IE2; case 0x0400021C: return NDS::IF2; + case 0x04004000: return SCFG_BIOS; case 0x04004008: return SCFG_EXT[1]; case 0x04004010: return SCFG_MC; @@ -1430,8 +1547,8 @@ u32 ARM7IORead32(u32 addr) case 0x04004400: return DSi_AES::ReadCnt(); case 0x0400440C: return DSi_AES::ReadOutputFIFO(); - case 0x04004D00: return ConsoleID & 0xFFFFFFFF; - case 0x04004D04: return ConsoleID >> 32; + case 0x04004D00: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID & 0xFFFFFFFF; + case 0x04004D04: if (SCFG_BIOS & (1<<10)) return 0; return ConsoleID >> 32; case 0x04004D08: return 0; } @@ -1453,6 +1570,13 @@ void ARM7IOWrite8(u32 addr, u8 val) { switch (addr) { + case 0x04004000: + SCFG_BIOS |= (val & 0x03); + return; + case 0x04004001: + SCFG_BIOS |= ((val & 0x07) << 8); + return; + case 0x04004500: DSi_I2C::WriteData(val); return; case 0x04004501: DSi_I2C::WriteCnt(val); return; } @@ -1467,10 +1591,12 @@ void ARM7IOWrite16(u32 addr, u16 val) case 0x04000218: NDS::IE2 = (val & 0x7FF7); NDS::UpdateIRQ(1); return; case 0x0400021C: NDS::IF2 &= ~(val & 0x7FF7); NDS::UpdateIRQ(1); return; + case 0x04004000: + SCFG_BIOS |= (val & 0x0703); + return; case 0x04004004: SCFG_Clock7 = val & 0x0187; return; - case 0x04004010: Set_SCFG_MC((SCFG_MC & 0xFFFF0000) | val); return; @@ -1497,6 +1623,9 @@ void ARM7IOWrite32(u32 addr, u32 val) case 0x04000218: NDS::IE2 = (val & 0x7FF7); NDS::UpdateIRQ(1); return; case 0x0400021C: NDS::IF2 &= ~(val & 0x7FF7); NDS::UpdateIRQ(1); return; + case 0x04004000: + SCFG_BIOS |= (val & 0x0703); + return; case 0x04004008: SCFG_EXT[0] &= ~0x03000000; SCFG_EXT[0] |= (val & 0x03000000); diff --git a/src/DSi.h b/src/DSi.h index b29cdb5..bd37550 100644 --- a/src/DSi.h +++ b/src/DSi.h @@ -25,6 +25,9 @@ namespace DSi { +extern u8 ARM9iBIOS[0x10000]; +extern u8 ARM7iBIOS[0x10000]; + extern u8 eMMC_CID[16]; extern u64 ConsoleID; diff --git a/src/NDS.cpp b/src/NDS.cpp index 42b5d9f..95265cf 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -86,10 +86,11 @@ u32 SchedListMask; u32 CPUStop; -u8 ARM9BIOS[0x10000]; -u8 ARM7BIOS[0x10000]; +u8 ARM9BIOS[0x1000]; +u8 ARM7BIOS[0x4000]; -u8 MainRAM[MAIN_RAM_SIZE]; +u8 MainRAM[0x1000000]; +u32 MainRAMMask; u8 SharedWRAM[0x8000]; u8 WRAMCnt; @@ -235,7 +236,11 @@ void SetARM9RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq, ARM9MemTimings[i][3] = S32; } - ARM9->UpdateRegionTimings(addrstart<<14, addrend<<14); + addrstart <<= 14; + addrend <<= 14; + if (!addrend) addrend = 0xFFFFFFFF; + + ARM9->UpdateRegionTimings(addrstart, addrend); } void SetARM7RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq, int seq) @@ -395,53 +400,58 @@ void Reset() LastSysClockCycles = 0; - memset(ARM9BIOS, 0, 0x10000); - memset(ARM7BIOS, 0, 0x10000); + memset(ARM9BIOS, 0, 0x1000); + memset(ARM7BIOS, 0, 0x4000); - if (true) + // DS BIOSes are always loaded, even in DSi mode + // we need them for DS-compatible mode + + f = Platform::OpenLocalFile("bios9.bin", "rb"); + if (!f) { - DSi::LoadBIOS(); - DSi::LoadNAND(); + printf("ARM9 BIOS not found\n"); - ARM9ClockShift = 2; + for (i = 0; i < 16; i++) + ((u32*)ARM9BIOS)[i] = 0xE7FFDEFF; } else { - f = Platform::OpenLocalFile("bios9.bin", "rb"); - if (!f) - { - printf("ARM9 BIOS not found\n"); + fseek(f, 0, SEEK_SET); + fread(ARM9BIOS, 0x1000, 1, f); - for (i = 0; i < 16; i++) - ((u32*)ARM9BIOS)[i] = 0xE7FFDEFF; - } - else - { - fseek(f, 0, SEEK_SET); - fread(ARM9BIOS, 0x1000, 1, f); + printf("ARM9 BIOS loaded\n"); + fclose(f); + } - printf("ARM9 BIOS loaded\n"); - fclose(f); - } + f = Platform::OpenLocalFile("bios7.bin", "rb"); + if (!f) + { + printf("ARM7 BIOS not found\n"); - f = Platform::OpenLocalFile("bios7.bin", "rb"); - if (!f) - { - printf("ARM7 BIOS not found\n"); + for (i = 0; i < 16; i++) + ((u32*)ARM7BIOS)[i] = 0xE7FFDEFF; + } + else + { + fseek(f, 0, SEEK_SET); + fread(ARM7BIOS, 0x4000, 1, f); - for (i = 0; i < 16; i++) - ((u32*)ARM7BIOS)[i] = 0xE7FFDEFF; - } - else - { - fseek(f, 0, SEEK_SET); - fread(ARM7BIOS, 0x4000, 1, f); + printf("ARM7 BIOS loaded\n"); + fclose(f); + } - printf("ARM7 BIOS loaded\n"); - fclose(f); - } + if (true) + { + DSi::LoadBIOS(); + DSi::LoadNAND(); + ARM9ClockShift = 2; + MainRAMMask = 0xFFFFFF; + } + else + { ARM9ClockShift = 1; + MainRAMMask = 0x3FFFFF; } ARM9Timestamp = 0; ARM9Target = 0; @@ -450,7 +460,7 @@ void Reset() InitTimings(); - memset(MainRAM, 0, MAIN_RAM_SIZE); + memset(MainRAM, 0, 0x1000000); memset(SharedWRAM, 0, 0x8000); memset(ARM7WRAM, 0, 0x10000); @@ -1608,36 +1618,36 @@ void debug(u32 param) fwrite(&val, 4, 1, shit); } fclose(shit);*/ - /*FILE* - shit = fopen("debug/dump9.bin", "wb"); + FILE* + /*shit = fopen("debug/dump9.bin", "wb"); for (u32 i = 0x02000000; i < 0x04000000; i+=4) { u32 val = DSi::ARM9Read32(i); fwrite(&val, 4, 1, shit); } - fclose(shit); - shit = fopen("debug/dump7.bin", "wb"); + fclose(shit);*/ + shit = fopen("debug/dump7_2.bin", "wb"); for (u32 i = 0x02000000; i < 0x04000000; i+=4) { u32 val = DSi::ARM7Read32(i); fwrite(&val, 4, 1, shit); } - fclose(shit);*/ + fclose(shit); } u8 ARM9Read8(u32 addr) { - if ((addr & 0xFFFF0000) == 0xFFFF0000) + if ((addr & 0xFFFFF000) == 0xFFFF0000) { - return *(u8*)&ARM9BIOS[addr & 0xFFFF]; + return *(u8*)&ARM9BIOS[addr & 0xFFF]; } switch (addr & 0xFF000000) { case 0x02000000: - return *(u8*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)]; + return *(u8*)&MainRAM[addr & MainRAMMask]; case 0x03000000: if (SWRAM_ARM9) @@ -1690,15 +1700,15 @@ u8 ARM9Read8(u32 addr) u16 ARM9Read16(u32 addr) { - if ((addr & 0xFFFF0000) == 0xFFFF0000) + if ((addr & 0xFFFFF000) == 0xFFFF0000) { - return *(u16*)&ARM9BIOS[addr & 0xFFFF]; + return *(u16*)&ARM9BIOS[addr & 0xFFF]; } switch (addr & 0xFF000000) { case 0x02000000: - return *(u16*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)]; + return *(u16*)&MainRAM[addr & MainRAMMask]; case 0x03000000: if (SWRAM_ARM9) @@ -1751,15 +1761,15 @@ u16 ARM9Read16(u32 addr) u32 ARM9Read32(u32 addr) { - if ((addr & 0xFFFF0000) == 0xFFFF0000) + if ((addr & 0xFFFFF000) == 0xFFFF0000) { - return *(u32*)&ARM9BIOS[addr & 0xFFFF]; + return *(u32*)&ARM9BIOS[addr & 0xFFF]; } switch (addr & 0xFF000000) { case 0x02000000: - return *(u32*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)]; + return *(u32*)&MainRAM[addr & MainRAMMask]; case 0x03000000: if (SWRAM_ARM9) @@ -1815,7 +1825,7 @@ void ARM9Write8(u32 addr, u8 val) switch (addr & 0xFF000000) { case 0x02000000: - *(u8*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val; + *(u8*)&MainRAM[addr & MainRAMMask] = val; return; case 0x03000000: @@ -1844,7 +1854,7 @@ void ARM9Write16(u32 addr, u16 val) switch (addr & 0xFF000000) { case 0x02000000: - *(u16*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val; + *(u16*)&MainRAM[addr & MainRAMMask] = val; return; case 0x03000000: @@ -1887,7 +1897,7 @@ void ARM9Write32(u32 addr, u32 val) switch (addr & 0xFF000000) { case 0x02000000: - *(u32*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val; + *(u32*)&MainRAM[addr & MainRAMMask] = val; return ; case 0x03000000: @@ -1931,7 +1941,7 @@ bool ARM9GetMemRegion(u32 addr, bool write, MemRegion* region) { case 0x02000000: region->Mem = MainRAM; - region->Mask = MAIN_RAM_SIZE-1; + region->Mask = MainRAMMask; return true; case 0x03000000: @@ -1959,10 +1969,10 @@ bool ARM9GetMemRegion(u32 addr, bool write, MemRegion* region) u8 ARM7Read8(u32 addr) { - if (addr < 0x00010000) + if (addr < 0x00004000) { // TODO: check the boundary? is it 4000 or higher on regular DS? - if (ARM7->R[15] >= 0x00010000) + if (ARM7->R[15] >= 0x00004000) return 0xFF; if (addr < ARM7BIOSProt && ARM7->R[15] >= ARM7BIOSProt) return 0xFF; @@ -1974,7 +1984,7 @@ u8 ARM7Read8(u32 addr) { case 0x02000000: case 0x02800000: - return *(u8*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)]; + return *(u8*)&MainRAM[addr & MainRAMMask]; case 0x03000000: if (SWRAM_ARM7) @@ -2016,9 +2026,9 @@ u8 ARM7Read8(u32 addr) u16 ARM7Read16(u32 addr) { - if (addr < 0x00010000) + if (addr < 0x00004000) { - if (ARM7->R[15] >= 0x00010000) + if (ARM7->R[15] >= 0x00004000) return 0xFFFF; if (addr < ARM7BIOSProt && ARM7->R[15] >= ARM7BIOSProt) return 0xFFFF; @@ -2030,7 +2040,7 @@ u16 ARM7Read16(u32 addr) { case 0x02000000: case 0x02800000: - return *(u16*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)]; + return *(u16*)&MainRAM[addr & MainRAMMask]; case 0x03000000: if (SWRAM_ARM7) @@ -2079,9 +2089,9 @@ u16 ARM7Read16(u32 addr) u32 ARM7Read32(u32 addr) { - if (addr < 0x00010000) + if (addr < 0x00004000) { - if (ARM7->R[15] >= 0x00010000) + if (ARM7->R[15] >= 0x00004000) return 0xFFFFFFFF; if (addr < ARM7BIOSProt && ARM7->R[15] >= ARM7BIOSProt) return 0xFFFFFFFF; @@ -2093,7 +2103,7 @@ u32 ARM7Read32(u32 addr) { case 0x02000000: case 0x02800000: - return *(u32*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)]; + return *(u32*)&MainRAM[addr & MainRAMMask]; case 0x03000000: if (SWRAM_ARM7) @@ -2146,7 +2156,7 @@ void ARM7Write8(u32 addr, u8 val) { case 0x02000000: case 0x02800000: - *(u8*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val; + *(u8*)&MainRAM[addr & MainRAMMask] = val; return; case 0x03000000: @@ -2184,7 +2194,7 @@ void ARM7Write16(u32 addr, u16 val) { case 0x02000000: case 0x02800000: - *(u16*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val; + *(u16*)&MainRAM[addr & MainRAMMask] = val; return; case 0x03000000: @@ -2230,7 +2240,7 @@ void ARM7Write32(u32 addr, u32 val) { case 0x02000000: case 0x02800000: - *(u32*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val; + *(u32*)&MainRAM[addr & MainRAMMask] = val; return; case 0x03000000: @@ -2278,7 +2288,7 @@ bool ARM7GetMemRegion(u32 addr, bool write, MemRegion* region) case 0x02000000: case 0x02800000: region->Mem = MainRAM; - region->Mask = MAIN_RAM_SIZE-1; + region->Mask = MainRAMMask; return true; case 0x03000000: @@ -2555,7 +2565,7 @@ u32 ARM9IORead32(u32 addr) case 0x04000130: return (KeyInput & 0xFFFF) | (KeyCnt << 16); - case 0x04000180: return IPCSync9; + case 0x04000180: /*printf("ARM9 read IPCSYNC: %04X\n", IPCSync9);*/ return IPCSync9; case 0x040001A0: return NDSCart::SPICnt | (NDSCart::ReadSPIData() << 16); case 0x040001A4: return NDSCart::ROMCnt; @@ -2764,6 +2774,7 @@ void ARM9IOWrite16(u32 addr, u16 val) return; case 0x04000180: + printf("ARM9 IPCSYNC = %04X\n", val); IPCSync7 &= 0xFFF0; IPCSync7 |= ((val & 0x0F00) >> 8); IPCSync9 &= 0xB0FF; @@ -3348,6 +3359,7 @@ void ARM7IOWrite16(u32 addr, u16 val) case 0x04000138: RTC::Write(val, false); return; case 0x04000180: + printf("ARM7 IPCSYNC = %04X\n", val); IPCSync9 &= 0xFFF0; IPCSync9 |= ((val & 0x0F00) >> 8); IPCSync7 &= 0xB0FF; diff --git a/src/NDS.h b/src/NDS.h index 309b16a..1b572ea 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -155,13 +155,12 @@ extern u16 ExMemCnt[2]; extern u8 ROMSeed0[2*8]; extern u8 ROMSeed1[2*8]; -extern u8 ARM9BIOS[0x10000]; -extern u8 ARM7BIOS[0x10000]; +extern u8 ARM9BIOS[0x1000]; +extern u8 ARM7BIOS[0x4000]; +extern u16 ARM7BIOSProt; -//#define MAIN_RAM_SIZE 0x400000 -#define MAIN_RAM_SIZE 0x1000000 - -extern u8 MainRAM[MAIN_RAM_SIZE]; +extern u8 MainRAM[0x1000000]; +extern u32 MainRAMMask; extern u32 KeyInput; -- cgit v1.2.3 From 43e045357f7d74eecff61b0c8af8068b31e963b3 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Mon, 1 Jun 2020 20:36:30 +0200 Subject: make it able to switch between DS and DSi modes --- src/ARM.cpp | 46 +++++++++ src/ARM.h | 43 ++++---- src/CP15.cpp | 30 ++---- src/DMA.cpp | 29 ++++-- src/DMA.h | 5 + src/DSi.cpp | 7 +- src/NDS.cpp | 54 +++++++--- src/NDS.h | 5 + src/NDSCart.cpp | 15 ++- src/SPI.cpp | 32 ++++-- src/SPU.cpp | 16 ++- src/SPU.h | 6 ++ src/frontend/FrontendUtil.h | 9 ++ src/frontend/Util_ROM.cpp | 163 +++++++++++++++++++++++++++--- src/frontend/qt_sdl/EmuSettingsDialog.cpp | 2 +- src/frontend/qt_sdl/main.cpp | 45 +++++++-- 16 files changed, 396 insertions(+), 111 deletions(-) (limited to 'src/NDS.h') diff --git a/src/ARM.cpp b/src/ARM.cpp index 2d8c807..68cac59 100644 --- a/src/ARM.cpp +++ b/src/ARM.cpp @@ -18,6 +18,7 @@ #include #include "NDS.h" +#include "DSi.h" #include "ARM.h" #include "ARMInterpreter.h" #include "AREngine.h" @@ -101,10 +102,55 @@ void ARM::Reset() void ARMv5::Reset() { + if (NDS::ConsoleType == 1) + { + BusRead8 = DSi::ARM9Read8; + BusRead16 = DSi::ARM9Read16; + BusRead32 = DSi::ARM9Read32; + BusWrite8 = DSi::ARM9Write8; + BusWrite16 = DSi::ARM9Write16; + BusWrite32 = DSi::ARM9Write32; + GetMemRegion = DSi::ARM9GetMemRegion; + } + else + { + BusRead8 = NDS::ARM9Read8; + BusRead16 = NDS::ARM9Read16; + BusRead32 = NDS::ARM9Read32; + BusWrite8 = NDS::ARM9Write8; + BusWrite16 = NDS::ARM9Write16; + BusWrite32 = NDS::ARM9Write32; + GetMemRegion = NDS::ARM9GetMemRegion; + } + CP15Reset(); ARM::Reset(); } +void ARMv4::Reset() +{ + if (NDS::ConsoleType) + { + BusRead8 = DSi::ARM7Read8; + BusRead16 = DSi::ARM7Read16; + BusRead32 = DSi::ARM7Read32; + BusWrite8 = DSi::ARM7Write8; + BusWrite16 = DSi::ARM7Write16; + BusWrite32 = DSi::ARM7Write32; + } + else + { + BusRead8 = NDS::ARM7Read8; + BusRead16 = NDS::ARM7Read16; + BusRead32 = NDS::ARM7Read32; + BusWrite8 = NDS::ARM7Write8; + BusWrite16 = NDS::ARM7Write16; + BusWrite32 = NDS::ARM7Write32; + } + + ARM::Reset(); +} + void ARM::DoSavestate(Savestate* file) { diff --git a/src/ARM.h b/src/ARM.h index 95c41d4..e0832e2 100644 --- a/src/ARM.h +++ b/src/ARM.h @@ -23,7 +23,6 @@ #include "types.h" #include "NDS.h" -#include "DSi.h" #define ROR(x, n) (((x) >> (n)) | ((x) << (32-(n)))) @@ -133,6 +132,14 @@ public: NDS::MemRegion CodeMem; static u32 ConditionTable[16]; + +protected: + u8 (*BusRead8)(u32 addr); + u16 (*BusRead16)(u32 addr); + u32 (*BusRead32)(u32 addr); + void (*BusWrite8)(u32 addr, u8 val); + void (*BusWrite16)(u32 addr, u16 val); + void (*BusWrite32)(u32 addr, u32 val); }; class ARMv5 : public ARM @@ -260,6 +267,8 @@ public: s32 RegionCodeCycles; u8* CurICacheLine; + + bool (*GetMemRegion)(u32 addr, bool write, NDS::MemRegion* region); }; class ARMv4 : public ARM @@ -267,26 +276,25 @@ class ARMv4 : public ARM public: ARMv4(); + void Reset(); + void JumpTo(u32 addr, bool restorecpsr = false); void Execute(); u16 CodeRead16(u32 addr) { - //return NDS::ARM7Read16(addr); - return DSi::ARM7Read16(addr); + return BusRead16(addr); } u32 CodeRead32(u32 addr) { - //return NDS::ARM7Read32(addr); - return DSi::ARM7Read32(addr); + return BusRead32(addr); } void DataRead8(u32 addr, u32* val) { - *val = DSi::ARM7Read8(addr); - //*val = NDS::ARM7Read8(addr); + *val = BusRead8(addr); DataRegion = addr >> 24; DataCycles = NDS::ARM7MemTimings[DataRegion][0]; } @@ -295,8 +303,7 @@ public: { addr &= ~1; - *val = DSi::ARM7Read16(addr); - //*val = NDS::ARM7Read16(addr); + *val = BusRead16(addr); DataRegion = addr >> 24; DataCycles = NDS::ARM7MemTimings[DataRegion][0]; } @@ -305,8 +312,7 @@ public: { addr &= ~3; - *val = DSi::ARM7Read32(addr); - //*val = NDS::ARM7Read32(addr); + *val = BusRead32(addr); DataRegion = addr >> 24; DataCycles = NDS::ARM7MemTimings[DataRegion][2]; } @@ -315,15 +321,13 @@ public: { addr &= ~3; - *val = DSi::ARM7Read32(addr); - //*val = NDS::ARM7Read32(addr); + *val = BusRead32(addr); DataCycles += NDS::ARM7MemTimings[DataRegion][3]; } void DataWrite8(u32 addr, u8 val) { - DSi::ARM7Write8(addr, val); - //NDS::ARM7Write8(addr, val); + BusWrite8(addr, val); DataRegion = addr >> 24; DataCycles = NDS::ARM7MemTimings[DataRegion][0]; } @@ -332,8 +336,7 @@ public: { addr &= ~1; - DSi::ARM7Write16(addr, val); - //NDS::ARM7Write16(addr, val); + BusWrite16(addr, val); DataRegion = addr >> 24; DataCycles = NDS::ARM7MemTimings[DataRegion][0]; } @@ -342,8 +345,7 @@ public: { addr &= ~3; - DSi::ARM7Write32(addr, val); - //NDS::ARM7Write32(addr, val); + BusWrite32(addr, val); DataRegion = addr >> 24; DataCycles = NDS::ARM7MemTimings[DataRegion][2]; } @@ -352,8 +354,7 @@ public: { addr &= ~3; - DSi::ARM7Write32(addr, val); - //NDS::ARM7Write32(addr, val); + BusWrite32(addr, val); DataCycles += NDS::ARM7MemTimings[DataRegion][3]; } diff --git a/src/CP15.cpp b/src/CP15.cpp index b61cc45..d340b9e 100644 --- a/src/CP15.cpp +++ b/src/CP15.cpp @@ -720,8 +720,7 @@ u32 ARMv5::CodeRead32(u32 addr, bool branch) if (CodeMem.Mem) return *(u32*)&CodeMem.Mem[addr & CodeMem.Mask]; - //return NDS::ARM9Read32(addr); - return DSi::ARM9Read32(addr); + return BusRead32(addr); } @@ -740,8 +739,7 @@ void ARMv5::DataRead8(u32 addr, u32* val) return; } - *val = DSi::ARM9Read8(addr); - //*val = NDS::ARM9Read8(addr); + *val = BusRead8(addr); DataCycles = MemTimings[addr >> 12][1]; } @@ -762,8 +760,7 @@ void ARMv5::DataRead16(u32 addr, u32* val) return; } - *val = DSi::ARM9Read16(addr); - //*val = NDS::ARM9Read16(addr); + *val = BusRead16(addr); DataCycles = MemTimings[addr >> 12][1]; } @@ -784,8 +781,7 @@ void ARMv5::DataRead32(u32 addr, u32* val) return; } - *val = DSi::ARM9Read32(addr); - //*val = NDS::ARM9Read32(addr); + *val = BusRead32(addr); DataCycles = MemTimings[addr >> 12][2]; } @@ -806,8 +802,7 @@ void ARMv5::DataRead32S(u32 addr, u32* val) return; } - *val = DSi::ARM9Read32(addr); - //*val = NDS::ARM9Read32(addr); + *val = BusRead32(addr); DataCycles += MemTimings[addr >> 12][3]; } @@ -826,8 +821,7 @@ void ARMv5::DataWrite8(u32 addr, u8 val) return; } - DSi::ARM9Write8(addr, val); - //NDS::ARM9Write8(addr, val); + BusWrite8(addr, val); DataCycles = MemTimings[addr >> 12][1]; } @@ -848,8 +842,7 @@ void ARMv5::DataWrite16(u32 addr, u16 val) return; } - DSi::ARM9Write16(addr, val); - //NDS::ARM9Write16(addr, val); + BusWrite16(addr, val); DataCycles = MemTimings[addr >> 12][1]; } @@ -870,8 +863,7 @@ void ARMv5::DataWrite32(u32 addr, u32 val) return; } - DSi::ARM9Write32(addr, val); - //NDS::ARM9Write32(addr, val); + BusWrite32(addr, val); DataCycles = MemTimings[addr >> 12][2]; } @@ -892,8 +884,7 @@ void ARMv5::DataWrite32S(u32 addr, u32 val) return; } - DSi::ARM9Write32(addr, val); - //NDS::ARM9Write32(addr, val); + BusWrite32(addr, val); DataCycles += MemTimings[addr >> 12][3]; } @@ -906,7 +897,6 @@ void ARMv5::GetCodeMemRegion(u32 addr, NDS::MemRegion* region) return; }*/ - DSi::ARM9GetMemRegion(addr, false, &CodeMem); - //NDS::ARM9GetMemRegion(addr, false, &CodeMem); + GetMemRegion(addr, false, &CodeMem); } diff --git a/src/DMA.cpp b/src/DMA.cpp index 8e294fc..cd2df45 100644 --- a/src/DMA.cpp +++ b/src/DMA.cpp @@ -53,8 +53,6 @@ DMA::DMA(u32 cpu, u32 num) CountMask = 0x001FFFFF; else CountMask = (num==3 ? 0x0000FFFF : 0x00003FFF); - - Reset(); } DMA::~DMA() @@ -77,6 +75,21 @@ void DMA::Reset() Running = false; InProgress = false; + + if (NDS::ConsoleType == 1) + { + BusRead16 = (CPU==0) ? DSi::ARM9Read16 : DSi::ARM7Read16; + BusRead32 = (CPU==0) ? DSi::ARM9Read32 : DSi::ARM7Read32; + BusWrite16 = (CPU==0) ? DSi::ARM9Write16 : DSi::ARM7Write16; + BusWrite32 = (CPU==0) ? DSi::ARM9Write32 : DSi::ARM7Write32; + } + else + { + BusRead16 = (CPU==0) ? NDS::ARM9Read16 : NDS::ARM7Read16; + BusRead32 = (CPU==0) ? NDS::ARM9Read32 : NDS::ARM7Read32; + BusWrite16 = (CPU==0) ? NDS::ARM9Write16 : NDS::ARM7Write16; + BusWrite32 = (CPU==0) ? NDS::ARM9Write32 : NDS::ARM7Write32; + } } void DMA::DoSavestate(Savestate* file) @@ -227,8 +240,7 @@ void DMA::Run9() { NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift); - //NDS::ARM9Write16(CurDstAddr, NDS::ARM9Read16(CurSrcAddr)); - DSi::ARM9Write16(CurDstAddr, DSi::ARM9Read16(CurSrcAddr)); + BusWrite16(CurDstAddr, BusRead16(CurSrcAddr)); CurSrcAddr += SrcAddrInc<<1; CurDstAddr += DstAddrInc<<1; @@ -264,8 +276,7 @@ void DMA::Run9() { NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift); - //NDS::ARM9Write32(CurDstAddr, NDS::ARM9Read32(CurSrcAddr)); - DSi::ARM9Write32(CurDstAddr, DSi::ARM9Read32(CurSrcAddr)); + BusWrite32(CurDstAddr, BusRead32(CurSrcAddr)); CurSrcAddr += SrcAddrInc<<2; CurDstAddr += DstAddrInc<<2; @@ -341,8 +352,7 @@ void DMA::Run7() { NDS::ARM7Timestamp += unitcycles; - //NDS::ARM7Write16(CurDstAddr, NDS::ARM7Read16(CurSrcAddr)); - DSi::ARM7Write16(CurDstAddr, DSi::ARM7Read16(CurSrcAddr)); + BusWrite16(CurDstAddr, BusRead16(CurSrcAddr)); CurSrcAddr += SrcAddrInc<<1; CurDstAddr += DstAddrInc<<1; @@ -378,8 +388,7 @@ void DMA::Run7() { NDS::ARM7Timestamp += unitcycles; - //NDS::ARM7Write32(CurDstAddr, NDS::ARM7Read32(CurSrcAddr)); - DSi::ARM7Write32(CurDstAddr, DSi::ARM7Read32(CurSrcAddr)); + BusWrite32(CurDstAddr, BusRead32(CurSrcAddr)); CurSrcAddr += SrcAddrInc<<2; CurDstAddr += DstAddrInc<<2; diff --git a/src/DMA.h b/src/DMA.h index 2e7678c..0344fba 100644 --- a/src/DMA.h +++ b/src/DMA.h @@ -86,6 +86,11 @@ private: bool Stall; bool IsGXFIFODMA; + + u16 (*BusRead16)(u32 addr); + u32 (*BusRead32)(u32 addr); + void (*BusWrite16)(u32 addr, u16 val); + void (*BusWrite32)(u32 addr, u32 val); }; #endif diff --git a/src/DSi.cpp b/src/DSi.cpp index 58f39c2..520b269 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -18,6 +18,7 @@ #include #include +#include "Config.h" #include "NDS.h" #include "DSi.h" #include "ARM.h" @@ -221,7 +222,7 @@ bool LoadBIOS() memset(ARM9iBIOS, 0, 0x10000); memset(ARM7iBIOS, 0, 0x10000); - f = Platform::OpenLocalFile("bios9i.bin", "rb"); + f = Platform::OpenLocalFile(Config::DSiBIOS9Path, "rb"); if (!f) { printf("ARM9i BIOS not found\n"); @@ -238,7 +239,7 @@ bool LoadBIOS() fclose(f); } - f = Platform::OpenLocalFile("bios7i.bin", "rb"); + f = Platform::OpenLocalFile(Config::DSiBIOS7Path, "rb"); if (!f) { printf("ARM7i BIOS not found\n"); @@ -283,7 +284,7 @@ bool LoadNAND() memset(NWRAMEnd, 0, sizeof(NWRAMEnd)); memset(NWRAMMask, 0, sizeof(NWRAMMask)); - FILE* f = Platform::OpenLocalFile("nand.bin", "rb"); + FILE* f = Platform::OpenLocalFile(Config::DSiNANDPath, "rb"); if (f) { u32 bootparams[8]; diff --git a/src/NDS.cpp b/src/NDS.cpp index 001dfe6..22368ae 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -62,6 +62,8 @@ namespace NDS // // timings for GBA slot and wifi are set up at runtime +int ConsoleType; + u8 ARM9MemTimings[0x40000][4]; u8 ARM7MemTimings[0x20000][4]; @@ -296,6 +298,8 @@ void InitTimings() // TODO: +3c nonseq waitstate doesn't apply to DMA! // but of course mainRAM always gets 8c nonseq waitstate + // TODO: DSi-specific timings!! + SetARM9RegionTimings(0x00000000, 0xFFFFFFFF, 32, 1 + 3, 1); // void SetARM9RegionTimings(0xFFFF0000, 0xFFFFFFFF, 32, 1 + 3, 1); // BIOS @@ -321,6 +325,12 @@ void InitTimings() void SetupDirectBoot() { + if (ConsoleType == 1) + { + printf("!! DIRECT BOOT NOT SUPPORTED IN DSI MODE\n"); + return; + } + u32 bootparams[8]; memcpy(bootparams, &NDSCart::CartROM[0x20], 8*4); @@ -469,7 +479,7 @@ void Reset() fclose(f); } - if (true) + if (ConsoleType == 1) { DSi::LoadBIOS(); DSi::LoadNAND(); @@ -559,8 +569,11 @@ void Reset() RTC::Reset(); Wifi::Reset(); - DSi::Reset(); - KeyInput &= ~(1 << (16+6)); // TODO + if (ConsoleType == 1) + { + DSi::Reset(); + KeyInput &= ~(1 << (16+6)); + } AREngine::Reset(); } @@ -670,6 +683,11 @@ bool DoSavestate(Savestate* file) { file->Section("NDSG"); + // TODO: + // * do something for bool's (sizeof=1) + // * do something for 'loading DSi-mode savestate in DS mode' and vice-versa + // * add IE2/IF2 there + file->VarArray(MainRAM, 0x400000); file->VarArray(SharedWRAM, 0x8000); file->VarArray(ARM7WRAM, 0x10000); @@ -772,6 +790,11 @@ bool DoSavestate(Savestate* file) return true; } +void SetConsoleType(int type) +{ + ConsoleType = type; +} + bool LoadROM(const char* path, const char* sram, bool direct) { if (NDSCart::LoadROM(path, sram, direct)) @@ -883,7 +906,7 @@ u32 RunFrame() if (!(CPUStop & 0x80000000)) DMAs[1]->Run(); if (!(CPUStop & 0x80000000)) DMAs[2]->Run(); if (!(CPUStop & 0x80000000)) DMAs[3]->Run(); - DSi::RunNDMAs(0); + if (ConsoleType == 1) DSi::RunNDMAs(0); } else { @@ -906,7 +929,7 @@ u32 RunFrame() DMAs[5]->Run(); DMAs[6]->Run(); DMAs[7]->Run(); - DSi::RunNDMAs(1); + if (ConsoleType == 1) DSi::RunNDMAs(1); } else { @@ -990,7 +1013,7 @@ void CancelEvent(u32 id) void TouchScreen(u16 x, u16 y) { - if (true) // TODO!! + if (ConsoleType == 1) { DSi_SPI_TSC::SetTouchCoords(x, y); } @@ -1003,7 +1026,7 @@ void TouchScreen(u16 x, u16 y) void ReleaseScreen() { - if (true) // TODO!! + if (ConsoleType == 1) { DSi_SPI_TSC::SetTouchCoords(0x000, 0xFFF); } @@ -1144,7 +1167,8 @@ void UpdateIRQ(u32 cpu) if (IME[cpu] & 0x1) { arm->IRQ = IE[cpu] & IF[cpu]; - if (cpu) arm->IRQ |= (IE2 & IF2); + if ((ConsoleType == 1) && cpu) + arm->IRQ |= (IE2 & IF2); } else { @@ -1223,7 +1247,7 @@ void GXFIFOStall() DMAs[1]->StallIfRunning(); DMAs[2]->StallIfRunning(); DMAs[3]->StallIfRunning(); - DSi::StallNDMAs(); + if (ConsoleType == 1) DSi::StallNDMAs(); } } @@ -1361,6 +1385,7 @@ void NocashPrint(u32 ncpu, u32 addr) void MonitorARM9Jump(u32 addr) { // checkme: can the entrypoint addr be THUMB? + // also TODO: make it work in DSi mode if ((!RunningGame) && NDSCart::CartROM) { @@ -1468,7 +1493,7 @@ bool DMAsInMode(u32 cpu, u32 mode) if (DMAs[cpu+2]->IsInMode(mode)) return true; if (DMAs[cpu+3]->IsInMode(mode)) return true; - if (true) + if (ConsoleType == 1) { cpu >>= 2; return DSi::NDMAsInMode(cpu, NDMAModes[mode]); @@ -1484,7 +1509,10 @@ bool DMAsRunning(u32 cpu) if (DMAs[cpu+1]->IsRunning()) return true; if (DMAs[cpu+2]->IsRunning()) return true; if (DMAs[cpu+3]->IsRunning()) return true; - if (DSi::NDMAsRunning(cpu>>2)) return true; + if (ConsoleType == 1) + { + if (DSi::NDMAsRunning(cpu>>2)) return true; + } return false; } @@ -1496,7 +1524,7 @@ void CheckDMAs(u32 cpu, u32 mode) DMAs[cpu+2]->StartIfNeeded(mode); DMAs[cpu+3]->StartIfNeeded(mode); - if (true) + if (ConsoleType == 1) { cpu >>= 2; DSi::CheckNDMAs(cpu, NDMAModes[mode]); @@ -1511,7 +1539,7 @@ void StopDMAs(u32 cpu, u32 mode) DMAs[cpu+2]->StopIfNeeded(mode); DMAs[cpu+3]->StopIfNeeded(mode); - if (true) + if (ConsoleType == 1) { cpu >>= 2; DSi::StopNDMAs(cpu, NDMAModes[mode]); diff --git a/src/NDS.h b/src/NDS.h index 26931de..9c5fe3d 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -133,6 +133,8 @@ typedef struct } MemRegion; +extern int ConsoleType; + extern u8 ARM9MemTimings[0x40000][4]; extern u8 ARM7MemTimings[0x20000][4]; @@ -174,6 +176,9 @@ bool DoSavestate(Savestate* file); void SetARM9RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq, int seq); void SetARM7RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq, int seq); +// 0=DS 1=DSi +void SetConsoleType(int type); + bool LoadROM(const char* path, const char* sram, bool direct); bool LoadGBAROM(const char* path, const char* sram); void LoadBIOS(); diff --git a/src/NDSCart.cpp b/src/NDSCart.cpp index 9497d33..b326dd6 100644 --- a/src/NDSCart.cpp +++ b/src/NDSCart.cpp @@ -561,11 +561,18 @@ void Key1_ApplyKeycode(u32* keycode, u32 mod) void Key1_InitKeycode(bool dsi, u32 idcode, u32 level, u32 mod) { - //memcpy(Key1_KeyBuf, &NDS::ARM7BIOS[0x30], 0x1048); // hax - if (dsi) - memcpy(Key1_KeyBuf, &DSi::ARM7Init[0x254], 0x1048); // hax + // TODO: source the key data from different possible places + if (NDS::ConsoleType == 1) + { + if (dsi) + memcpy(Key1_KeyBuf, &DSi::ARM7Init[0x254], 0x1048); // hax + else + memcpy(Key1_KeyBuf, &DSi::ITCMInit[0x4894], 0x1048); // hax + } else - memcpy(Key1_KeyBuf, &DSi::ITCMInit[0x4894], 0x1048); // hax + { + memcpy(Key1_KeyBuf, &NDS::ARM7BIOS[0x30], 0x1048); // hax + } u32 keycode[3] = {idcode, idcode>>1, idcode<<1}; if (level >= 1) Key1_ApplyKeycode(keycode, mod); diff --git a/src/SPI.cpp b/src/SPI.cpp index 29f3321..ac40707 100644 --- a/src/SPI.cpp +++ b/src/SPI.cpp @@ -93,7 +93,10 @@ void Reset() if (Firmware) delete[] Firmware; Firmware = NULL; - strncpy(FirmwarePath, Config::FirmwarePath, 1023); + if (NDS::ConsoleType == 1) + strncpy(FirmwarePath, Config::DSiFirmwarePath, 1023); + else + strncpy(FirmwarePath, Config::FirmwarePath, 1023); FILE* f = Platform::OpenLocalFile(FirmwarePath, "rb"); if (!f) @@ -620,7 +623,7 @@ void Reset() SPI_Firmware::Reset(); SPI_Powerman::Reset(); SPI_TSC::Reset(); - DSi_SPI_TSC::Reset(); + if (NDS::ConsoleType == 1) DSi_SPI_TSC::Reset(); } void DoSavestate(Savestate* file) @@ -633,7 +636,7 @@ void DoSavestate(Savestate* file) SPI_Firmware::DoSavestate(file); SPI_Powerman::DoSavestate(file); SPI_TSC::DoSavestate(file); - DSi_SPI_TSC::DoSavestate(file); + if (NDS::ConsoleType == 1) DSi_SPI_TSC::DoSavestate(file); } @@ -647,8 +650,12 @@ void WriteCnt(u16 val) { case 0x0000: SPI_Powerman::Hold = 0; break; case 0x0100: SPI_Firmware::Hold = 0; break; - //case 0x0200: SPI_TSC::DataPos = 0; break; - case 0x0200: DSi_SPI_TSC::DataPos = 0; break; + case 0x0200: + if (NDS::ConsoleType == 1) + DSi_SPI_TSC::DataPos = 0; + else + SPI_TSC::DataPos = 0; + break; } } @@ -674,8 +681,11 @@ u8 ReadData() { case 0x0000: return SPI_Powerman::Read(); case 0x0100: return SPI_Firmware::Read(); - //case 0x0200: return SPI_TSC::Read(); - case 0x0200: return DSi_SPI_TSC::Read(); + case 0x0200: + if (NDS::ConsoleType == 1) + return DSi_SPI_TSC::Read(); + else + return SPI_TSC::Read(); default: return 0; } } @@ -691,8 +701,12 @@ void WriteData(u8 val) { case 0x0000: SPI_Powerman::Write(val, Cnt&(1<<11)); break; case 0x0100: SPI_Firmware::Write(val, Cnt&(1<<11)); break; - //case 0x0200: SPI_TSC::Write(val, Cnt&(1<<11)); break; - case 0x0200: DSi_SPI_TSC::Write(val, Cnt&(1<<11)); break; + case 0x0200: + if (NDS::ConsoleType == 1) + DSi_SPI_TSC::Write(val, Cnt&(1<<11)); + else + SPI_TSC::Write(val, Cnt&(1<<11)); + break; default: printf("SPI to unknown device %04X %02X\n", Cnt, val); break; } diff --git a/src/SPU.cpp b/src/SPU.cpp index 959de12..9f6b107 100644 --- a/src/SPU.cpp +++ b/src/SPU.cpp @@ -155,6 +155,11 @@ Channel::~Channel() void Channel::Reset() { + if (NDS::ConsoleType == 1) + BusRead32 = DSi::ARM7Read32; + else + BusRead32 = NDS::ARM7Read32; + SetCnt(0); SrcAddr = 0; TimerReload = 0; @@ -217,8 +222,7 @@ void Channel::FIFO_BufferData() for (u32 i = 0; i < burstlen; i += 4) { - //FIFO[FIFOWritePos] = NDS::ARM7Read32(SrcAddr + FIFOReadOffset); - FIFO[FIFOWritePos] = DSi::ARM7Read32(SrcAddr + FIFOReadOffset); + FIFO[FIFOWritePos] = BusRead32(SrcAddr + FIFOReadOffset); FIFOReadOffset += 4; FIFOWritePos++; FIFOWritePos &= 0x7; @@ -466,6 +470,11 @@ CaptureUnit::~CaptureUnit() void CaptureUnit::Reset() { + if (NDS::ConsoleType == 1) + BusWrite32 = DSi::ARM7Write32; + else + BusWrite32 = NDS::ARM7Write32; + SetCnt(0); DstAddr = 0; TimerReload = 0; @@ -501,8 +510,7 @@ void CaptureUnit::FIFO_FlushData() { for (u32 i = 0; i < 4; i++) { - //NDS::ARM7Write32(DstAddr + FIFOWriteOffset, FIFO[FIFOReadPos]); - DSi::ARM7Write32(DstAddr + FIFOWriteOffset, FIFO[FIFOReadPos]); + BusWrite32(DstAddr + FIFOWriteOffset, FIFO[FIFOReadPos]); FIFOReadPos++; FIFOReadPos &= 0x3; diff --git a/src/SPU.h b/src/SPU.h index 74a4471..8ab17a0 100644 --- a/src/SPU.h +++ b/src/SPU.h @@ -142,6 +142,9 @@ public: } void PanOutput(s32* inbuf, u32 samples, s32* leftbuf, s32* rightbuf); + +private: + u32 (*BusRead32)(u32 addr); }; class CaptureUnit @@ -196,6 +199,9 @@ public: } void Run(s32 sample); + +private: + void (*BusWrite32)(u32 addr, u32 val); }; } diff --git a/src/frontend/FrontendUtil.h b/src/frontend/FrontendUtil.h index 6b83cbc..099583f 100644 --- a/src/frontend/FrontendUtil.h +++ b/src/frontend/FrontendUtil.h @@ -46,6 +46,15 @@ enum Load_FirmwareBad, Load_FirmwareNotBootable, + Load_DSiBIOS9Missing, + Load_DSiBIOS9Bad, + + Load_DSiBIOS7Missing, + Load_DSiBIOS7Bad, + + Load_DSiNANDMissing, + Load_DSiNANDBad, + // TODO: more precise errors for ROM loading Load_ROMLoadError, }; diff --git a/src/frontend/Util_ROM.cpp b/src/frontend/Util_ROM.cpp index d410550..8116a93 100644 --- a/src/frontend/Util_ROM.cpp +++ b/src/frontend/Util_ROM.cpp @@ -96,6 +96,42 @@ int VerifyDSBIOS() return Load_OK; } +int VerifyDSiBIOS() +{ + FILE* f; + long len; + + // TODO: check the first 32 bytes + + f = Platform::OpenLocalFile(Config::DSiBIOS9Path, "rb"); + if (!f) return Load_DSiBIOS9Missing; + + fseek(f, 0, SEEK_END); + len = ftell(f); + if (len != 0x10000) + { + fclose(f); + return Load_DSiBIOS9Bad; + } + + fclose(f); + + f = Platform::OpenLocalFile(Config::DSiBIOS7Path, "rb"); + if (!f) return Load_DSiBIOS7Missing; + + fseek(f, 0, SEEK_END); + len = ftell(f); + if (len != 0x10000) + { + fclose(f); + return Load_DSiBIOS7Bad; + } + + fclose(f); + + return Load_OK; +} + int VerifyDSFirmware() { FILE* f; @@ -110,7 +146,6 @@ int VerifyDSFirmware() { // 128KB firmware, not bootable fclose(f); - return Load_OK; // FIXME!!!! return Load_FirmwareNotBootable; } else if (len != 0x40000 && len != 0x80000) @@ -124,6 +159,45 @@ int VerifyDSFirmware() return Load_OK; } +int VerifyDSiFirmware() +{ + FILE* f; + long len; + + f = Platform::OpenLocalFile(Config::DSiFirmwarePath, "rb"); + if (!f) return Load_FirmwareMissing; + + fseek(f, 0, SEEK_END); + len = ftell(f); + if (len != 0x20000) + { + // not 128KB + // TODO: check whether those work + fclose(f); + return Load_FirmwareBad; + } + + fclose(f); + + return Load_OK; +} + +int VerifyDSiNAND() +{ + FILE* f; + long len; + + f = Platform::OpenLocalFile(Config::DSiNANDPath, "rb"); + if (!f) return Load_DSiNANDMissing; + + // TODO: some basic checks + // check that it has the nocash footer, and all + + fclose(f); + + return Load_OK; +} + int LoadBIOS() { int res; @@ -131,8 +205,22 @@ int LoadBIOS() res = VerifyDSBIOS(); if (res != Load_OK) return res; - res = VerifyDSFirmware(); - if (res != Load_OK) return res; + if (Config::ConsoleType == 1) + { + res = VerifyDSiBIOS(); + if (res != Load_OK) return res; + + res = VerifyDSiFirmware(); + if (res != Load_OK) return res; + + res = VerifyDSiNAND(); + if (res != Load_OK) return res; + } + else + { + res = VerifyDSFirmware(); + if (res != Load_OK) return res; + } // TODO: // original code in the libui frontend called NDS::LoadGBAROM() if needed @@ -142,6 +230,7 @@ int LoadBIOS() ROMPath[ROMSlot_NDS][0] = '\0'; SRAMPath[ROMSlot_NDS][0] = '\0'; + NDS::SetConsoleType(Config::ConsoleType); NDS::LoadBIOS(); SavestateLoaded = false; @@ -154,16 +243,39 @@ int LoadROM(const char* file, int slot) int res; bool directboot = Config::DirectBoot != 0; + if (Config::ConsoleType == 1 && slot == 1) + { + // cannot load a GBA ROM into a DSi + return Load_ROMLoadError; + } + res = VerifyDSBIOS(); if (res != Load_OK) return res; - res = VerifyDSFirmware(); - if (res != Load_OK) + if (Config::ConsoleType == 1) { - if (res == Load_FirmwareNotBootable) - directboot = true; - else - return res; + res = VerifyDSiBIOS(); + if (res != Load_OK) return res; + + res = VerifyDSiFirmware(); + if (res != Load_OK) return res; + + res = VerifyDSiNAND(); + if (res != Load_OK) return res; + + GBACart::Eject(); + ROMPath[ROMSlot_GBA][0] = '\0'; + } + else + { + res = VerifyDSFirmware(); + if (res != Load_OK) + { + if (res == Load_FirmwareNotBootable) + directboot = true; + else + return res; + } } char oldpath[1024]; @@ -177,6 +289,8 @@ int LoadROM(const char* file, int slot) SetupSRAMPath(0); SetupSRAMPath(1); + NDS::SetConsoleType(Config::ConsoleType); + if (slot == ROMSlot_NDS && NDS::LoadROM(ROMPath[slot], SRAMPath[slot], directboot)) { SavestateLoaded = false; @@ -225,17 +339,36 @@ int Reset() res = VerifyDSBIOS(); if (res != Load_OK) return res; - res = VerifyDSFirmware(); - if (res != Load_OK) + if (Config::ConsoleType == 1) { - if (res == Load_FirmwareNotBootable) - directboot = true; - else - return res; + res = VerifyDSiBIOS(); + if (res != Load_OK) return res; + + res = VerifyDSiFirmware(); + if (res != Load_OK) return res; + + res = VerifyDSiNAND(); + if (res != Load_OK) return res; + + GBACart::Eject(); + ROMPath[ROMSlot_GBA][0] = '\0'; + } + else + { + res = VerifyDSFirmware(); + if (res != Load_OK) + { + if (res == Load_FirmwareNotBootable) + directboot = true; + else + return res; + } } SavestateLoaded = false; + NDS::SetConsoleType(Config::ConsoleType); + if (ROMPath[ROMSlot_NDS][0] == '\0') { NDS::LoadBIOS(); diff --git a/src/frontend/qt_sdl/EmuSettingsDialog.cpp b/src/frontend/qt_sdl/EmuSettingsDialog.cpp index 7760a88..09faf4e 100644 --- a/src/frontend/qt_sdl/EmuSettingsDialog.cpp +++ b/src/frontend/qt_sdl/EmuSettingsDialog.cpp @@ -49,7 +49,7 @@ EmuSettingsDialog::EmuSettingsDialog(QWidget* parent) : QDialog(parent), ui(new ui->txtDSiNANDPath->setText(Config::DSiNANDPath); ui->cbxConsoleType->addItem("DS"); - ui->cbxConsoleType->addItem("DSi"); + ui->cbxConsoleType->addItem("DSi (experimental)"); ui->cbxConsoleType->setCurrentIndex(Config::ConsoleType); ui->chkDirectBoot->setChecked(Config::DirectBoot != 0); diff --git a/src/frontend/qt_sdl/main.cpp b/src/frontend/qt_sdl/main.cpp index ef21bc7..7b3d5cd 100644 --- a/src/frontend/qt_sdl/main.cpp +++ b/src/frontend/qt_sdl/main.cpp @@ -1360,17 +1360,40 @@ QString MainWindow::loadErrorStr(int error) { switch (error) { - case Frontend::Load_BIOS9Missing: return "DS ARM9 BIOS was not found or could not be accessed. Check your emu settings."; - case Frontend::Load_BIOS9Bad: return "DS ARM9 BIOS is not a valid BIOS dump."; - - case Frontend::Load_BIOS7Missing: return "DS ARM7 BIOS was not found or could not be accessed. Check your emu settings."; - case Frontend::Load_BIOS7Bad: return "DS ARM7 BIOS is not a valid BIOS dump."; - - case Frontend::Load_FirmwareMissing: return "DS firmware was not found or could not be accessed. Check your emu settings."; - case Frontend::Load_FirmwareBad: return "DS firmware is not a valid firmware dump."; - case Frontend::Load_FirmwareNotBootable: return "DS firmware is not bootable."; - - case Frontend::Load_ROMLoadError: return "Failed to load the ROM. Make sure the file is accessible and isn't used by another application."; + case Frontend::Load_BIOS9Missing: + return "DS ARM9 BIOS was not found or could not be accessed. Check your emu settings."; + case Frontend::Load_BIOS9Bad: + return "DS ARM9 BIOS is not a valid BIOS dump."; + + case Frontend::Load_BIOS7Missing: + return "DS ARM7 BIOS was not found or could not be accessed. Check your emu settings."; + case Frontend::Load_BIOS7Bad: + return "DS ARM7 BIOS is not a valid BIOS dump."; + + case Frontend::Load_FirmwareMissing: + return "DS firmware was not found or could not be accessed. Check your emu settings."; + case Frontend::Load_FirmwareBad: + return "DS firmware is not a valid firmware dump."; + case Frontend::Load_FirmwareNotBootable: + return "DS firmware is not bootable."; + + case Frontend::Load_DSiBIOS9Missing: + return "DSi ARM9 BIOS was not found or could not be accessed. Check your emu settings."; + case Frontend::Load_DSiBIOS9Bad: + return "DSi ARM9 BIOS is not a valid BIOS dump."; + + case Frontend::Load_DSiBIOS7Missing: + return "DSi ARM7 BIOS was not found or could not be accessed. Check your emu settings."; + case Frontend::Load_DSiBIOS7Bad: + return "DSi ARM7 BIOS is not a valid BIOS dump."; + + case Frontend::Load_DSiNANDMissing: + return "DSi NAND was not found or could not be accessed. Check your emu settings."; + case Frontend::Load_DSiNANDBad: + return "DSi NAND is not a valid NAND dump."; + + case Frontend::Load_ROMLoadError: + return "Failed to load the ROM. Make sure the file is accessible and isn't used by another application."; default: return "Unknown error during launch; smack Arisotura."; } -- cgit v1.2.3