mirror of
https://github.com/ethauvin/chip-8.git
synced 2025-04-25 00:37:13 -07:00
First commit
This commit is contained in:
commit
ee139eba9b
55 changed files with 1728 additions and 0 deletions
83
README.md
Normal file
83
README.md
Normal file
|
@ -0,0 +1,83 @@
|
|||
# chip8
|
||||
## A [Chip-8](http://www.cs.columbia.edu/~sedwards/classes/2016/4840-spring/designs/Chip8.pdf) emulator written in Kotlin
|
||||
|
||||
<p align="center">
|
||||
<img src="https://github.com/cbeust/chip8/blob/master/pics/space-invaders-2.gif?raw=true"/>
|
||||
</p>
|
||||
|
||||
# How to run
|
||||
|
||||
```
|
||||
$ ./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.
|
||||
|
||||
# Architecture
|
||||
|
||||
The game creates a [`Computer`](https://github.com/cbeust/chip8/blob/master/src/main/kotlin/com/beust/chip8/Computer.kt) object which is made of a `Display`, `Keyboard`, `FrameBuffer` and `Cpu`.
|
||||
|
||||
## 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](http://www.cs.columbia.edu/~sedwards/classes/2016/4840-spring/designs/Chip8.pdf). Since there is no specific definition for the CPU clock, I used the timing diagram from the document
|
||||
to set it at around 500Hz:
|
||||
|
||||
```kotlin
|
||||
// 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)
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<img width="50%" src="https://github.com/cbeust/chip8/blob/master/pics/tetris-1.png?raw=true"/>
|
||||
</p>
|
||||
|
||||
The next two bytes are then masked and turned into instructions. All the op codes can be found in the `[Ops.kt](https://github.com/cbeust/chip8/blob/master/src/main/kotlin/com/beust/chip8/Ops.kt)` file. Here is an example:
|
||||
|
||||
```kotlin
|
||||
/**
|
||||
* 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"
|
||||
}
|
||||
```
|
||||
|
||||
## Display
|
||||
|
||||
The `Display` is a simple interface which allows multiple strategies to render the frame buffer:
|
||||
|
||||
```kotlin
|
||||
interface Display {
|
||||
val pane: Pane
|
||||
fun draw(frameBuffer: IntArray)
|
||||
fun clear(frameBuffer: IntArray)
|
||||
}
|
||||
```
|
||||
|
||||
For example, here is a text based renderer:
|
||||
|
||||
<p align="center">
|
||||
<img width="50%" src="https://github.com/cbeust/chip8/blob/master/pics/space-invaders-text.png?raw=true"/>
|
||||
</p>
|
||||
|
||||
The emulator window will resize gracefully:
|
||||
|
||||
<p align="center">
|
||||
<img width="50%" src="https://github.com/cbeust/chip8/blob/master/pics/space-invaders-small.png?raw=true"/>
|
||||
</p>
|
||||
|
||||
You can also easily alter other aspects of the renderer:
|
||||
|
||||
<p align="center">
|
||||
<img width="50%" src="https://github.com/cbeust/chip8/blob/master/pics/space-invaders-colors.png?raw=true"/>
|
||||
</p>
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue