Skip to content
Permalink
Browse files

refactoring #1

  • Loading branch information...
badlogic committed Oct 12, 2014
1 parent 02f02a9 commit 69edff00fe2a4078beeb16cd8904d50d485119da
@@ -0,0 +1,93 @@
package chip8;

import java.io.DataInputStream
import java.io.BufferedInputStream
import java.io.FileInputStream

fun loadRom(file: String): VmState {
return DataInputStream(BufferedInputStream(FileInputStream(file))).use {
val rom = it.readBytes()
val state = VmState(programSize=rom.size)
System.arraycopy(rom, 0, state.ram, state.pc, rom.size)
state
}
}

fun decode(decoder: Decoder, address:Int, msb: Byte, lsb: Byte) {
val opCode = (msb.toInt() shl 8 or lsb.toInt().and(0xff)).and(0xffff)
decoder.before(opCode, address)
when (msb.hi) {
0x0 -> {
when (msb.toInt() shl 8 or lsb.toInt()) {
0x00e0 -> decoder.clear()
0x00ee -> decoder.ret()
else -> decoder.unknown(opCode, address)
}
}
0x1 -> decoder.jmp(address(msb, lsb))
0x2 -> decoder.call(address(msb, lsb))
0x3 -> decoder.jeq(msb.lo, lsb.toInt())
0x4 -> decoder.jneq(msb.lo, lsb.toInt())
0x5 -> decoder.jeqr(msb.lo, lsb.hi)
0x6 -> decoder.set(msb.lo, lsb.toInt())
0x7 -> decoder.add(msb.lo, lsb.toInt())
0x8 -> {
val reg1 = msb.lo
val reg2 = lsb.hi
when(lsb.lo) {
0x0 -> decoder.setr(reg1, reg2)
0x1 -> decoder.or(reg1, reg2)
0x2 -> decoder.and(reg1, reg2)
0x3 -> decoder.xor(reg1, reg2)
0x4 -> decoder.addr(reg1, reg2)
0x5 -> decoder.sub(reg1, reg2)
0x6 -> decoder.shr(reg1)
0x7 -> decoder.subb(reg1, reg2)
0xe -> decoder.shl(reg1)
else -> decoder.unknown(opCode, address)
}
}
0x9 -> {
val reg1 = msb.lo
val reg2 = lsb.hi
decoder.jneqr(reg1, reg2)
}
0xa -> decoder.seti(address(msb, lsb))
0xb -> decoder.jmpv0(address(msb, lsb))
0xc -> decoder.rand(msb.lo, lsb.toInt())
0xd -> decoder.draw(msb.lo, lsb.hi, lsb.lo)
0xe -> {
when(lsb.toInt() or 0xff) {
0x9e -> decoder.jkey(msb.lo)
0xa1 -> decoder.jnkey(msb.lo)
else -> decoder.unknown(opCode, address)
}
}
0xf -> {
val reg = msb.lo
when(lsb.toInt() or 0xff) {
0x07 -> decoder.getdelay(reg)
0x0a -> decoder.waitkey(reg)
0x15 -> decoder.setdelay(reg)
0x18 -> decoder.setsound(reg)
0x1e -> decoder.addi(reg)
0x29 -> decoder.spritei(reg)
0x33 -> decoder.bcd(reg)
0x55 -> decoder.push(reg)
0x65 -> decoder.pop(reg)
else -> decoder.unknown(opCode, address)
}
}
else -> decoder.unknown(opCode, address)
}
}

fun disassemble(vmState: VmState): String {
val decoder = Disassembler()
for(addr in 0x200..(0x200+vmState.programSize - 1) step 2) {
val msb = vmState.ram[addr]
val lsb = vmState.ram[addr + 1]
decode(decoder, addr, msb, lsb)
}
return decoder.toString()
}
@@ -2,126 +2,42 @@ package chip8;

