Thursday, November 15, 2012

Better SPMP8000 Homebrewing (and PC Engine emulator!)

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!


  1. Hello friend, thank you for this thing!

    I put this at the forum, we love SPMP8k

  2. Good!

  3. Hi! Sorry for my bad English(
    Its realy cool. Emulator works very good. Some games are not working, but most of games playing perfectly. Thank you for this great work!!!
    Maybe you can port some new emus, for example java or ps1 emulator. Or maybe you can do some alternative player or pdf reader? It will be great!

  4. PC Engine emulator works well on devices with ~ 350 MHz overclock, and checked on the JXD 1000
    [emuIfGraphInit (0046ef74) returns 00000000
    Framebuffer 01e81540, shadow buffer 01dc78b0
    Width 480, Height 272
    LCD format 00000000
    ARM frequency 348000000
    system ID 2
    emuIfSoundInit returns 0, sp.rate 44010

    SPMP8000A devices also works well

    my problem with hanging JXD 1000 - the fault of the native font that I always cut
    \ MW \ FONTS \ SUNPLUS - if this folder is empty, or use an alternative font that you should return to the place native font

    we are waiting for new news
    sorry for my english

    1. just committed a quick fix for that to git (untested)

  5. Thank you very much for the great emulator console! There are complaints on compatibility, unfortunately emulator on my console (Defender MultiMix Magic Russian clone - MiShark64 \ LetCool) does not run many games. The emulator does not support many of my buttons - R, L, Vol - +, Hold, can I add them? And whether other emulators, such as ZX Spectrum and Java? Now a lot of phones with touch and play hits such as asphalt and Gravity Defide not! PS From Russia with love. Sorry for my english. Google translate helped me.

  6. Cool! I'm also have "Defender MultiMix Magic" is Russian clone of MiShark64 \ LetCool. I want to test your new emu's. Start to tgemu-r163.bin - some games workd fine, but some not. Looks fine like Bomberman, Bomberman '93 and other. Graphical problems with Bonk's Revenge. Darkwind Duck didn't start even. I wonder how I can be useful? May be you can say what to do?

    I also want to say that one real thing is need to play. It's a saving slot. Could it be done?

    Sorry for my english :) and have a nice day!

  7. your emulators works great on my Letcool : ).. tanks.. can you doo the multi player function for this?

  8. this firmware is running in letcool nj350 ?