A Chip-8 emulator written in Kotlin
Chip-8 is a processor developed in the 70s. Because of its simplicity, it's a great starter project for anyone interested in learning how to implement an emulator. The specification is pretty small (about ten pages) and there are several roms available that make it easy to test how well your emulator runs.
$ ./gradlew run
The emulator will load with Space Invaders by default (press 5 to start the game, then 4/5/6 to move around and shoot). Open a new rom by clicking on the "Open rom..." button.
You can pause the emulator at any time (key 'p
'), which will update the disassembly window to show the next instructions about to be executed. You can also adjust the clock speed to make the emulator go slower or faster.
The game creates a Computer
object which is made of a Display
, Keyboard
, FrameBuffer
and Cpu
.
The CPU reads a new instruction (the next two bytes extracted at the program counter location) at a fixed rate
which defines the clock speed. Two timers are needed: one for the CPU and one for the device timer register,
called DT
, which needs to tick at 60 Hz according to the spec. Since there is no specific definition for the CPU clock, I used the timing diagram from the document
to set it at around 500Hz:
// CPU clock: around 500 Hz by default
cpuFuture = executor.scheduleAtFixedRate(cpuTick, 0, 1_000_000L / cpuClockHz, TimeUnit.MICROSECONDS)
// Delay Timer: 60 Hz by spec
timerFuture = executor.scheduleAtFixedRate(timerTick, 0, 16L, TimeUnit.MILLISECONDS)
The next two bytes are then masked and turned into instructions. All the op codes can be found in the Ops.kt file. Here is an example:
/**
* 7xkk
* Set Vx = Vx + kk
*/
class Add(c: Computer, n: Nibbles): Op(c, n) {
override fun run() { cpu.V[x] = unsigned(cpu.V[x] + kk) }
override fun toString() = "ADD V$x, $kk"
}
The Display
is a simple interface which allows multiple strategies to render the frame buffer:
interface Display {
val pane: Pane
fun draw(frameBuffer: IntArray)
fun clear(frameBuffer: IntArray)
}
For example, here is a text based renderer:
The emulator window will resize gracefully:
You can also easily alter other aspects of the renderer: