gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > emulator/hardware build tip

#59573 - SevenString - Wed Nov 02, 2005 7:12 pm

I came up with what I think is a cool way to deal with emu vs. hardware issues. Let me tell you up front that I am already using these methods, so I'm not just posting some "wishful thinking" thing.

Like everyone else, I don't want to have to swap cards in and out of my PC and GBAMP, plus all of the rebooting and such, everytime I want to test some tiny little change in my code. So for little changes, I test with an emulator.

Well, my application CAN run in an emulator, but some of the graphics are displayed incorrectly, and I'm using multiple audio resolutions that aren't supported in emulation.

Also, because I'm doing 3d (objects, textures, etc), a lot of audio, and a lot of full-screen 2D pieces, the data for multiple "levels" is rapidly approaching the 4MB ram boundary, and the emulator that I'm using does not support emulated FAT file access (even on a FAT drive).

So here's what I've done: I've set things up so that all file access goes through a few wrapper functions that use a compile-time definition to determine the actual internal methods for file access.

If I have defined "COMPILE_FOR_HW", the internal methods use the FAT file system. However, by defining "COMPILE_FOR_EMU", file access is through GBFS. Also, before accessing the GBFS file, I strip out the folders from the filepath, since GBFS compilation produces a flat structure.

Since GBFS IS a flat structure, my file naming convention insures that every filename is unique. For instance, all files in the textures folder begin with "texture_".

Finally, when I'm finished with the data returned by a "file read", I call a custom function called "my_free" to clean up the data. Within that custom function, if COMPILE_FOR_EMU is defined, I know that I'm using GBFS, which returned a pointer the static file data living in memory. In this case, I do nothing and return. However, if COMPILE_FOR_HW is defined, I know that I actually did some data reading from a FAT file into newly allocated buffer, so some memory actually needs freeing: time to call the standard "free" function, then return.

Now, for the makefile, I use the same flags, and only compile/append the GBFS file to the executable if I am doing an EMU build. This works pretty well for those tests that require a quick turnaround. Also, in the future, if it turns out that the emulator DOES emulate the 4MB limit, I'll set things up so that only a subset of the data will be appended to the executable.

Note that although my MAIN usage of these flags is to support GBFS on the emulator and FAT on actual hardware, these flags can also be used in other parts of the code to reconcile differences between your emulator and hardware.

For instance, the iDeaS emulator has a bug in the SQRT functionallity that causes warping during a gl rotation about an arbitrary axis. I've set up alternative calls in my version of libnds, called "sqrtf32_iDeaS" and "glRotatef_iDeaS" that are invoked by my code based on the target (hardware or emu).

Code:
#ifdef COMPILE_FOR_HW
    glRotatef(angle, x, y, z);
#else
    glRotatef_iDeaS(angle, x, y, z);
#endif



So over the past couple of days, I've already been saving a lot of time because I can use the emulator for a large portion of my coding and testing, and only go to the hardware as needed. And I can now switch back and forth between build types by changing a single #define.

I hope these ideas will help anyone who's interested.
_________________
"Artificial Intelligence is no match for natural stupidity."