#44799 - Dark Knight ez - Sun Jun 05, 2005 2:33 pm
I've coded the interface and some other parts of a backup program that lets one store NDS saves on a GBA flashcard, and also to write it back. I ran into a few problems though, since I'm new to coding C and coding for NDS, so I was wondering if you guys could help me out on these issues.
First of all, it was recommended to use this line of code
Code: |
if (memcmp((void*)0x080000AC, "PASS", 4) == 0) {} |
However, I don't know where the function memcmp is stored, and how to 'link' to it. Could you give me a quick how-to on that?
Further more, I've noticed that in ndslib with the cardReadEeprom and cardWriteEeprom functions, there is a comment in its proximity directed at darkfader on fixing some stuff. Do the two functions I just mentioned require any fixing before I can use them, or do they work properly yet?
With cardWriteEeprom it is noted that it doesn't work for small Eeproms. How small are we talking about here? It could affect some of my code. Does the same apply to cardReadEeprom?
Further more, if anyone of you would be willing to review my code so far, I'd be ever so grateful. I've been programming in Java for quite some time, but most of what I've done so far in this program right now was guesswork and copy-paste (built in a day), but it all seems to work so far (tested it on hardware). Especially the (so far) actual saving and back-up part will need checking, since those are the only parts that could cause unwanted 'damage'.
Thanks in advance,
Dark Knight ez.
P.S.
This is a link to the current source for this project, so you could review it / look it through. I'd really appreciate it.
http://www.few.vu.nl/~ssstolk/temp/main.cpp
#44804 - tepples - Sun Jun 05, 2005 4:11 pm
memcmp() is in libc, which is linked by default to all programs. To bring in its prototype, do #include <string.h> (in C) or #include <cstring> (in C++).
Based on what I know about EEPROM save on the GBA, I'm guessing that the smaller EEPROMs might require a shorter address to be sent.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#44807 - strager - Sun Jun 05, 2005 5:03 pm
A faster method is to compare it as if it were an integer:
Code: |
if(*(u32 *)(0x080000AC) == (u32)('PASS')) {} |
Or you could pack into a define. It confuses me on why people don't use this method...
#44809 - Dark Knight ez - Sun Jun 05, 2005 6:40 pm
That particular line of code causes the warning "multi-character character constant", when I try to build it. Probably due to comparing a (u32) with a (u32 *), or something.
I guess I'll use the include for now, unless you could give a non-warning giving version of that.
Thanks to both of you.
Would still like information on the other issues.
#44810 - tepples - Sun Jun 05, 2005 6:52 pm
strager wrote: |
A faster method is to compare it as if it were an integer:
Code: | if(*(u32 *)(0x080000AC) == (u32)('PASS')) {} |
Or you could pack into a define. It confuses me on why people don't use this method... |
Several reasons: - The value of a multicharacter literal is implementation-defined. You can't be sure whether a particular toolchain will need 'PASS' or 'SSAP' without reading the manual every time you upgrade; in fact, GCC breaks the C standard by failing to document its behavior.
- A lot of people don't know of the -Wno-multichar option to suppress the warning that Dark Knight ez mentions.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#45182 - Dark Knight ez - Wed Jun 08, 2005 10:35 am
I just realised that this save backup program isn't all that useful. For savefiles of the size of 512 bytes, you'd already need 10 runs (saving 56 bytes per run with this program), which is kind of doable, but for savegames larger than that.... it would be madness.
Unless someone knows how to be able to save way larger chunks of data on the gba flashcard's sram, this program will be useless. (Although I still intend to use it for a specific game I own, with a savesize of 512 bytes.)
Further more, I've had a glance at the NDS Tech Wiki on the DS card registers for writing and reading a savegame, and now I understand why ndslib mentioned "fixing" of the write and read functions: the functinos of the registers aren't fully understood, it seems (or not yet updated at the site).
#45213 - josath - Wed Jun 08, 2005 6:05 pm
Dark Knight ez wrote: |
I just realised that this save backup program isn't all that useful. For savefiles of the size of 512 bytes, you'd already need 10 runs (saving 56 bytes per run with this program), which is kind of doable, but for savegames larger than that.... it would be madness. |
I don't see a problem, ever heard of 'for' loops?
#45227 - wintermute - Wed Jun 08, 2005 8:44 pm
tepples wrote: |
strager wrote: | A faster method is to compare it as if it were an integer:
Code: | if(*(u32 *)(0x080000AC) == (u32)('PASS')) {} |
Or you could pack into a define. It confuses me on why people don't use this method... |
Several reasons: - The value of a multicharacter literal is implementation-defined. You can't be sure whether a particular toolchain will need 'PASS' or 'SSAP' without reading the manual every time you upgrade;
|
the order of multichar literals has nothing to do with implementation, it's defined by the endianness of the system.
Quote: |
in fact, GCC breaks the C standard by failing to document its behavior. A lot of people don't know of the -Wno-multichar option to suppress the warning that Dark Knight ez mentions. |
given that gcc is a multisystem compiler and works in the endianness of the system you're compiling for, I fail to see how gcc can document this.
code for the DS
Code: |
if(*(u32 *)(0x080000AC) == (u32)('SSAP')) {} |
it's little endian. Stragers method will obviously only work on big endian systems.
#45230 - natrium42 - Wed Jun 08, 2005 8:51 pm
Bah, you can always do this if unsure:
Code: |
if(*(u32 *)(0x080000AC) == (u32)('SSAP') || *(u32 *)(0x080000AC) == (u32)('PASS')) {} |
Who cares about some demo named "SSAP" :P
_________________
www.natrium42.com
#45232 - strager - Wed Jun 08, 2005 9:05 pm
wintermute wrote: |
Code: | if(*(u32 *)(0x080000AC) == (u32)('SSAP')) {} |
it's little endian. Stragers method will obviously only work on big endian systems. |
Like DOS :-)
You could just add a bit in the IPC->buttons (bit 7?) that signals that it is OK to write to SRAM. It would save a few instructions (maybe) and speed the code up (maybe), but it will have its cons (haven't found any yet but more work for the ARM7).
No matter. Anyone can use whichever method they choose. It's not like it is required to have super-optimized memcmp.
#45236 - dagamer34 - Wed Jun 08, 2005 9:39 pm
strager wrote: |
wintermute wrote: | Code: | if(*(u32 *)(0x080000AC) == (u32)('SSAP')) {} |
it's little endian. Stragers method will obviously only work on big endian systems. |
Like DOS :-)
You could just add a bit in the IPC->buttons (bit 7?) that signals that it is OK to write to SRAM. It would save a few instructions (maybe) and speed the code up (maybe), but it will have its cons (haven't found any yet but more work for the ARM7).
No matter. Anyone can use whichever method they choose. It's not like it is required to have super-optimized memcmp. |
It would still need to be checked every second or so, as to prevent from writing to a commercial game's SRAM if the game pak is swapped for some odd reason.
_________________
Little kids and Playstation 2's don't mix. :(
#45237 - Diskun - Wed Jun 08, 2005 9:47 pm
dagamer34 wrote: |
It would still need to be checked every second or so, as to prevent from writing to a commercial game's SRAM if the game pak is swapped for some odd reason. |
Why bother? Every game that uses save function reads "Don't switch off your DS nor remove the game card from the slot" (or whatever). If the user swaps the game during the backup process is HIS problem, not the coder's.
Do it easy.
#45262 - tepples - Thu Jun 09, 2005 3:00 am
wintermute wrote: |
tepples wrote: | The value of a multicharacter literal is implementation-defined. You can't be sure whether a particular toolchain will need 'PASS' or 'SSAP' without reading the manual every time you upgrade; |
the order of multichar literals has nothing to do with implementation, it's defined by the endianness of the system. |
The C standard states that the value is implementation defined. A compiler is free to turn 'PASS' into 'P' 'A' 'S' 'S', 'S' 'S' 'A' 'P', or anything else, as long as the manual documents the behavior. The endianness of the system doesn't matter for this purpose.
Quote: |
given that gcc is a multisystem compiler and works in the endianness of the system you're compiling for, I fail to see how gcc can document this. |
I would expect something to the effect of the following: "On SYSTEM1, SYSTEM2, and SYSTEM3, multicharacter literals are packed with earlier character codes in more significant bits. On SYSTEM4, SYSTEM5, and SYSTEM6, multicharacter literals are packed with earlier character codes in less significant bits."
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#45271 - wintermute - Thu Jun 09, 2005 3:42 am
mkay, apologies. I seem to have been mixing up system memory behaviour with the compiler behaviour and assumed that multi-char literals were placed in the register with the first character as msb.
http://gcc.gnu.org/onlinedocs/cpp/Implementation_002ddefined-behavior.html
#45319 - Dark Knight ez - Thu Jun 09, 2005 4:38 pm
josath wrote: |
Dark Knight ez wrote: | I just realised that this save backup program isn't all that useful. For savefiles of the size of 512 bytes, you'd already need 10 runs (saving 56 bytes per run with this program), which is kind of doable, but for savegames larger than that.... it would be madness. |
I don't see a problem, ever heard of 'for' loops? |
Yes, but I don't know how to allocate more size for saving purposes on the gba flashcard's sram, than 64bytes... nor how to address it. Didn't I mention that somewhere in this post?
If there's a way to do that, then yes, I could use a for-loop for example.
edit:
My bad. Stupid me. GBA saveram is usually 64 Kbytes, not 64 bytes.
*whaps self*