Cibyl

From SpelWiki

Boulder Dash-style game for Cibyl (ported from Mophun). Also shows part of the implementation
Enlarge
Boulder Dash-style game for Cibyl (ported from Mophun). Also shows part of the implementation
A screenshot from the Cibyl port of Sarien.
Enlarge
A screenshot from the Cibyl port of Sarien.

Cibyl is a programming environment and binary translator that allows compiled C programs to execute on J2ME-capable phones. Cibyl uses GCC to compile the C programs to MIPS binaries, and these are then recompiled into Java bytecode. Cibyl programs are regular compiled Java programs, and Cibyl therefore performs relatively well. Cibyl is an abbreviation of something, but only the C, meaning C has been fixed so far.

With Cibyl, C programs can be ported to J2ME without switching language. It also allows C and Java code to be integrated in an easy and efficient way. The environment uses the GNU compiler tools (GCC and binutils) and should work in all environments which provide a GNU toolchain.

There are three reasons why I want Cibyl. First, C is in my opinion a much better suited language for writing games than Java. Also, since I have a couple of old games written in C, I would like to port them to the J2ME environment without rewriting the entire games (which I have also done with Lessphun). The goal is to be able to get by without porting the game to another language. Finally, I find it a nice intellectual past time which combines my favorite areas compilers, low-level programming and performance.

Contents

Topics

These pages contain information about how Cibyl works, how to build and run programs and reference usage of the tools. Simon's blog also contains journal entries about Cibyl internals.

Showcases

Ehud Shabtai has ported RoadMap to J2ME phones using Cibyl. The J2ME version supports GPS navigation and 3D map display among other things
Enlarge
Ehud Shabtai has ported RoadMap to J2ME phones using Cibyl. The J2ME version supports GPS navigation and 3D map display among other things

Some quotes and links about Cibyl found on the net:

