CONTENTS

Home
Electronics
Graphics
Java
Java Mobile
Android / iOS
Other Stuff
Music
Resume
Contact





Java Grinder

Posted: January 05, 2014
Updated: July 7, 2014

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 some packages 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 (which I haven't tested at all yet) and started on ARM and MIPS. I also have a Z80 support which is generating working code on a TI-84 calculator emulator. All generated assembly can be assembled with naken_asm.

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" 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.

Download
java_grinder-2014-07-05.tar.gz
java_grinder-2014-07-05.zip
java_grinder-2014-07-05-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, 6502
Code complete: 68000, Z80, Atmel AVR8
Work In Progress: MSP430X, ARM, MIPS, TMS9900 (TI99)
Maybe: x86_64, x86, 8052

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.

https://www.youtube.com/watch?v=f85XkyO0EdA
Here's a dsPIC computing Mandelbrots optimized with the dsPIC's DSP instructions. For a full write-up on how this works see here: dsPIC Mandelbrots.
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:

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 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-2014 - Michael Kohn