diff --git a/chip8/chip8.go b/chip8/chip8.go index 3ef4e8b..bfec8cc 100644 --- a/chip8/chip8.go +++ b/chip8/chip8.go @@ -1,13 +1,23 @@ package chip8 +const ( + MemorySize = 4096 // 4KB of memory + StackSize = 16 + InstructionSize = 2 +) + +const ( + ProgramAddress = uint16(0x0200) + StackAddress = uint16(0x0EA0) + VideoBufferAddress = uint16(0x0F00) +) + type Emulator struct { - V [16]uint8 // general registers - I uint16 // address register - SP uint16 // stack pointer - PC uint16 // program counter - Memory [4096]uint8 // 4KB of system RAM - Stack []uint8 // 32 bytes of stack. starting at 0x0EA0 - Screen []uint8 // 256 bytes of display buffer. starting at 0x0F00 + V [16]uint8 // general registers + I uint16 // address register + SP uint16 // stack pointer + PC uint16 // program counter + Memory [MemorySize]uint8 // 4KB of system RAM Timer struct { Delay uint8 // delay timer Sound uint8 // sound timer @@ -23,13 +33,11 @@ func NewEmulator() *Emulator { func (emulator *Emulator) Reset() { emulator.V = [16]uint8{} - emulator.I = 0x00 - emulator.SP = 0x00 - emulator.PC = 0x0200 - emulator.Memory = [4096]uint8{} - emulator.Stack = emulator.Memory[0x0EA0:] - emulator.Screen = emulator.Memory[0x0F00:] + emulator.I = 0 + emulator.SP = StackAddress + emulator.PC = ProgramAddress + emulator.Memory = [MemorySize]uint8{} emulator.Timer.Delay = 0 emulator.Timer.Sound = 0 - copy(emulator.Memory[0x0200:], emulator.ROM) + copy(emulator.Memory[ProgramAddress:], emulator.ROM) } diff --git a/chip8/instructions.go b/chip8/instructions.go new file mode 100644 index 0000000..89dff7b --- /dev/null +++ b/chip8/instructions.go @@ -0,0 +1,43 @@ +package chip8 + +func (emulator *Emulator) ClearScreen() { + // TODO: clear the screen buffer + emulator.PC += InstructionSize +} + +func (emulator *Emulator) Return() { + emulator.StackPop() +} + +func (emulator *Emulator) Jump(addr uint16) { + emulator.PC = addr +} + +func (emulator *Emulator) Call(addr uint16) { + emulator.StackPush() + emulator.PC = addr +} + +func (emulator *Emulator) SkipEqual(x uint8, value uint8) { + if emulator.V[x] == value { + emulator.PC += InstructionSize * 2 + } else { + emulator.PC += InstructionSize + } +} + +func (emulator *Emulator) SkipNotEqual(x uint8, value uint8) { + if emulator.V[x] != value { + emulator.PC += InstructionSize * 2 + } else { + emulator.PC += InstructionSize + } +} + +func (emulator *Emulator) SkipRegistersEqual(x uint8, y uint8) { + if emulator.V[x] == emulator.V[y] { + emulator.PC += InstructionSize * 2 + } else { + emulator.PC += InstructionSize + } +} diff --git a/chip8/instructions_test.go b/chip8/instructions_test.go new file mode 100644 index 0000000..3a3f634 --- /dev/null +++ b/chip8/instructions_test.go @@ -0,0 +1 @@ +package chip8_test diff --git a/chip8/stack.go b/chip8/stack.go new file mode 100644 index 0000000..4767ffd --- /dev/null +++ b/chip8/stack.go @@ -0,0 +1,20 @@ +package chip8 + +import "encoding/binary" + +func (emulator *Emulator) StackPush() { + if emulator.SP == StackAddress+StackSize*2 { + panic("chip8: stack overflow") + } + binary.BigEndian.PutUint16(emulator.Memory[emulator.SP:], emulator.PC) + emulator.SP += 2 +} + +func (emulator *Emulator) StackPop() { + if emulator.SP == StackAddress { + panic("chip8: nothing to pop from stack") + } + emulator.SP -= 2 + emulator.PC = binary.BigEndian.Uint16(emulator.Memory[emulator.SP:]) + binary.BigEndian.PutUint16(emulator.Memory[emulator.SP:], 0x00) // clean the stack position +} diff --git a/chip8/stack_test.go b/chip8/stack_test.go new file mode 100644 index 0000000..f0fd33b --- /dev/null +++ b/chip8/stack_test.go @@ -0,0 +1,31 @@ +package chip8_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/tangzero/chip8-emulator/chip8" +) + +func TestEmulator_StackPush(t *testing.T) { + emulator := chip8.NewEmulator() + + emulator.PC = 0xABCD + emulator.StackPush() + + assert.Equal(t, uint8(0xAB), emulator.Memory[chip8.StackAddress]) + assert.Equal(t, uint8(0xCD), emulator.Memory[chip8.StackAddress+1]) + assert.Equal(t, chip8.StackAddress+2, emulator.SP) +} + +func TestEmulator_StackPop(t *testing.T) { + emulator := chip8.NewEmulator() + + emulator.SP = chip8.StackAddress + 32 + emulator.Memory[chip8.StackAddress+30] = 0xEE + emulator.Memory[chip8.StackAddress+31] = 0xFF + emulator.StackPop() + + assert.Equal(t, uint16(0xEEFF), emulator.PC) + assert.Equal(t, chip8.StackAddress+30, emulator.SP) +}