class Disassembler(): Decoder {
val builder = StringBuilder()
override fun before(opCode: Int, address: Int) {
builder.append("addr: 0x${address.toHex()}, op: 0x${opCode.toHex()}, ")
}
override fun unknown(opCode: Int, address: Int) {
builder.append("Unknown opcode addr: 0x${address.toHex()}, op: 0x${opCode.toHex()}")
}
override fun clear() {
builder.line("clear")
}
override fun ret() {
builder.line("ret")
}
override fun jmp(address: Int) {
builder.line("jmp 0x${address.toHex()}")
}
override fun call(address: Int) {
builder.line("call 0x${address.toHex()}")
}
override fun jeq(reg: Int, value: Int) {
builder.line("jeq v${reg.toHex()}, 0x${value.toHex()}")
}
override fun jneq(reg: Int, value: Int) {
builder.line("jneq v${reg.toHex()}, 0x${value.toHex()}")
}
override fun jeqr(reg1: Int, reg2: Int) {
builder.line("jeqr v${reg1.toHex()}, v${reg2.toHex()}")
}
override fun set(reg: Int, value: Int) {
builder.line("set v${reg.toHex()}, 0x${value.toHex()}")
}
override fun add(reg: Int, value: Int) {
builder.line("add v${reg.toHex()}, 0x${value.toHex()}")
}
override fun setr(reg1: Int, reg2: Int) {
builder.line("setr v${reg1.toHex()}, v${reg2.toHex()}")
}
override fun or(reg1: Int, reg2: Int) {
builder.line("or v${reg1.toHex()}, v${reg2.toHex()}")
}
override fun and(reg1: Int, reg2: Int) {
builder.line("and v${reg1.toHex()}, v${reg2.toHex()}")
}
override fun xor(reg1: Int, reg2: Int) {
builder.line("xor v${reg1.toHex()}, v${reg2.toHex()}")
}
override fun addr(reg1: Int, reg2: Int) {
builder.line("addr v${reg1.toHex()}, v${reg2.toHex()}")
}
override fun sub(reg1: Int, reg2: Int) {
builder.line("sub v${reg1.toHex()}, v${reg2.toHex()}")
}
override fun shr(reg1: Int) {
builder.line("shr v${reg1.toHex()}")
}
override fun subb(reg1: Int, reg2: Int) {
builder.line("subb v${reg1.toHex()}, v${reg2.toHex()}")
}
override fun shl(reg1: Int) {
builder.line("shl v${reg1.toHex()}")
}
override fun jneqr(reg1: Int, reg2: Int) {
builder.line("jneqr v${reg1.toHex()}, v${reg2.toHex()}")
}
override fun seti(value: Int) {
builder.line("seti 0x${value.toHex()}")
}
override fun jmpv0(address: Int) {
builder.line("jmpv0 0x${address.toHex()}")
}
override fun rand(reg: Int, value: Int) {
builder.line("rand v${reg.toHex()}, 0x${value.toHex()}")
}
override fun draw(reg1: Int, reg2: Int, value: Int) {
builder.line("draw v${reg1.toHex()}, v${reg2.toHex()}, 0x${value.toHex()}")
}
override fun jkey(reg: Int) {
builder.line("jkey v${reg.toHex()}")
}
override fun jnkey(reg: Int) {
builder.line("jnkey v${reg.toHex()}")
}
override fun getdelay(reg: Int) {
builder.line("getdelay v${reg.toHex()}")
}
override fun waitkey(reg: Int) {
builder.line("waitkey v${reg.toHex()}")
}
override fun setdelay(reg: Int) {
builder.line("setdelay v${reg.toHex()}")
}
override fun setsound(reg: Int) {
builder.line("setsound v${reg.toHex()}")
}
override fun addi(reg: Int) {
builder.line("addi v${reg.toHex()}")
}
override fun spritei(reg: Int) {
builder.line("spritei v${reg.toHex()}")
}
override fun bcd(reg: Int) {
builder.line("bcd v${reg.toHex()}")
}
override fun push(reg: Int) {
builder.line("push v0-v${reg.toHex()}")
}
override fun pop(reg: Int) {
builder.line("pop v0-v${reg.toHex()}")
}

override fun toString(): String {
return builder.toString()
}
}

