CONTENTS

Home
News
Software
Electronics
Android / iOS
Music
Resume
Contact





Java Grinder

Posted: January 05, 2014
Updated: May 20, 2015

Introduction

Java Grinder is a Java byte-code compiler similar to a JIT (just in time compiler.. actually this more like an ahead of time compiler (AOT)) but instead of being a part of a JVM Java Grinder will compile classes into an assembly language text file. I started out with MSP430 and dsPIC (examples below) creating both an assembly generator and a Java API for doing things like SPI, GPIO, A/D conversion, and more. Joe Davisson (who did the 6502/6510 assembler in naken_asm) added a 6502/6510 generator and the API for making Commodore 64 programs. Joe has also been helping me fix bugs and added mul/div support for the MSP430. I recently added 68000 / Sega Genesis and started on ARM and MIPS. I also have a Z80 support which is generating working code on a TI-84 calculator emulator and TMS9900 output for the TI99 computer. I have x86 now working on PC with a sample test program in samples/x86 and a Mandelbrot generator that I used to compare the speed of it with (hope to post that soon). Eventually I'd like to target Intel Edison or maybe Intel Galileo and x86_64 is also in the works.

If anyone would like to contribute to having Java Grinder support the Intel Edison or the Parallella board, donating a board through my Amazon Wishlist would help :).

All generated assembly can be assembled with naken_asm (except the x86 code which is assembled with The Netwide Assembler (nasm)).

Java Grinder can do bits of optimization to improve the speed of the generated code. For example, despite Java being a stack based language, Java Grinder keeps values in registers. It can also do 1 or 2 instruction look-aheads to find better instructions for certain CPU's. An example of this is explained below. Also, the API is written so that every method is static and when the assembly language is generated, almost all the API methods are replaced with inline assembly instead of function calls.

There are some issues with how this works:

  • Only a subset of Java is supported. (See below)
  • For now, int on MSP430 and dsPIC is actually 16 bit. I may change this. Joe implemented 6502 and avr8 as 16 bit.
  • Need to implement switch/case.
  • Add "new" for objects and virtual method calling (maybe?).
  • Currently no garbage collection or memory protection. Doing new array[] will pull memory from the heap but never free it.
3 billion devices run Java

Download
java_grinder-2015-04-13.tar.gz
java_grinder-2015-04-13.zip
java_grinder-2015-04-13-macosx10.9-x86_64.tar.gz

Repository
git clone https://github.com/mikeakohn/java_grinder.git

Related Projects @mikekohn.net

Related pages on www.mikekohn.net: Java Grinder, dsPIC Mandelbrots, naken_asm

Targets
Working: MSP430, dsPIC (Video), 6502 / C64 (Video), TMS9990 / TI99/4A (Video), x86
Code complete: 68000 / Sega Genesis, Z80, Atmel AVR8
Work In Progress: MSP430X, ARM, MIPS, 65816 (SNES or Apple IIgs)
Maybe: x86_64, 8052, Parallella / Epiphany

Examples

Joe Davisson worked on the 6502 support (and Atmel AVR8 support) and made this Commodore 64 demo for Java Grinder.

To test out type:

java_grinder CommodoreDemo.class demo.asm c64
naken_asm -l -b -o demo.prg demo.asm

Source code included in Java Grinder samples directory.

Here is a video of it running on a real C64: Retro Console Java

https://www.youtube.com/watch?v=f85XkyO0EdA
dsPIC Mandelbrots in Java Here's a dsPIC computing Mandelbrots optimized with the dsPIC's DSP instructions. For a full write-up on how this works and a video see here: dsPIC Mandelbrots.
Nokia 5110 LCD I added support for being able to read static fields from external class files and wrote some code to test it by printing a bitmap to a Nokia 5110 LCD. Since http://littlebirdelectronics.com.au likes to link to some of my projects and sells this display, I decided to link back :).
Here's another example showing and MSP430 and a Java Grinder program controlling an LCD display. Source code is again included with package. http://youtu.be/q0PdsJ9YUkE

Explanation

