Introduction
Commodore 64 support for java_grinder is a work-in-progress, but complete enough for certain games and demos. The API can be added to (or replaced entirely) but modifying these files:
java/net/mikekohn/java_grinder/c64/VIC.java
java/net/mikekohn/java_grinder/c64/SID.java
api/c64_vic.cxx
api/c64_vic.h
api/c64_sid.cxx
api/c64_sid.h
generator/API_C64.h
generator/C64.cxx
generator/C64.h
The M6502 generator uses 16-bit math, and javac doesn't make much of an effort to optimize the bytecode output, so expect large program sizes. (Many features and API methods are placed into subroutines, but there is still plenty of inline code.)
Only NTSC is supported, although eventually I hope to have an API call for choosing NTSC or PAL.
Classes
The relevant Java classes are:
- CPU
- Grinder
- Math
- Memory
- Timer
- TimerListener
- VIC
- SID
Memory Layout
- 0002-0013: internal variables
- 0014-0017: unused
- 0018-0049: text row table
- 004A-007B: color row table
- 0080-00FF: default Java stack (64 levels)
- 0100-0111: saved variables (for interrupts)
- 0112-01FF: 6502 stack
- 0200-03FF: large Java stack (256 levels)
- 0400-07E7: internal variables
- 0801-9FFF: program (38k)
- A000-BFFF: array heap (8k)
- C000-C3E7: text screen #1
- C400-C7E7: text screen #2
- C800-CFFF: charset
- D000-DFFF: chip registers, color RAM, etc
- E000-FFFF: hires/graphics area
BASIC and KERNAL ROMs are switched off. Graphics data may be copied to D000-DFFF as long as the processor port is toggled like this:
CPU.asm(" sei\n"); // disable interrupts
Memory.write8(0x01, 0x34); // enable all RAM
// copy data
Memory.write8(0x01, 0x35); // disable RAM at 0xd000-0xdfff
CPU.asm(" cli\n"); // enable interrupts
Class Members
CPU:
Insert inline assembly (uses naken_asm syntax, '\n' is required for new line, etc.):
- public static void asm(String code)
Note: The X register is used internally as the Java stack pointer, so it will have to be saved and restored if used by inline assembly or custom API routines.
Grinder:
- public static void largeJavaStack()
Call this at the beginning of a program to increase the variable stack size from 64 to 256 (238 if timerInterrupt() is used), at the cost of performance and increased code size.
Math:
- public static int abs(int value)
- public static int min(int n0, int n1)
- public static int max(int n0, int n1)
Memory:
These are similar to PEEK and POKE in BASIC:
- public static byte read8(int address)
- public static void write8(int address, byte value)
- public static short read16(int address)
- public static void write16(int address, short value)
Timer:
Time is set in processor cycles. "Cycles" and "divider" set the countdown for CIA #1 timers A and B respectively, interrupt occurs when timer B underflows:
- public static void setInterval(int cycles, int divider)
Turn the timer on or off:
- public static void setListener(boolean enabled)
TimerListener:
The program class should implement TimerListener, and include this method containing the interrupt code:
- public void timerInterrupt()
VIC:
Double-buffering is available if textEnable(1) is used, after which calls to textCopy() will update the screen. Color RAM is unaffected.
Binary data may be loaded at build time like this:
byte my_sprite[] = Memory.preloadByteArray("my_sprite.bin");
It then can be copied to the VIC-II graphics area:
VIC.copyDataFromArray(my_sprite, 0xe000, 63);
Sprite pointers need to be set for both screens unless only screen 0 will be used:
Memory.write8(0xc3f8, (byte)128); // sprite data at 0xe000
Memory.write8(0xc7f8, (byte)128); // sprite data at 0xe000
Sprite methods:
- public static void sprite0pos(int x, int y)
- public static void sprite1pos(int x, int y)
- public static void sprite2pos(int x, int y)
- public static void sprite3pos(int x, int y)
- public static void sprite4pos(int x, int y)
- public static void sprite5pos(int x, int y)
- public static void sprite6pos(int x, int y)
- public static void sprite7pos(int x, int y)
- public static void spriteExpandX(int value)
- public static void spriteExpandY(int value)
- public static void spritePriority(int value)
- public static void spriteMulticolorEnable(int value)
- public static int spriteCollision()
- public static int dataCollision()
- public static void sprite0color(int value)
- public static void sprite1color(int value)
- public static void sprite2color(int value)
- public static void sprite3color(int value)
- public static void sprite4color(int value)
- public static void sprite5color(int value)
- public static void sprite6color(int value)
- public static void sprite7color(int value)
- public static void spriteMulticolor0(int value)
- public static void spriteMulticolor1(int value)
Sprite positions are updated during the vertical blanking interval.
Colors:
- public static void border(int value)
- public static void background(int value)
- public static void multicolor1(int value)
- public static void multicolor2(int value)
- public static void multicolor3(int value)
Registers:
- public static void writeControl1(int value)
- public static int readControl1()
- public static void waitRaster(int value)
- public static void spriteEnable(int value)
- public static void writeControl2(int value)
- public static int readControl2()
- public static void writePointer(int value)
- public static int readPointer()
- public static void writeInterruptStatus(int value)
- public static int readInterruptStatus()
- public static void interruptControl(int value)
Text support:
- public static void textEnable(int screen)
- public static void textClear(int value)
- public static void textCopy()
- public static void textPlot(int x, int y, int value, int color)
- public static void textAsciiPlot(int x, int y, int value, int color)
- public static int textRead(int x, int y)
- public static int textString(String str)
- public static int textFill(int x, int y, int w, int h, int value)
- public static int textPaint(int x, int y, int w, int h, int value)
- public static void textScrollLeft()
- public static void textScrollRight()
- public static void textScrollUp()
- public static void textScrollDown()
- public static void makeTextTable()
- public static void makeColorTable()
- public static void colorRamClear(int value)
- public static void copyUppercase()
- public static void copyLowercase()
High-resolution graphics:
- public static void hiresEnable()
- public static void hiresClear(int value)
- public static void hiresPlot(int x, int y, int value)
- public static void makeHiresTables()
SID:
- public static void frequency1(int value)
- public static void pulseWidth1(int value)
- public static void waveform1(int value)
- public static void adsr1(int value)
- public static void frequency2(int value)
- public static void pulseWidth2(int value)
- public static void waveform2(int value)
- public static void adsr2(int value)
- public static void frequency3(int value)
- public static void pulseWidth3(int value)
- public static void waveform3(int value)
- public static void adsr3(int value)
- public static void filterCutoff(int value)
- public static void filterResonance(int value)
- public static void volume(int value)
- public static void oscillator3(int value)
- public static void envelope3(int value)
- public static void clear()
ADSR is set with a single 16-bit value arranged as SRAD (highest to lowest nybble).