fun disassemble(vmState: VmState): String {
val decoder = Disassembler()
for(addr in 0x200..(0x200+vmState.programSize - 1) step 2) {
val msb = vmState.ram[addr]
val lsb = vmState.ram[addr + 1]
decode(decoder, addr, msb, lsb)
}
return decoder.toString()
fun Any?.unit() {}
override fun before(opCode: Int, address: Int) = builder.append("addr: 0x${address.hex}, op: 0x${opCode.hex}, ").unit()
override fun unknown(opCode: Int, address: Int) = builder.append("Unknown opcode addr: 0x${address.hex}, op: 0x${opCode.hex}").unit()
override fun clear() = builder.line("clear")
override fun ret() = builder.line("ret")
override fun jmp(address: Int) = builder.line("jmp 0x${address.hex}")
override fun call(address: Int) = builder.line("call 0x${address.hex}")
override fun jeq(reg: Int, value: Int) = builder.line("jeq v${reg.hex}, 0x${value.hex}")
override fun jneq(reg: Int, value: Int) = builder.line("jneq v${reg.hex}, 0x${value.hex}")
override fun jeqr(reg1: Int, reg2: Int) = builder.line("jeqr v${reg1.hex}, v${reg2.hex}")
override fun set(reg: Int, value: Int) = builder.line("set v${reg.hex}, 0x${value.hex}")
override fun add(reg: Int, value: Int) = builder.line("add v${reg.hex}, 0x${value.hex}")
override fun setr(reg1: Int, reg2: Int) = builder.line("setr v${reg1.hex}, v${reg2.hex}")
override fun or(reg1: Int, reg2: Int) = builder.line("or v${reg1.hex}, v${reg2.hex}")
override fun and(reg1: Int, reg2: Int) = builder.line("and v${reg1.hex}, v${reg2.hex}")
override fun xor(reg1: Int, reg2: Int) = builder.line("xor v${reg1.hex}, v${reg2.hex}")
override fun addr(reg1: Int, reg2: Int) = builder.line("addr v${reg1.hex}, v${reg2.hex}")
override fun sub(reg1: Int, reg2: Int) = builder.line("sub v${reg1.hex}, v${reg2.hex}")
override fun shr(reg1: Int) = builder.line("shr v${reg1.hex}")
override fun subb(reg1: Int, reg2: Int) = builder.line("subb v${reg1.hex}, v${reg2.hex}")
override fun shl(reg1: Int) = builder.line("shl v${reg1.hex}")
override fun jneqr(reg1: Int, reg2: Int) = builder.line("jneqr v${reg1.hex}, v${reg2.hex}")
override fun seti(value: Int) = builder.line("seti 0x${value.hex}")
override fun jmpv0(address: Int) = builder.line("jmpv0 0x${address.hex}")
override fun rand(reg: Int, value: Int) = builder.line("rand v${reg.hex}, 0x${value.hex}")
override fun draw(reg1: Int, reg2: Int, value: Int) = builder.line("draw v${reg1.hex}, v${reg2.hex}, 0x${value.hex}")
override fun jkey(reg: Int) = builder.line("jkey v${reg.hex}")
override fun jnkey(reg: Int) = builder.line("jnkey v${reg.hex}")
override fun getdelay(reg: Int) = builder.line("getdelay v${reg.hex}")
override fun waitkey(reg: Int) = builder.line("waitkey v${reg.hex}")
override fun setdelay(reg: Int) = builder.line("setdelay v${reg.hex}")
override fun setsound(reg: Int) = builder.line("setsound v${reg.hex}")
override fun addi(reg: Int) = builder.line("addi v${reg.hex}")
override fun spritei(reg: Int) = builder.line("spritei v${reg.hex}")
override fun bcd(reg: Int) = builder.line("bcd v${reg.hex}")
override fun push(reg: Int) = builder.line("push v0-v${reg.hex}")
override fun pop(reg: Int) = builder.line("pop v0-v${reg.hex}")
override fun toString(): String = builder.toString()
}
@@ -1,9 +1,9 @@
package chip8;

