diff --git a/execute.go b/execute.go index 44db7aa..d7d9287 100644 --- a/execute.go +++ b/execute.go @@ -1,40 +1,90 @@ package main type state struct { - register r, - memory m + registers registers + memory memory } -func step(state *S) { +func step(s *state) { } const modeNone = -1 const modeImmediate = 0 const modeZeroPage = 1 -const modeAbsolute = 2 - -type opcode struct { - name string - code int8 - bytes int - cycles int - mode int -} +const modeZeroPageX = 3 +const modeAbsolute = 2 // https://www.masswerk.at/6502/6502_instruction_set.html -func opA1LDA(state *, opcode) { - value := s->memory - s->register.setRegister(regA, value) - +func opLDAimm(s *state, line []uint8) { + opLDR(s, line, regA, modeImmediate) } -func opLDA(state *s, reg, mode, arg) { +func opLDAzpg(s *state, line []uint8) { + opLDR(s, line, regA, modeZeroPage) } -opcodes := []Opcode{ - 0: opcode('BRK', 0x0, 1, 7, modeImmediate) - 1: +func opLDYimm(s *state, line []uint8) { + opLDR(s, line, regY, modeImmediate) } +func opLDAzpgX(s *state, line []uint8) { + opLDR(s, line, regA, modeZeroPageX) +} + +func opLDAabs(s *state, line []uint8) { + opLDR(s, line, regA, modeAbsolute) +} + +func getWordInLine(line []uint8) uint16 { + return uint16(line[1]) + 0x100*uint16(line[2]) +} + +func opLDR(s *state, line []uint8, reg int, mode int) { + var value uint8 + switch mode { + case modeImmediate: + value = line[1] + case modeZeroPage: + address := line[1] + value = s.memory[address] + case modeZeroPageX: + address := line[1] + s.registers.getRegister(regX) + value = s.memory[address] + case modeAbsolute: + address := getWordInLine(line) + value = s.memory[address] + } + + s.registers.setRegister(reg, value) +} + +type opFunc func(s *state, line []uint8, opcode opcode) +type opcode struct { + name string + bytes int + cycles int + mode int + reg int + action opFunc +} + +func opNOP(s *state, line []uint8, opcode opcode) {} +func opLDRex(s *state, line []uint8, opcode opcode) { + opLDR(s, line, opcode.reg, opcode.mode) +} + +var opcodes = [256]opcode{ + 0x00: opcode{"BRK", 1, 7, modeImmediate, regNone, opNOP}, + 0xA0: opcode{"LDY", -1, -1, modeImmediate, regY, opLDRex}, + 0xA5: opcode{"LDA", 2, 3, modeZeroPage, regA, opLDRex}, + 0xB5: opcode{"LDA", 2, 4, modeZeroPageX, regA, opLDRex}, + 0xA9: opcode{"LDA", 2, 2, modeImmediate, regA, opLDRex}, + 0xAD: opcode{"LDA", 3, 4, modeAbsolute, regA, opLDRex}, +} + +func executeLine(s *state, line []uint8) { + opcode := opcodes[line[0]] + opcode.action(s, line, opcode) +} diff --git a/execute_test.go b/execute_test.go new file mode 100644 index 0000000..e76d1a5 --- /dev/null +++ b/execute_test.go @@ -0,0 +1,87 @@ +package main + +import ( + "testing" +) + +func TestLDA(t *testing.T) { + var s state + + opLDAimm(&s, []uint8{0xA9, 0x42}) + if s.registers.getA() != 0x42 { + t.Error("Error in LDA #") + } + + opLDYimm(&s, []uint8{0xA0, 0xFE}) + if s.registers.getY() != 0xFE { + t.Error("Error in LDY #") + } + + s.memory[0x38] = 0x87 + opLDAzpg(&s, []uint8{0xA5, 0x38}) + if s.registers.getA() != 0x87 { + t.Error("Error in LDA zpg") + } + + s.memory[0x57] = 0x90 + s.registers.setX(0x10) + opLDAzpgX(&s, []uint8{0xB5, 0x47}) + if s.registers.getA() != 0x90 { + t.Error("Error in LDA zpgX") + } + + s.memory[0x38] = 0x12 + s.registers.setX(0x89) + opLDAzpgX(&s, []uint8{0xB5, 0xAF}) + if s.registers.getA() != 0x12 { + t.Error("Error in LDA zpgX with sero page overflow") + } + + s.memory[0x1234] = 0x67 + opLDAabs(&s, []uint8{0xAD, 0x34, 0x12}) + if s.registers.getA() != 0x67 { + t.Error("Error in LDA abs") + } + +} + +func TestLDA2(t *testing.T) { + var s state + + executeLine(&s, []uint8{0xA9, 0x42}) + if s.registers.getA() != 0x42 { + t.Error("Error in LDA #") + } + + executeLine(&s, []uint8{0xA0, 0xFE}) + if s.registers.getY() != 0xFE { + t.Error("Error in LDY #") + } + + s.memory[0x38] = 0x87 + executeLine(&s, []uint8{0xA5, 0x38}) + if s.registers.getA() != 0x87 { + t.Error("Error in LDA zpg") + } + + s.memory[0x57] = 0x90 + s.registers.setX(0x10) + executeLine(&s, []uint8{0xB5, 0x47}) + if s.registers.getA() != 0x90 { + t.Error("Error in LDA zpgX") + } + + s.memory[0x38] = 0x12 + s.registers.setX(0x89) + executeLine(&s, []uint8{0xB5, 0xAF}) + if s.registers.getA() != 0x12 { + t.Error("Error in LDA zpgX with sero page overflow") + } + + s.memory[0x1234] = 0x67 + executeLine(&s, []uint8{0xAD, 0x34, 0x12}) + if s.registers.getA() != 0x67 { + t.Error("Error in LDA abs") + } + +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..7905807 --- /dev/null +++ b/main.go @@ -0,0 +1,5 @@ +package main + +func main() { + +} diff --git a/memory.go b/memory.go index b2a1091..367b8be 100644 --- a/memory.go +++ b/memory.go @@ -1,4 +1,3 @@ package main type memory [65536]uint8 - diff --git a/registers.go b/registers.go index 360f55f..fdef307 100644 --- a/registers.go +++ b/registers.go @@ -1,41 +1,41 @@ package main const ( - regA = 0 - regX = 1 - regY = 2 - // empty - regP = 4 - regS = 5 - regPC = 6 // 2 bytes + regA = 0 + regX = 1 + regY = 2 + regP = 4 + regS = 5 + regPC = 6 // 2 bytes + regNone = 10 ) type registers struct { data [8]uint8 } -func (r registers) getA() uint8 { return r.data[regA] } -func (r registers) getX() uint8 { return r.data[regX] } -func (r registers) getY() uint8 { return r.data[regY] } -func (r registers) getP() uint8 { return r.data[regP] } -func (r registers) getS() uint8 { return r.data[regS] } +func (r *registers) getRegister(i int) uint8 { return r.data[i] } -func (r registers) setRegister(i int, v uint8) registers { +func (r *registers) getA() uint8 { return r.data[regA] } +func (r *registers) getX() uint8 { return r.data[regX] } +func (r *registers) getY() uint8 { return r.data[regY] } +func (r *registers) getP() uint8 { return r.data[regP] } +func (r *registers) getS() uint8 { return r.data[regS] } + +func (r *registers) setRegister(i int, v uint8) { r.data[i] = v - return r } -func (r registers) setA(v uint8) registers { return r.setRegister(regA, v) } -func (r registers) setX(v uint8) registers { return r.setRegister(regX, v) } -func (r registers) setY(v uint8) registers { return r.setRegister(regY, v) } -func (r registers) setP(v uint8) registers { return r.setRegister(regP, v) } -func (r registers) setS(v uint8) registers { return r.setRegister(regS, v) } +func (r *registers) setA(v uint8) { r.setRegister(regA, v) } +func (r *registers) setX(v uint8) { r.setRegister(regX, v) } +func (r *registers) setY(v uint8) { r.setRegister(regY, v) } +func (r *registers) setP(v uint8) { r.setRegister(regP, v) } +func (r *registers) setS(v uint8) { r.setRegister(regS, v) } -func (r registers) getPC() uint16 { +func (r *registers) getPC() uint16 { return uint16(r.data[regPC])*256 + uint16(r.data[regPC+1]) } -func (r registers) setPC(v uint16) registers { +func (r *registers) setPC(v uint16) { r.data[regPC] = uint8(v >> 8) r.data[regPC+1] = uint8(v) - return r } diff --git a/registers_test.go b/registers_test.go index b9d873c..44d902d 100644 --- a/registers_test.go +++ b/registers_test.go @@ -2,19 +2,21 @@ package main import "testing" -func TestRegA(t *testing.T){ +func TestRegA(t *testing.T) { var r registers var data uint8 data = 200 - if r.setA(data).getA() != data { + r.setA(data) + if r.getA() != data { t.Error("Error storing and loading A") } } -func TestRegPC(t *testing.T){ +func TestRegPC(t *testing.T) { var r registers var data uint16 data = 0xc600 - if r.setPC(data).getPC() != data { + r.setPC(data) + if r.getPC() != data { t.Error("Error storing and loading PC") } -} \ No newline at end of file +}