diff --git a/cmd/chip8/main.go b/cmd/chip8/main.go index 60b7fdb..e02ec25 100644 --- a/cmd/chip8/main.go +++ b/cmd/chip8/main.go @@ -20,7 +20,7 @@ var ( window *pixelgl.Window // TODO: Abstract this. - keys = map[uint16]pixelgl.Button{ + keys = map[byte]pixelgl.Button{ 0x1: pixelgl.Key1, 0x2: pixelgl.Key2, 0x3: pixelgl.Key3, 0xC: pixelgl.Key4, 0x4: pixelgl.KeyQ, 0x5: pixelgl.KeyW, 0x6: pixelgl.KeyE, 0xD: pixelgl.KeyR, 0x7: pixelgl.KeyA, 0x8: pixelgl.KeyS, 0x9: pixelgl.KeyD, 0xE: pixelgl.KeyF, @@ -73,8 +73,6 @@ func run() { log.Fatal("Could not create window:", err) } - // TODO: Setup input. - vm = chip8.New() vm.Debug = debug diff --git a/internal/chip8/opcodes.go b/internal/chip8/opcodes.go index e8fbf44..c47e468 100644 --- a/internal/chip8/opcodes.go +++ b/internal/chip8/opcodes.go @@ -64,7 +64,10 @@ func (v *VM) registerHandlers() { opcode: "ANNN", handler: v.setAddress, }, - // TODO: BNNN + 0xB000: { + opcode: "BNNN", + handler: v.jumpV0, + }, 0xC000: { opcode: "CXNN", handler: v.setVxRand, @@ -359,8 +362,8 @@ func (v *VM) decVxVy(x, y uint16) opcodeHandlerFunc { // to the right by 1. func (v *VM) setVFLeastVx(x, y uint16) opcodeHandlerFunc { return func() (uint16, error) { - v.v[0xF] = v.v[x] & 1 v.v[x] >>= 1 + v.v[0xF] = v.v[x] & 1 v.pc += 2 @@ -389,8 +392,8 @@ func (v *VM) setVxVyMinusVx(x, y uint16) opcodeHandlerFunc { // to the left by 1. func (v *VM) setVFMostVx(x, y uint16) opcodeHandlerFunc { return func() (uint16, error) { - v.v[0xF] = v.v[x] & 7 v.v[x] <<= 1 + v.v[0xF] = v.v[x] & 7 v.pc += 2 @@ -423,6 +426,14 @@ func (v *VM) setAddress() (uint16, error) { return v.opc, nil } +// jumpV0 jumps to the address NNN plus V0. +func (v *VM) jumpV0() (uint16, error) { + // Jump to NNN. + v.pc = uint16(v.v[0]) + v.opc&0x0FFF + + return v.opc, nil +} + // setVxRand sets VX to the result of a bitwise and operation on a random // number (typically: 0 to 255) and NN. func (v *VM) setVxRand() (uint16, error) { @@ -497,9 +508,9 @@ func (v *VM) skipVxKeyPressed() (uint16, error) { // instead of the usual 2. if v.keys[k] == 1 { v.keys[k] = 0 - v.pc += 2 - } else { v.pc += 4 + } else { + v.pc += 2 } return v.opc & 0xFFFF, nil @@ -530,7 +541,8 @@ func (v *VM) handle0xF000() (uint16, error) { case 0x0007: return v.getDelayTimer() - // TODO: FX0A + case 0x000A: + return v.getKey() case 0x0015: return v.setDelayTimer() @@ -538,7 +550,8 @@ func (v *VM) handle0xF000() (uint16, error) { case 0x0018: return v.setSoundTimer() - // TODO: FX1E + case 0x001E: + return v.incIVx() case 0x0029: return v.loadFont() @@ -546,7 +559,8 @@ func (v *VM) handle0xF000() (uint16, error) { case 0x0033: return v.setBCD() - // TODO: FX55 + case 0x0055: + return v.regDump() case 0x0065: return v.regLoad() @@ -556,7 +570,7 @@ func (v *VM) handle0xF000() (uint16, error) { } } -// getDelayTimer the delay timer to VX. +// getDelayTimer sets the delay timer to VX. func (v *VM) getDelayTimer() (uint16, error) { v.v[(v.opc&0x0F00)>>8] = v.delayTimer v.pc += 2 @@ -564,6 +578,21 @@ func (v *VM) getDelayTimer() (uint16, error) { return v.opc & 0xFFFF, nil } +// getKey waits for a key press and then stores in VX. Blocking Operation. All +// instruction halted until next key event. +func (v *VM) getKey() (uint16, error) { + x := (v.opc & 0x0F00) >> 8 + for i := range v.keys { + if v.keys[i] == 1 { + v.v[x] = v.keys[i] + v.pc += 2 + break + } + } + + return v.opc & 0xFFFF, nil +} + // setDelayTimer sets the delay timer to VX. func (v *VM) setDelayTimer() (uint16, error) { v.delayTimer = v.v[(v.opc&0x0F00)>>8] @@ -580,6 +609,14 @@ func (v *VM) setSoundTimer() (uint16, error) { return v.opc & 0xFFFF, nil } +// incIVx adds VX to I. +func (v *VM) incIVx() (uint16, error) { + v.i += uint16(v.v[(v.opc&0x0F00)>>8]) + v.pc += 2 + + return v.opc & 0xFFFF, nil +} + // loadFont sets i to the location of the sprite for the character in VX. // Characters 0-F (in hexadecimal) are represented by a 4x5 font. func (v *VM) loadFont() (uint16, error) { @@ -605,7 +642,19 @@ func (v *VM) setBCD() (uint16, error) { return v.opc & 0xFFFF, nil } -// fillV0Vx stores V0 to VX (including VX) in mem starting at address i. The +// regDump stores V0 to VX (including VX) in memory starting at address i. The +// offset from i is increased by 1 for each value written, but i itself is left +// unmodified. +func (v *VM) regDump() (uint16, error) { + for i := uint16(0); i <= (v.opc&0x0F00)>>8; i++ { + v.mem[v.i+i] = v.v[i] + } + v.pc += 2 + + return v.opc & 0xFFFF, nil +} + +// regLoad stores V0 to VX (including VX) in mem starting at address i. The // offset from i is increased by 1 for each value written, but i itself is left // unmodified. func (v *VM) regLoad() (uint16, error) { diff --git a/internal/chip8/vm.go b/internal/chip8/vm.go index e8e3546..b862e6d 100644 --- a/internal/chip8/vm.go +++ b/internal/chip8/vm.go @@ -129,7 +129,7 @@ func (v *VM) Beep() <-chan struct{} { } // KeyDown marks key as pressed. -func (v *VM) KeyDown(key uint16) { +func (v *VM) KeyDown(key byte) { v.keys[key] = 1 }