From d376e465966f00b9bc72afc14bdb190026ec9442 Mon Sep 17 00:00:00 2001 From: Ivan Izaguirre Date: Sun, 27 Jan 2019 19:57:17 +0100 Subject: [PATCH] Added the six transfer opcodes --- execute.go | 122 +++++++++++++++++++++++++++--------------------- execute_test.go | 49 ++++++++++++++++++- registers.go | 33 +++++++------ 3 files changed, 132 insertions(+), 72 deletions(-) diff --git a/execute.go b/execute.go index e387b1e..ba68cb8 100644 --- a/execute.go +++ b/execute.go @@ -30,8 +30,6 @@ type opcode struct { name string bytes int cycles int - mode int - reg int action opFunc } @@ -39,71 +37,87 @@ type opFunc func(s *state, line []uint8, opcode opcode) func opNOP(s *state, line []uint8, opcode opcode) {} -func opLDR(s *state, line []uint8, opcode opcode) { - var value uint8 - switch opcode.mode { - case modeImmediate: - value = line[1] - case modeZeroPage: - address := line[1] - value = s.memory[address] - case modeZeroPageX: - address := line[1] + s.registers.getX() - value = s.memory[address] - case modeZeroPageY: - address := line[1] + s.registers.getY() - value = s.memory[address] - case modeAbsolute: - address := getWordInLine(line) - value = s.memory[address] - case modeAbsoluteX: - address := getWordInLine(line) + uint16(s.registers.getX()) - value = s.memory[address] - case modeAbsoluteY: - address := getWordInLine(line) + uint16(s.registers.getY()) - value = s.memory[address] - case modeIndexedIndirectX: - addressAddress := uint8(line[1] + s.registers.getX()) - address := s.memory.getZeroPageWord(addressAddress) - value = s.memory[address] - case modeIndirectIndexedY: - address := s.memory.getZeroPageWord(line[1]) + - uint16(s.registers.getY()) - value = s.memory[address] +func buildOPTransfer(regSrc int, regDst int) opFunc { + return func(s *state, line []uint8, opcode opcode) { + s.registers.setRegister(regDst, s.registers.getRegister(regSrc)) + // TODO: Update flags (N, Z) for all but TXS } +} - s.registers.setRegister(opcode.reg, value) +func buildOpLoad(addressMode int, regDst int) opFunc { + return func(s *state, line []uint8, opcode opcode) { + var value uint8 + switch addressMode { + case modeImmediate: + value = line[1] + case modeZeroPage: + address := line[1] + value = s.memory[address] + case modeZeroPageX: + address := line[1] + s.registers.getX() + value = s.memory[address] + case modeZeroPageY: + address := line[1] + s.registers.getY() + value = s.memory[address] + case modeAbsolute: + address := getWordInLine(line) + value = s.memory[address] + case modeAbsoluteX: + address := getWordInLine(line) + uint16(s.registers.getX()) + value = s.memory[address] + case modeAbsoluteY: + address := getWordInLine(line) + uint16(s.registers.getY()) + value = s.memory[address] + case modeIndexedIndirectX: + addressAddress := uint8(line[1] + s.registers.getX()) + address := s.memory.getZeroPageWord(addressAddress) + value = s.memory[address] + case modeIndirectIndexedY: + address := s.memory.getZeroPageWord(line[1]) + + uint16(s.registers.getY()) + value = s.memory[address] + } - // TODO: Update flags (N, Z) + s.registers.setRegister(regDst, value) + + // TODO: Update flags (N, Z) + } } var opcodes = [256]opcode{ - 0x00: opcode{"BRK", 1, 7, modeImmediate, regNone, opNOP}, + 0x00: opcode{"BRK", 1, 7, opNOP}, - 0xA0: opcode{"LDY", 2, 2, modeImmediate, regY, opLDR}, + 0xA0: opcode{"LDY", 2, 2, buildOpLoad(modeImmediate, regY)}, - 0xA1: opcode{"LDX", 2, 6, modeIndexedIndirectX, regA, opLDR}, + 0xA1: opcode{"LDX", 2, 6, buildOpLoad(modeIndexedIndirectX, regA)}, - 0xA2: opcode{"LDX", 2, 2, modeImmediate, regX, opLDR}, - 0xA4: opcode{"LDY", 2, 3, modeZeroPage, regY, opLDR}, - 0xA5: opcode{"LDA", 2, 3, modeZeroPage, regA, opLDR}, - 0xA6: opcode{"LDX", 2, 3, modeZeroPage, regX, opLDR}, - 0xA9: opcode{"LDA", 2, 2, modeImmediate, regA, opLDR}, + 0xA2: opcode{"LDX", 2, 2, buildOpLoad(modeImmediate, regX)}, + 0xA4: opcode{"LDY", 2, 3, buildOpLoad(modeZeroPage, regY)}, + 0xA5: opcode{"LDA", 2, 3, buildOpLoad(modeZeroPage, regA)}, + 0xA6: opcode{"LDX", 2, 3, buildOpLoad(modeZeroPage, regX)}, + 0xA9: opcode{"LDA", 2, 2, buildOpLoad(modeImmediate, regA)}, - 0xAC: opcode{"LDY", 3, 4, modeAbsolute, regY, opLDR}, - 0xAD: opcode{"LDA", 3, 4, modeAbsolute, regA, opLDR}, - 0xAE: opcode{"LDX", 3, 4, modeAbsolute, regX, opLDR}, + 0xAA: opcode{"TAX", 1, 2, buildOPTransfer(regA, regX)}, + 0xA8: opcode{"TAY", 1, 2, buildOPTransfer(regA, regY)}, + 0xBA: opcode{"TSX", 1, 2, buildOPTransfer(regSP, regX)}, + 0x8A: opcode{"TXA", 1, 2, buildOPTransfer(regX, regA)}, + 0x9A: opcode{"TXS", 1, 2, buildOPTransfer(regX, regSP)}, + 0x98: opcode{"TYA", 1, 2, buildOPTransfer(regY, regA)}, - 0xB1: opcode{"LDX", 2, 5, modeIndirectIndexedY, regA, opLDR}, // Extra cycles + 0xAC: opcode{"LDY", 3, 4, buildOpLoad(modeAbsolute, regY)}, + 0xAD: opcode{"LDA", 3, 4, buildOpLoad(modeAbsolute, regA)}, + 0xAE: opcode{"LDX", 3, 4, buildOpLoad(modeAbsolute, regX)}, - 0xB4: opcode{"LDY", 2, 4, modeZeroPageX, regY, opLDR}, - 0xB5: opcode{"LDA", 2, 4, modeZeroPageX, regA, opLDR}, - 0xB6: opcode{"LDX", 2, 4, modeZeroPageY, regX, opLDR}, + 0xB1: opcode{"LDX", 2, 5, buildOpLoad(modeIndirectIndexedY, regA)}, // Extra cycles - 0xB9: opcode{"LDA", 3, 4, modeAbsoluteY, regA, opLDR}, // Extra cycles - 0xBC: opcode{"LDY", 3, 4, modeAbsoluteX, regY, opLDR}, // Extra cycles - 0xBD: opcode{"LDA", 3, 4, modeAbsoluteX, regA, opLDR}, // Extra cycles - 0xBE: opcode{"LDX", 3, 4, modeAbsoluteY, regX, opLDR}, // Extra cycles + 0xB4: opcode{"LDY", 2, 4, buildOpLoad(modeZeroPageX, regY)}, + 0xB5: opcode{"LDA", 2, 4, buildOpLoad(modeZeroPageX, regA)}, + 0xB6: opcode{"LDX", 2, 4, buildOpLoad(modeZeroPageY, regX)}, + + 0xB9: opcode{"LDA", 3, 4, buildOpLoad(modeAbsoluteY, regA)}, // Extra cycles + 0xBC: opcode{"LDY", 3, 4, buildOpLoad(modeAbsoluteX, regY)}, // Extra cycles + 0xBD: opcode{"LDA", 3, 4, buildOpLoad(modeAbsoluteX, regA)}, // Extra cycles + 0xBE: opcode{"LDX", 3, 4, buildOpLoad(modeAbsoluteY, regX)}, // Extra cycles } func executeLine(s *state, line []uint8) { diff --git a/execute_test.go b/execute_test.go index 82b3e33..dde28e0 100644 --- a/execute_test.go +++ b/execute_test.go @@ -4,7 +4,7 @@ import ( "testing" ) -func TestLDA(t *testing.T) { +func TestLoad(t *testing.T) { var s state executeLine(&s, []uint8{0xA9, 0x42}) @@ -66,4 +66,51 @@ func TestLDA(t *testing.T) { t.Error("Error in LDA (oper,X)") } + s.memory[0x86] = 0x28 + s.memory[0x87] = 0x40 + s.registers.setY(0x10) + s.memory[0x4038] = 0x99 + executeLine(&s, []uint8{0xB1, 0x86}) + if s.registers.getA() != 0x99 { + t.Error("Error in LDA (oper),Y") + } +} + +func TestTransfer(t *testing.T) { + var s state + + s.registers.setA(0xB0) + executeLine(&s, []uint8{0xAA}) + if s.registers.getX() != 0xB0 { + t.Error("Error in TAX") + } + + s.registers.setA(0xB1) + executeLine(&s, []uint8{0xA8}) + if s.registers.getY() != 0xB1 { + t.Error("Error in TAY") + } + + s.registers.setSP(0xB2) + executeLine(&s, []uint8{0xBA}) + if s.registers.getX() != 0xB2 { + t.Error("Error in TSX") + } + + s.registers.setX(0xB3) + executeLine(&s, []uint8{0x8A}) + if s.registers.getA() != 0xB3 { + t.Error("Error in TXA") + } + + s.registers.setX(0xB4) + executeLine(&s, []uint8{0x9A}) + if s.registers.getSP() != 0xB4 { + t.Error("Error in TXS") + } + s.registers.setY(0xB5) + executeLine(&s, []uint8{0x98}) + if s.registers.getA() != 0xB5 { + t.Error("Error in TYA") + } } diff --git a/registers.go b/registers.go index fdef307..3780303 100644 --- a/registers.go +++ b/registers.go @@ -1,13 +1,12 @@ package main const ( - regA = 0 - regX = 1 - regY = 2 - regP = 4 - regS = 5 - regPC = 6 // 2 bytes - regNone = 10 + regA = 0 + regX = 1 + regY = 2 + regP = 4 + regSP = 5 + regPC = 6 // 2 bytes ) type registers struct { @@ -16,20 +15,20 @@ type registers struct { func (r *registers) getRegister(i int) uint8 { return r.data[i] } -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) 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) getSP() uint8 { return r.data[regSP] } func (r *registers) setRegister(i int, v uint8) { r.data[i] = 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) 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) setSP(v uint8) { r.setRegister(regSP, v) } func (r *registers) getPC() uint16 { return uint16(r.data[regPC])*256 + uint16(r.data[regPC+1])