diff --git a/pkg/chip8/chip8.go b/pkg/chip8/chip8.go index bd9ae11..02e513d 100644 --- a/pkg/chip8/chip8.go +++ b/pkg/chip8/chip8.go @@ -1,14 +1,17 @@ package chip8 -import "fmt" +import ( + "fmt" + "math/rand" +) const graphicsBufferSize = 64 * 32 type Chip8 struct { addressRegister uint16 - beepTimer uint16 + beepTimer byte drawRequired bool - delayTimer uint16 + delayTimer byte graphics [graphicsBufferSize]byte keys [16]byte memory [4096]byte @@ -106,9 +109,9 @@ func (cpu *Chip8) setRegisterTo() { cpu.registers[r] = byte(cpu.opcode & 0xFF) } -func (cpu *Chip8) RegisterPlusEqualsNN() {} // QUESTION HERE - WHAT DO IF IT WOULD WRAP ROUND? +func (cpu *Chip8) registerPlusEqualsNN() {} // QUESTION HERE - WHAT DO IF IT WOULD WRAP ROUND? -func (cpu *Chip8) BitOpsAndMath() { +func (cpu *Chip8) bitOpsAndMath() { instruction := cpu.opcode & 0x0F regX, regY := cpu.opcode>>8&0x0F, cpu.opcode>>4&0x0F switch instruction { @@ -166,19 +169,134 @@ func (cpu *Chip8) BitOpsAndMath() { } } -func (cpu *Chip8) SkipIfRegistersNotEqual() { +func (cpu *Chip8) skipIfRegistersNotEqual() { x, y := (cpu.opcode>>8)&0x0F, (cpu.opcode>>4)&0x0F if cpu.registers[x] != cpu.registers[y] { cpu.pc += 2 } } -func (cpu *Chip8) SetAddressRegister() { +func (cpu *Chip8) setAddressRegister() { // ANNN // Sets the address register to NNN cpu.addressRegister = cpu.opcode & 0x0FFF } +func (cpu *Chip8) jumpToV0PlusAddress() { + // BNNN + // PC=V0+NNN + cpu.pc = uint16(cpu.registers[0]) + (cpu.opcode & 0x0FFF) +} + +func (cpu *Chip8) setRegisterToRand() { + // CXNN + // Vx = rand() & NN + cpu.registers[(cpu.opcode>>8)&0x0F] = byte(cpu.opcode&0xFF) & byte(rand.Intn(256)) +} + +func (cpu *Chip8) displaySprite() { + // DXYN + // Draws a sprite in the graphics buffer + // VF is set to 1 if any pixels are flipped and zero otherwise + cpu.registers[0x0F] = 0 + x := int(cpu.registers[(cpu.opcode>>8)&0x0F]) + y := int(cpu.registers[(cpu.opcode>>4)&0x0F]) + + for row := 0; row < int(cpu.opcode&0xF); row++ { + pixel := cpu.memory[int(cpu.addressRegister)+row] + for column := 0; column < 8; column++ { + if pixel&(0x80>>column) != 0 { + graphicsPosition := x + column + ((y + row) * 60) + if cpu.graphics[graphicsPosition] == 1 { + cpu.registers[0xF] = 1 + } + cpu.graphics[graphicsPosition] ^= 1 + } + } + } + cpu.drawRequired = true +} + +func (cpu *Chip8) SkipOnKeyOpcodes() { + opcode := cpu.opcode & 0xFF + key := cpu.registers[(cpu.opcode>>8)&0x0F] + switch opcode { + case 0x9E: + // EX9E + // skip if key X is pressed + if cpu.keys[key] != 0 { + cpu.pc += 2 + } + case 0xA1: + // EXA1 + // skip if kkey X is not pressed + if cpu.keys[key] == 0 { + cpu.pc += 2 + } + } +} + +func (cpu *Chip8) FifteenIndexOpcodes() { + instruction := cpu.opcode & 0xFF + reg := int(cpu.opcode>>8) & 0xF + switch instruction { + // FX07 + // Set VX to the value of the delay timer + case 0x07: + cpu.registers[reg] = cpu.delayTimer + case 0x0A: + // FX0A + // block + wait for key press + for i, val := range cpu.keys { + if val != 0 { + cpu.registers[reg] = byte(i) + } + } + case 0x15: + // FX15 + // Set delay timer to VX + cpu.delayTimer = cpu.registers[reg] + case 0x18: + // FX18 + // SET THE BEEP TIMER TO VX + // BEEP + cpu.beepTimer = cpu.registers[reg] + case 0x1E: + // FX1E + // Add VX to the address register + // Set VF to 1 when range overflow + if int(cpu.registers[reg])+int(cpu.addressRegister) > 0xFFF { + cpu.registers[0x0F] = 1 + } else { + cpu.registers[0x0F] = 0 + } + cpu.addressRegister = uint16((int(cpu.addressRegister) + int(cpu.registers[reg])) & 0xFFF) + case 0x29: + // FX29 + // Sets address register to location of char stored in VX + cpu.addressRegister = uint16(cpu.registers[reg]) * 5 + case 0x33: + // FX33 + // Stores BCD representation of VX + cpu.memory[cpu.addressRegister] = cpu.registers[reg] / 100 + cpu.memory[cpu.addressRegister+1] = (cpu.registers[reg] / 10) % 10 + cpu.memory[cpu.addressRegister+2] = cpu.registers[reg] % 10 + case 0x55: + // FX55 + // takes values from and including reg X and stores then in memory + for i := 0; i <= reg; i++ { + cpu.memory[int(cpu.addressRegister)+i] = cpu.registers[i] + } + case 0x65: + // FX65 + // takes values from memory and stores them in registers + for i := 0; i <= reg; i++ { + cpu.registers[i] = cpu.memory[int(cpu.addressRegister)+i] + } + } + +} + func main() { fmt.Printf("Hello world!\n") prog := []byte{1, 2, 3, 4}