Compiling phoneME in 2021
10 Apr 2021
It was by sheer luck that I bumped into this J2ME emulator for the GP2X & Wiz consoles, developed by zaxxon. It seemed remarkably complete and I had not been aware of the project, so I begen to dig a bit deeper.
As it turns out, phoneME was Sun Microsystems’ implementation of Java ME, including the CLDC virtual machine and MIDP 2.0 APIs (but also the heavier CDC, and other JSR APIs). Notably, unlike Sun’s earlier KVM (Kilobyte Virtual Machine, the implementation built into many feature phones in the early-to-mid 2000s), phoneME is licensed under the GNU GPL. phoneME was hosted on java.net, and when that website was shut down by Oracle, it seems to have all but disappeared from the face of the earth. Add to this the fact that searching the web for phoneme yields millions of irrelevant results and the quest for building the emulator seems almost hopeless. Fortunately, XerShadowTail has shared a complete dump of the entire SVN repository, with branches, history and all.
While the compressed dump is only about 64 MB, the full check-out is like 80 gigabytes (though this is mostly an artifact of how branches and tags in SVN work).
Revision #0 is dated October 12, 2006 and the first code (labeled phoneME OSS - b01
) was commited in November of the same year. It is clear that this was a pre-existing codebase, but so far I haven’t tried to find out more about its history. The final commit, r20547, dates to 2011-06-15, 06:17:37 UTC.
The release “phoneme_feature-mr2-rel-b23”, which serves as base for zaxxon’s emulator, dates to May 9, 2007 (r5524).
Build it!
Now that we have the code, we can try to see how buildable it is. I opted to first try the GP2X SDL version; although it is not based on phoneME’s latest version, it is an exact snapshot of something that was released to users, and it has all the ingredients for not only an ARM build, but also i386. That’s right, i386, as in 32-bit. Similar to KVM, the phoneME codebase makes many assumptions about the target (and host!) CPU being 32-bit: for example, pointers are being cast to int
and back without second thought. And then there is of course the VM interpreter loop written in i486 assembly.
Since we strictly need a 32-build environment, I opted to grab an image of Debian 6 (squeeze) from here. This release, which comes with kernel 2.6.32, predates all Vagrants, Dockers, and the other nifty automation tools that we have come to love. In fact, additional packages are installed from physical media by default!
Making the Debian 6 apt
work in the current decade was an adventure of its own, due to expired signing keys. I set up a build environment in a virtual machine, checked out the code and attempted to compile it. After some trivial-ish failures and fixes, I ran into this error
../../romgen/app/romgen -cp /home/user/phoneme_feature/build_output/cldc/classes.zip +GenerateGNUCode =HeapCapacity16M -romconfig /home/user/phoneme_feature/cldc/src/vm/cldctest_rom.cfg -romincludepath /home/user/phoneme_feature/cldc/src/vm +RewriteROMConstantPool +EnableAllROMOptimizations -romize
#
# VM Error, assertion failure
#
# Error ID: /home/user/phoneme_feature/cldc/src/vm/share/runtime/JVM.cpp, 322
#
# assert(JVMAssemblerLoopFlags::GeneratedInterpreterLoop(), "Must have a real interpreter loop")
#
After more fumbling around, it still didn’t make any sense. However, phoneME history indicates that GCC 4.x support was only added after the b23 release. It would seem that our build environment is not ancient enough:
user@debian:~$ gcc -v
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.4.5-8' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.4 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-targets=all --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu
Thread model: posix
gcc version 4.4.5 (Debian 4.4.5-8)
Attempt II
This time around, I wasn’t going to risk anything. The OS is 32-bit Debian 5 (Lenny) and compiler GCC 3.4, built from source. The goal is to get a reliably reproducible procedure for compiling a working emulator.
It took many hours, but finally – success! Some interesting lessons have been learned along the way. I have captured the necessary steps in this git repository. You will also need to download and decompress my Debian Lenny base image, which is basically just the most-default Debian installation + a SSH server.
The steps needed are, roughly:
- Install GCC 4.whatever as packaged by Debian
- Compile GCC 3.4.6 from source
- Use GCC 3 to compile SDL, SDL_image and SDL_mixer (1.2.x)
- Use GCC 3 to compile phoneME for i386
- Modify the kernel boot options to set a 16-bit 640x480 video mode (
vga=0x311
)
Future
After this, I decided to take a break; however, I plan to revisit the project in the future. It would be cool to have a codebase that works both on desktop PCs (perhaps as a libretro core) and small embedded devices without relying on a full JVM. I imagine these could be the next steps:
- Rebase the SDL front-end onto a later phoneME release or even SVN trunk
- Try progressively newer GCC/binutils/glibc versions, fixing issues along the way
- Also try to build the emulator on an 64-bit host
- Build also for 32-bit ARM Linux using a modern toolchain
- Later worry about details like MIDI support and user experience
In the meantime I have learnt of bittboy-j2me, which is a recent re-incarnation of the phoneME codebase and definitely deserves some investigation. bittboy-j2me is using CDC VM & MIDPath (while the GP2X port uses CLDC with phoneME’s MIDP implementation) – it should be interesting to compare game compatibility between the two.