I recently got myself a JXD A1000 and found it quite an enjoyable device to develop for. The "official" API ("native game" interface) isn't any fun, though: Fixed screen size of 320x240, no access to all but three buttons, no support for generated audio, no access to the ROM file system, not even a way to list directories.
The firmware is, of course, able to do much better than that, but while all the functionality is there, we don't know how to access it: function and memory addresses are different from device to device and from firmware revision to firmware revision. While it was easy to adapt, for instance, Triple Oxygen's libemu for the Cybergame to my A1000 to get sound support, the result would again only run on a single machine. I didn't really want to spend a lot of time developing software that won't run on other people's systems, so I did some thinking and came up with a solution: On-the-fly firmware reverse-engineering.
Whenever I found something interesting in the firmware, I devised a simple heuristic that weasels its way through the running operating system, usually starting from a function the address of which we know because it's part of the "official" interface, and taking advantage of typical subroutine calls, address loads, debug strings, and function table offsets to get to the sweet stuff in a way that works on all SPMP8000 firmwares. To check that it really does work everywhere I availed myself of eleven different firmwares (and an additional JXD 100) and wrote a test harness that verifies that the heuristic actually arrives at the right spot.
The result is a library that provides you with a greatly extended API in a portable fashion, so your programs will (hopefully) run on any SPMP8k device. Here's the stuff you couldn't get before:
- Emulator interface: This is the API used by the built-in emulators. It provides hardware scaling from arbitrary resolutions, access to all keys on all controllers (both raw scan codes and standardized mappings), and streaming audio.
- Frame buffer access: Direct access to the currently active display device's frame buffers, with support for single and double buffering.
- eCos POSIX-like file API: Access to all files without restrictions or filtering. Full set of directory functions. (Seriously, with the official API you can't even read a directory!) I have glued this interface to newlib, so you can use stdio functions (fopen() etc.).
- High-resolution timer: The official API gives you mere 100 Hz; with the new libgame_utime(), you can get microsecond resolution. Indispensable for accurate speed and profiling.
- CPU scaling: Saves battery power, you can go down as low as 5 MHz. (Sorry, no overclocking.)
- Built-in fonts: A few simple routines I wrote to use the bitmap fonts in ROM. Not as black magic as the other stuff, but with full Unicode support. :)
There's more stuff in there, like the mysterious SPMP_SendSignal() function that takes dozens of commands, or the eCos threading interface, that I will unearth as needed. I also more or less worked out the signatures of all the as-yet undocumented functions in both the "native game" and the emulator API, if you want to experiment a little.
Using this souped-up libspmp8k, I have ported
PC Engine emulator TGEmu, and it runs like hell
(after some optimization) on both the JXD A1000 and 100, and probably on your SPMP8000 device, too. Check it out! (You need PC Engine ROMs, of course. Uncompressed, zipped, and gzipped files are supported.)
The source code should also give you a good idea of how to use the library. Have fun!