fun Int.toHex() = Integer.toHexString(this)
fun Byte.toHex() = Integer.toHexString(this.toInt())
fun Byte.high() = (this.toInt() and 0xf0) shr 4
fun Byte.low() = this.toInt() and 0xf
val Int.hex: String get() = Integer.toHexString(this)
val Byte.hex: String get() = Integer.toHexString(this.toInt())
val Byte.hi: Int get() = (this.toInt() and 0xf0) shr 4
val Byte.lo: Int get() = this.toInt() and 0xf
fun address(msb: Byte, lsb: Byte) = ((msb.toInt() and 0xf) shl 8) or (lsb.toInt() and 0xff)

fun StringBuilder.line(line: String) {
@@ -4,84 +4,6 @@ import java.io.FileInputStream
import java.io.BufferedInputStream
import java.io.DataInputStream

fun loadRom(file: String): VmState {
return DataInputStream(BufferedInputStream(FileInputStream(file))).use {
val rom = it.readBytes()
val state = VmState(programSize=rom.size)
System.arraycopy(rom, 0, state.ram, state.pc, rom.size)
state
}
}

fun decode(decoder: Decoder, address:Int, msb: Byte, lsb: Byte) {
val opCode = (msb.toInt() shl 8 or lsb.toInt().and(0xff)).and(0xffff)
decoder.before(opCode, address)
when (msb.high()) {
0x0 -> {
when (msb.toInt() shl 8 or lsb.toInt()) {
0x00e0 -> decoder.clear()
0x00ee -> decoder.ret()
else -> decoder.unknown(opCode, address)
}
}
0x1 -> decoder.jmp(address(msb, lsb))
0x2 -> decoder.call(address(msb, lsb))
0x3 -> decoder.jeq(msb.low(), lsb.toInt())
0x4 -> decoder.jneq(msb.low(), lsb.toInt())
0x5 -> decoder.jeqr(msb.low(), lsb.high())
0x6 -> decoder.set(msb.low(), lsb.toInt())
0x7 -> decoder.add(msb.low(), lsb.toInt())
0x8 -> {
val reg1 = msb.low()
val reg2 = lsb.high()
when(lsb.low()) {
0x0 -> decoder.setr(reg1, reg2)
0x1 -> decoder.or(reg1, reg2)
0x2 -> decoder.and(reg1, reg2)
0x3 -> decoder.xor(reg1, reg2)
0x4 -> decoder.addr(reg1, reg2)
0x5 -> decoder.sub(reg1, reg2)
0x6 -> decoder.shr(reg1)
0x7 -> decoder.subb(reg1, reg2)
0xe -> decoder.shl(reg1)
else -> decoder.unknown(opCode, address)
}
}
0x9 -> {
val reg1 = msb.low()
val reg2 = lsb.high()
decoder.jneqr(reg1, reg2)
}
0xa -> decoder.seti(address(msb, lsb))
0xb -> decoder.jmpv0(address(msb, lsb))
0xc -> decoder.rand(msb.low(), lsb.toInt())
0xd -> decoder.draw(msb.low(), lsb.high(), lsb.low())
0xe -> {
when(lsb.toInt() or 0xff) {
0x9e -> decoder.jkey(msb.low())
0xa1 -> decoder.jnkey(msb.low())
else -> decoder.unknown(opCode, address)
}
}
0xf -> {
val reg = msb.low()
when(lsb.toInt() or 0xff) {
0x07 -> decoder.getdelay(reg)
0x0a -> decoder.waitkey(reg)
0x15 -> decoder.setdelay(reg)
0x18 -> decoder.setsound(reg)
0x1e -> decoder.addi(reg)
0x29 -> decoder.spritei(reg)
0x33 -> decoder.bcd(reg)
0x55 -> decoder.push(reg)
0x65 -> decoder.pop(reg)
else -> decoder.unknown(opCode, address)
}
}
else -> decoder.unknown(opCode, address)
}
}

fun main(args: Array<String>) {
val vmState = loadRom("roms/maze.rom")
println(disassemble(vmState))

0 comments on commit 69edff0

Please sign in to comment.
You can’t perform that action at this time.