In the git repository in the testing directory there is a program called LedBlink.java. To test it out to see how it works (you'll need to download naken_asm first), do the following:

git clone https://github.com/mikeakohn/java_grinder.git
cd java_grinder
make
make java
make tests
./java_grinder testing/LedBlink.class out.asm msp430g2231
naken_asm -l -I ${PATH_TO_NAKEN_MSP430_INCLUDES} out.asm mspdebug rf2500
prog out.hex
run

The code in LedBlink.java looks like this:

  static public void main(String args[])
  {
    int n;

    IOPort0.setPinsAsOutput(0x3);

    while(true)
    {
      IOPort0.setPortOutputValue(2);
      for (n = 0; n < 16384; n++);
      IOPort0.setPortOutputValue(1);
      for (n = 0; n < 16384; n++);
    }
  }

Running javap -c testing/LedBlink.class, the Java assembly looks like this:

  public static void main(java.lang.String[]);
    Code:
       0: iconst_3      
       1: invokestatic  #2   // Method net/mikekohn/java_grinder/IOPort0.setPinsAsOutput:(I)V
       4: iconst_2      
       5: invokestatic  #3   // Method net/mikekohn/java_grinder/IOPort0.setPortOutputValue:(I)V
       8: iconst_0      
       9: istore_1      
      10: iload_1       
      11: sipush        16384
      14: if_icmpge     23
      17: iinc          1, 1
      20: goto          10
      23: iconst_1      
      24: invokestatic  #3   // Method net/mikekohn/java_grinder/IOPort0.setPortOutputValue:(I)V
      27: iconst_0      
      28: istore_1      
      29: iload_1       
      30: sipush        16384
      33: if_icmpge     4
      36: iinc          1, 1
      39: goto          29

And the code in out.asm looks like this:

main:
  mov.w SP, r12
  sub.w #0x4, SP
  bis.b #3, &P1DIR
main_4:
  mov.b #2, &P1OUT
  mov.w #0, -4(r12)
main_10:
  mov.w -4(r12), r4
  cmp.w #16738, r4
  jge main_23
  add.w #1, -4(r12)
  jmp main_10
main_23:
  mov.b #1, &P1OUT
  mov.w #0, -4(r12)
main_29:
  mov.w -4(r12), r4
  cmp.w #16738, r4
  jge main_4
  add.w #1, -4(r12)
  jmp main_29

When running the program looks like this: http://youtu.be/loHsatbB1dQ

Inside Details

So my first step in writing this was to take the source code for naken_java, changed the formatting, and added a generator directory. I started out doing the generator doing some object oriented C using function pointers, and then decided it would probably be better just doing this in C++, so I converted the whole thing to C++.

In the generator directory there is an abstract super-class called Generator that contains all the functions that each architecture must implement (if anything just returning -1 to let the compiler (common/compile.cxx) know that this function isn't implemented). In the java directory there is a net/mikekohn/java_grinder directory that have the JavaGrinder API. All classes/methods from this package are implemented in the Generator modules as functions with the name of the class in lowercase, underscore, and the method name unchanged. These functions are called by the functions in the objects/invoke.cxx file.

The flow of the code basically looks like this:

Java Grinder chart

So Java is a stack-based assembly language, in other words if you have a = 3 + 5, Java will push 3 on the stack, then push 5 on the stack, and then with an add instruction pop 3 and 5 off the stack, add them, and put the result back on the stack. To try and avoid using the stack on a microcontroller, which would probably be pretty slow, the generated code uses a "stack" of registers first (r4-r11 on MSP430) and when it runs out it will start using the real stack. This should help the speed of the generated code. I've been told that Google's Dalvik works in a similar way. I've never seen Dalvik before and nor would I want to. I'm making completely my own implementation.

Updates

Update May20, 2015: I have a simple Sega Genesis program written in Java writting in the MESS emulator. More to come...

Update April 11, 2015: TMS9900 / TI99/4A is now working and I have a YouTube clip of Java running on TI99/4A on this Retro Console Java page.

Update January 2, 2015: I've been kind of eyeballing the Intel Edison and Intel Galileo boards, so yesterday for fun I added x86 and x86_64 files to Java Grinder. I filled in about half of the x86 code. All that's missing is array stuff. Not sure how to do arrays. Should I use the C function malloc()? Or should I use the bss region to create some kind of heap? I put a little sample program in samples/x86 that assembles with The Netwide Assembler (nasm) and links to a C program so it runs on Linux from the command line.

Update October 23, 2014: I have the TMS9900 code mostly written along with part of a TI99 API. Currently it's able to draw text on the screen and even render a Mandelbrot in text mode. I'm adding a higher resolution graphics mode with some plotting routines so a nicer demo can be made. I also need to finish with the array code in the TMS9900.

Update April 6, 2014: I have Z80 code complete along with a little API for the TI84 Plus C calculator, but I haven't figured out how to get a program running in the Tilem emulator yet to make sure it works right. Hopefully soon.

Update March 15, 2014: Joe has been working on optimizing the 6502 code and building the C64 package for his demo. I've also been asked a couple times about a C generator instead of assembly, which to me is kind of odd. Why not just write the code in C and not add another layer? The purpose of Java Grinder is to basically do what a JIT does inside of a JVM, except compile the code before being put onto the flash memory of a micro. A microcontroller wouldn't have enough memory to hold the JIT code anyway. Assembly text seemed like a good idea instead of straight byte code because it makes it easier to bug the assembled code and it takes advantage of naken_asm's features (elf output, label computing, etc). Either way I decided to drop it in quickly anyway just to see what the generated code looks like. It should be working properly except arrays.

Update March 23, 2014: In preparation for Atmel AVR8 support in Java Grinder, I added a simulator for Atmel AVR8 yesterday in naken_asm. Joe will most likely be doing the Java Grinder code for that this week. I'm also adding a simulator for Z80 so Z80 can more easily be added to Java Grinder. I have a TI-84 calculator which would be quite cool to write programs for in Java :).

Update March 4, 2014: Joe Davisson has 6502 working and has a CommodoreDemo.java in the testing directory. The demo currently generates a Mandelbrot image. A nice demonstration of Java on the Commodore 64 :).

Update February 10, 2014: I've been adding opimizations to the compiler. Many Java instructions that used to take 2 instructions now take one instruction on the MSP430 which usually saves a cycle or two along with bringing code density down. Also, when using some of Java Grinder's packages, if a constant is passed to the Java Grinder method I was able to avoid putting things on the stack and directly write a literal to the micro's register. This is for both dsPIC and MSP430. More to come :).

Update February 9, 2014: The mul/div/mod instructions are supported in hardware for the dsPIC, but there aren't similar instructions for MSP430. Joe Davisson has now implemented a software version of these instructions so they should work now. He also has plans to add the 65xx code to Java Grinder (since he's the one who wrote the 65xx assembler for naken_asm) so maybe in the near future we'll have Java on the Commodore 64 :).



Copyright 1997-2015 - Michael Kohn