Sega Genesis Java
Write Once, Run On Sega
Posted: November 17, 2015
The purpose of this project is to demonstrate a Java program compiled to run on a Sega Genesis.
A few years ago one of my friends gave his old Sega Genesis console (also known as the Sega Mega Drive) with a CD drive on it. The CD drive gave me the idea that maybe it would be possible to write a little demo for the thing and run it on a real console, rather than just an emulator, by burning the program on a CD. I decided to add Motorola 68000 to naken_asm so I'd have my own assembler to give this a try. I then added 68000 support to Java Grinder which ended up being pretty easy to do thanks to it being 32 bit instruction set. Lastly I added an API to Java Grinder so I could write my code in Java and compile the .class files natively for 68000 taking advantage of the Sega's hardware.
I keep getting asked why I'm programming for a Sega Genesis system in Java, the reason is I'm hoping someone from Sega or Sun Microsystems finds this page and offers me a job.
Related Projects @mikekohn.net
Below is the demo compiled out of the samples/sega_genesis directory. The demo was written in Java and compiled using javac against a jar file filled with empty methods for all the API calls. The .class files that are generated are then run through Java Grinder which transforms the Java byte-code into a single native 68000 source file which is then assembled with naken_asm.
Above is the demo running on the Mess emulator. https://youtu.be/FdMh0TN6SlA
And this is the demo running on a real Sega Genesis (Sega Mega Drive). Unfortunately it was really hard to get the lighting right, but at least it's running on a real machine here. https://youtu.be/9ukp3bQlv8A
For a binary of the demo to run on an emulator (or a real system) click here: sega_genesis_java_demo.bin
The API And Demo
The entire Sega Genesis API can be viewed from the Java Grinder git repository in the file SegaGenesis.java. I pretty much wrote this API as I was writing the demo. As I needed a new feature from the Sega's hardware, I created a method name and added some code in the SegaGenesis.cxx generator.
The first API functions I added were used to display Java Grinder title page (which I need to give credit to Joe Davisson for drawing). Since the Sega Genesis uses a TMS9918 VDP which is a "tiles" based graphics display, there are 3 sets of memory that need to be set up. One sets up the color palettes, one sets up the 8x8 pattern table, and the last decides which 8x8 area of the screen goes with which pattern. An example of this is in ImageJavaGrinder.java. The first 3 functions in the run() method set the palettes, patterns, and the screen data. To generate the data for the images, I wrote a Google Go program (my first time writing code in Google Go) called bmp2sega.go. This program saves memory in the ROM by reusing patterns in different areas of the screen. For example, if the entire screen was simply the color red, it would generate one 8x8 pattern with just the color red and display that pattern in the entire 40x28 area of the screen. The same program can be used to generate the data for sprites too.
Since the original Sonic games had some kind of chorus singing "SEGA!" I thought it would be fun to do something similar with "JAVA!". I first recorded my voice using Apple's Garage Band and then wrote another Google Go program called wav2dac.go to convert my voice into 8 bit data samples that I could feed into the Yamaha YM2612. To assist with sound and music, the Sega Genesis has a Z80 co-processor that can access the two sound chips, the Yamaha YM2612 and an SN76489. Since the YM2612 can't play digital sound on its own, I wrote some Z80 assembly code to feed the digital samples into the YM2612 with a delay loop to play the sample at the correct speed. Java Grinder does have Z80 support, but I decided to do all the Z80 code in straight assembly anyway.
I was pretty sure that creating some kind of moving star field was required for graphics / sound demos, so I included it in this one. To do the stars and line drawing routines and such I wrote a plot() method into the API. Using the plot() routine is pretty simple taking just an X, Y location and a color. I then wrote some line drawing routines in the Common.java file of the demo. Joe Davisson used those routines to draw the 3D cube towards the end of the demo. The plot routine works by allocating enough space for 1120 patterns in the VDP and placing all these patterns in the display area. The plot routine then draws into the pattern area by first calculating which 8x8 pattern is affected, then calculating which byte in the 8x8 pattern is affected, then reading in the 16 bit word that holds that byte from the VDP into a 68000 register, then masking out the 4 bits that hold that pixel, OR:ing back in the new pixel value, and then writing the 16 bit data back into the VDP. Sega Genesis was definitely not designed for this use-case.
I really wanted to use the real Motorola logo for the Motorola Inside part of the demo, but I was afraid they would be unhappy about it. I instead ended up drawing the logo with a Sharpie and scanned the image in. To animate the logo, the Genesis has the ability to scroll the display in hardware. The horizontal scroll can actually work line by line or the entire screen. The horizontal scroll is also used for the Powered By naken_asm logo and (along with a vertical scroll) used it to make the stars spin in a circle.
For music, I originally was going to download some .mid's and write a little .mid file player for the Z80. I even put together a hardware project here using a couple SN76489's to test how it could sound playing a .mid file from my favorite guitar player. I ended up scratching that idea and just played some chords on my guitar that sounded pleasant together and wrote them down in a text file (song_title.txt in the git repository) in a format similar to my old Drums++ format. I created a program called text_tracker.go that I could use to convert the text version of the song into both .mid files (so I could preview how it sounds on my computer) and also into assembly .db data so I could insert the song into a Z80 assembly program that plays the notes through the Yamaha YM2612 synthesizer. This leaves the 68000 completely free to animate graphics while the music is playing. After assembling the Z80 program, I wrote a bin2java.go program that is used to convert the binary file produced by naken_asm into Java arrays that can be cut and pasted into the demo. I added some API methods for loading Z80 programs and controlling the Z80. An example of assembly source code for playing a song is z80_play_title_song.asm.
I did use the second sound chip in the Sega Genesis (the SN76489 or also called the PSG). It's used to create the sound effects when the "Powered By naken_asm" logo slides off the screen. The code to control the chip was written in assembly in the z80_play_laser.asm. I planned on also using this chip with its "white noise" feature to make drum kind of sounds for the music, but it sounded bad and I didn't feel like messing with it. All the code to use the PSG on voice 7 of the music demo is still in the music player asm file.
As with the star field, the Mandelbrot at the end was required. The song playing there was the test song I made to make sure the text_tracker.go program was working properly. It sounded kind of odd so I kept it in the demo while drawing the Mandelbrot.
At the very end, the closing credits screen is simply an image I drew and used the waitForHorizontalBlank() method to change the background color palette to draw the raster bars.
I kind of wanted to add gamepad control to the API. Would be fun to write a game for the console. Maybe later. Update (2015-Dec-19): I added gamepad support to the API. Also, in the demo I wanted to show off the ability to do a side scroller. I was going to add some methods that would use the DMA to shift the 8x8 tiles after using the scrolling hardware to move the image at a pixel level.
To run the demo on a real console, instead of trying to figure out how the CD drive worked I got an EverDrive-MD from Stoneage Gamer. It ended up that despite the code running perfectly on two different emulators (Mess and Dgen), there were bugs on the real console. First, the YM2612 wasn't working properly since I wasn't checking if the chip was busy before writing to it. Then the Stars.java routine was plotting out of bounds of the screen which cause the real hardware to hang. The oddest bug was in the plot() routine, I was writing a command to the VDP control port, calculating the data with several instructions, and then writing the data to the VDP. For some reason I needed to move the control port writing to right before the data or it would somtimes plot the pixels in random spots on the screen.
Debugging on the Mess emulator was really easy since I could break into the debugger while the demo was running and check all the registers and RAM in the 68000, the Z80, the VDP, or any other part of the console. Debugging on the real console, not so simple. The first two bugs actually took almost no time to figure out and fix, but VDP control / data issue wasn't so easy. Makes me wonder what kind of debugging tools the Sega game programmers had.
This CPU has always been one of my absolute favorite chips. I think everyone who I talked to who has done assembly on different chips including the 68000 always say the same thing. Making this chip work in Java Grinder was the, by far, easiest chip yet. The instruction set is so complete, so straight-forward, so simple. Really wish Motorola would have kept up this chip with the Intel x86 chips. Motorola should have been able to make this chip as fast the x86 with all the hardware optimizations and have the advantage over x86 of the clean instruction set. I think one of the big advantages x86 has over all the 1990's RISC chips that died in the 2000's is code density. The 68000 should have been able to have similar code size. What a shame.
Building The Demo
If anyone wants to build the demo to test it or maybe to learn how to use Java Grinder to make their own demo or game here are the steps:
1) git clone https://github.com/mikeakohn/naken_asm.git
This bin file will be created: sega_genesis_java_demo.bin and can be run with a Sega Genesis / Mega Drive emulator or a real console with the SD card cartridge mentioned above.
If there are missing features from the API that someone wants added, feel free to email me.
Copyright 1997-2020 - Michael Kohn