"Verdens mest kompliserte tilnærming for å lage J2ME applikasjoner" (www.java.no). If you don't read norwegian, it means basically "The world's most complex way of making J2ME applications".
"La forma mas complicada del mundo de programar en Java" (http://www.xatakamovil.com/2007/12/28-10-programas-asombrosos). A spanish article quite simiar to the Norwegian above. Well, at least the title is :-)
"Utterly bizarre cool idea: a translator from MIPS binaries to Java bytecode, so that you can compile C to the JVM using GCC" (http://del.icio.us/azz)
"This is the single most interesting thing I've seen in quite a long time" (Thygrr, www.j2meforums.com)
"Zajímavost pro programátory je prostředí Cibyl 9, které je určeno těm, kteří chtějí tvořit aplikace, či hry pro mobilní telefony zvládající J2ME, ale nechtějí se učit Javu." (Linuxsoft.cz) I don't understand a word of it, I hope it's not overly negative! ;-)
www.penguin.cz: Cibyl in the program news on another Czech site

Short example program

Simple example program for Cibyl
Enlarge
Simple example program for Cibyl
#include <javax/microedition/lcdui.h>

int main(int argc, char *argv[])
{
  NOPH_GameCanvas_t canvas = NOPH_GameCanvas_get();
  NOPH_Graphics_t graphics = NOPH_GameCanvas_getGraphics(canvas);

  /* Select red pen, then draw a line */
  NOPH_Graphics_setColor(graphics, 255,0,0);
  NOPH_Graphics_drawLine(graphics, 10, 10, 50, 50);

  NOPH_GameCanvas_flushGraphics(canvas);
  return 0;
}

Technology overview

Cibyl is based on the beautiful MIPS1 instruction set and uses GCC for compiling C source. The MIPS instructions are not decoded and parsed during runtime, but instead recompiled into Java bytecode at build-time. The overhead should therefore be small and the goal is to achieve similar performance of code written in C to a native Java implementation.

The API is called through special instruction encodings to get good efficiency. Cibyl also allows for semi-automatic generation of calls to native Java functionality.

The technology used in Cibyl is very similar to that in NestedVM, which also recompiles MIPS binaries into Java .class-files although they are completely unrelated code-wise. Note: I've seen somewhere on the web the statement that Cibyl predates NestedVM. This is not true, NestedVM came before Cibyl, but I was unaware of it until I had implemented quite a bit of Cibyl. The two projects are quite different, but I've tried to use good ideas from NestedVM whenever possible, and hope the same can be true in the other direction as well.

Compiler technology

The cibyl-mips2java compiler generates Java assembly for compilation with jasmin from the binary MIPS executable. Parts of the MIPS binary parser has been rewritten (into C++) from the Java MIPS emulator written for the topsy operating system. Some notes about the compilation:

  • Extra arguments need to be supplied: -mno-check-zero-division, -fno-pic, -mno-abicalls. These simplify certain things (i.e., no trap on div-by-zero, no position-independent code etc.)
  • A simple linker script that places the sections for easy parsing is used
  • The cibyl-mips2java tool recompiles the binary output into Java assembly
  • crt0.S initializes the C runtime and needs to be linked against by the C application.

Architectural model

There are some simplifications of the MIPS instruction set employed in Cibyl. Only instructions accessible in userspace (i.e., no coprocessor updates etc) are allowed, and nop instructions generate no code. Cibyl stores the memory contents in an integer-vector and registers as local variables. The instructions are recompiled into Java bytecode which update the registers and memory contents directly.

  • The file containing the data (resource in J2ME) starts with some setup information (stack size, bss size etc.) at address 0
  • The data segment is mapped to address 0x16 (to keep NULL == 0 and alignment)
  • syscalls translate into calls of Java functions. Arguments are passed via special instruction encodings
  • Java objects are stored in a table and passed via integer handles to C. When a Java object is created, an integer handle for it is registered and a mapping between the handle and the object is stored in the table.

System calls

Cibyl supports easy adaptation to different Cibyl APIs. Currently, subsets of the MIDP 2.0 and ANSI C APIs have been implemented. I will add functionality to the APIs as I go. The MIDP C API looks like

typedef int NOPH_Sprite_t;
... 
NOPH_Sprite_t NOPH_Sprite_new_image(NOPH_Image_t image);
NOPH_Sprite_t NOPH_Sprite_new_imageSize(NOPH_Image_t image, int width, int height);
NOPH_Sprite_t NOPH_Sprite_new_sprite(NOPH_Sprite_t sprite);
...

Integer handles are used to pass Java objects along. The cibyl-generate-c-header and cibyl-generate-java-wrappers tools goes through the syscall files and generates a C header and a Java class which defines the system calls and generates wrapper calls for the MIDP API.

Help needed!

  • Run the Cibyl test cases on your mobile phone: This is the easiest way of helping out - you don't even have to install Cibyl to do the tests!

A partial list of things to be done in the development can be found below. Feel free to contribute these!

  • Extend the API, most of J2ME is missing
  • Replace the ANSI C environment with uClibc or newlib (where possible)
  • Use MIPS32 instead of MIPS1 (R3000) as the target of compilation
    • MIPS32 has some useful extra instructions: movn (conditional move) and mul (32-bit multiply)
  • Nicer build-environment and less GNU/Linux dependencies. SCons?
    • Make Cibyl installable in /usr/local or similar
    • Integration with e.g., Eclipse
  • Other languages (ObjC/Fortran/?)
    • Runtime libraries needed
    • PyPy?
  • Optimization:
    • Better implementation of library routines, especially memcpy (though it can often be inlined efficiently)

Download

Cibyl is released under the GNU GPL and LGPL licenses. The tools (e.g., cibyl-mips2java) are released under GPL while the Java libraries are LGPL. Cibyl is managed on googlecode at http://cibyl.googlecode.com

Contact

Simon Kågström is the author of Cibyl. Contact him at simon.kagstrom@gmail.com. He has a blog at http://simonkagstrom.livejournal.com, where he sometimes will post Cibyl stuff.