Fixed JSR and BRK. Added disassemble.

This commit is contained in:
Ivan Izaguirre 2019-02-10 16:25:03 +01:00
parent ff0d3d10c9
commit 6e524093c1

View File

@ -11,20 +11,23 @@ func step(s *state) {
} }
const modeNone = -1 const (
const modeImmediate = 0 modeImplicit = iota + 1
const modeZeroPage = 1 modeImplicitX
const modeZeroPageX = 3 modeImplicitY
const modeZeroPageY = 6 modeAccumulator
const modeAbsolute = 2 modeImmediate
const modeAbsoluteX = 4 modeZeroPage
const modeAbsoluteY = 5 modeZeroPageX
const modeIndexedIndirectX = 7 modeZeroPageY
const modeIndirectIndexedY = 8 modeRelative
const modeAccumulator = 9 modeAbsolute
const modeRegisterX = 10 modeAbsoluteX
const modeRegisterY = 11 modeAbsoluteY
const modeIndirect = 12 modeIndirect
modeIndexedIndirectX
modeIndirectIndexedY
)
// https://www.masswerk.at/6502/6502_instruction_set.html // https://www.masswerk.at/6502/6502_instruction_set.html
// http://www.emulator101.com/reference/6502-reference.html // http://www.emulator101.com/reference/6502-reference.html
@ -44,11 +47,11 @@ func resolve(s *state, line []uint8, opcode opcode) (value uint8, address uint16
value = s.registers.getA() value = s.registers.getA()
hasAddress = false hasAddress = false
register = regA register = regA
case modeRegisterX: case modeImplicitX:
value = s.registers.getX() value = s.registers.getX()
hasAddress = false hasAddress = false
register = regX register = regX
case modeRegisterY: case modeImplicitY:
value = s.registers.getY() value = s.registers.getY()
hasAddress = false hasAddress = false
register = regY register = regY
@ -219,7 +222,7 @@ func opADC(s *state, line []uint8, opcode opcode) {
value, _, _ := resolve(s, line, opcode) value, _, _ := resolve(s, line, opcode)
if s.registers.getFlag(flagD) { if s.registers.getFlag(flagD) {
// TODO BCD. See http://www.6502.org/tutorials/decimal_mode.html // TODO BCD. See http://www.6502.org/tutorials/decimal_mode.html
panic("BCD not supported")
} else { } else {
total := uint16(s.registers.getA()) + total := uint16(s.registers.getA()) +
uint16(value) + uint16(value) +
@ -236,6 +239,7 @@ func opSBC(s *state, line []uint8, opcode opcode) {
value, _, _ := resolve(s, line, opcode) value, _, _ := resolve(s, line, opcode)
if s.registers.getFlag(flagD) { if s.registers.getFlag(flagD) {
// TODO BCD // TODO BCD
panic("BCD not supported")
} else { } else {
total := 0x100 + uint16(s.registers.getA()) - total := 0x100 + uint16(s.registers.getA()) -
uint16(value) - uint16(value) -
@ -300,8 +304,9 @@ func opJMP(s *state, line []uint8, opcode opcode) {
func opNOP(s *state, line []uint8, opcode opcode) {} func opNOP(s *state, line []uint8, opcode opcode) {}
func opJSR(s *state, line []uint8, opcode opcode) { func opJSR(s *state, line []uint8, opcode opcode) {
pushWord(s, s.registers.getPC()) pushWord(s, s.registers.getPC()-1)
s.registers.setPC(getWordInLine(line)) _, address, _ := resolve(s, line, opcode)
s.registers.setPC(address)
} }
func opRTI(s *state, line []uint8, opcode opcode) { func opRTI(s *state, line []uint8, opcode opcode) {
@ -310,28 +315,28 @@ func opRTI(s *state, line []uint8, opcode opcode) {
} }
func opRTS(s *state, line []uint8, opcode opcode) { func opRTS(s *state, line []uint8, opcode opcode) {
s.registers.setPC(pullWord(s) + 1) // TODO: Do we really need to add 1? s.registers.setPC(pullWord(s) + 1)
} }
func opBRK(s *state, line []uint8, opcode opcode) { func opBRK(s *state, line []uint8, opcode opcode) {
s.registers.setFlag(flagI) pushWord(s, s.registers.getPC()+1)
pushWord(s, s.registers.getPC()+1) // TODO: De we have to add 1 or 2?
pushByte(s, s.registers.getP()|(flagB+flag5)) pushByte(s, s.registers.getP()|(flagB+flag5))
s.registers.setFlag(flagI)
s.registers.setPC(s.memory.getWord(0xFFFE)) s.registers.setPC(s.memory.getWord(0xFFFE))
} }
var opcodes = [256]opcode{ var opcodes = [256]opcode{
0x00: opcode{"BRK", 1, 7, modeNone, opBRK}, 0x00: opcode{"BRK", 1, 7, modeImplicit, opBRK},
0x4C: opcode{"JMP", 3, 3, modeAbsolute, opJMP}, 0x4C: opcode{"JMP", 3, 3, modeAbsolute, opJMP},
0x6C: opcode{"JMP", 3, 3, modeIndirect, opJMP}, 0x6C: opcode{"JMP", 3, 3, modeIndirect, opJMP},
0x20: opcode{"JSR", 3, 6, modeNone, opJSR}, 0x20: opcode{"JSR", 3, 6, modeAbsolute, opJSR},
0x40: opcode{"RTI", 1, 6, modeNone, opRTI}, 0x40: opcode{"RTI", 1, 6, modeImplicit, opRTI},
0x60: opcode{"RTS", 1, 6, modeNone, opRTS}, 0x60: opcode{"RTS", 1, 6, modeImplicit, opRTS},
0x48: opcode{"PHA", 1, 3, modeNone, opPHA}, 0x48: opcode{"PHA", 1, 3, modeImplicit, opPHA},
0x08: opcode{"PHP", 1, 3, modeNone, opPHP}, 0x08: opcode{"PHP", 1, 3, modeImplicit, opPHP},
0x68: opcode{"PLA", 1, 4, modeNone, opPLA}, 0x68: opcode{"PLA", 1, 4, modeImplicit, opPLA},
0x28: opcode{"PLP", 1, 4, modeNone, opPLP}, 0x28: opcode{"PLP", 1, 4, modeImplicit, opPLP},
0x09: opcode{"ORA", 2, 2, modeImmediate, buildOpLogic(operationOr)}, 0x09: opcode{"ORA", 2, 2, modeImmediate, buildOpLogic(operationOr)},
0x05: opcode{"ORA", 2, 3, modeZeroPage, buildOpLogic(operationOr)}, 0x05: opcode{"ORA", 2, 3, modeZeroPage, buildOpLogic(operationOr)},
@ -379,7 +384,7 @@ var opcodes = [256]opcode{
0xF1: opcode{"SBC", 2, 5, modeIndirectIndexedY, opSBC}, // Extra cycles 0xF1: opcode{"SBC", 2, 5, modeIndirectIndexedY, opSBC}, // Extra cycles
0x24: opcode{"BIT", 2, 3, modeZeroPage, opBIT}, 0x24: opcode{"BIT", 2, 3, modeZeroPage, opBIT},
0x2C: opcode{"BIT", 2, 3, modeAbsolute, opBIT}, 0x2C: opcode{"BIT", 3, 3, modeAbsolute, opBIT},
0xC9: opcode{"CMP", 2, 2, modeImmediate, buildOpCompare(regA)}, 0xC9: opcode{"CMP", 2, 2, modeImmediate, buildOpCompare(regA)},
0xC5: opcode{"CMP", 2, 3, modeZeroPage, buildOpCompare(regA)}, 0xC5: opcode{"CMP", 2, 3, modeZeroPage, buildOpCompare(regA)},
@ -422,13 +427,13 @@ var opcodes = [256]opcode{
0x4E: opcode{"LSR", 3, 6, modeAbsolute, buildOpShift(false, false)}, 0x4E: opcode{"LSR", 3, 6, modeAbsolute, buildOpShift(false, false)},
0x5E: opcode{"LSR", 3, 7, modeAbsoluteX, buildOpShift(false, false)}, 0x5E: opcode{"LSR", 3, 7, modeAbsoluteX, buildOpShift(false, false)},
0x38: opcode{"SEC", 1, 2, modeNone, buildOpUpdateFlag(flagC, true)}, 0x38: opcode{"SEC", 1, 2, modeImplicit, buildOpUpdateFlag(flagC, true)},
0xF8: opcode{"SED", 1, 2, modeNone, buildOpUpdateFlag(flagD, true)}, 0xF8: opcode{"SED", 1, 2, modeImplicit, buildOpUpdateFlag(flagD, true)},
0x78: opcode{"SEI", 1, 2, modeNone, buildOpUpdateFlag(flagI, true)}, 0x78: opcode{"SEI", 1, 2, modeImplicit, buildOpUpdateFlag(flagI, true)},
0x18: opcode{"CLC", 1, 2, modeNone, buildOpUpdateFlag(flagC, false)}, 0x18: opcode{"CLC", 1, 2, modeImplicit, buildOpUpdateFlag(flagC, false)},
0xD8: opcode{"CLD", 1, 2, modeNone, buildOpUpdateFlag(flagD, false)}, 0xD8: opcode{"CLD", 1, 2, modeImplicit, buildOpUpdateFlag(flagD, false)},
0x58: opcode{"CLI", 1, 2, modeNone, buildOpUpdateFlag(flagI, false)}, 0x58: opcode{"CLI", 1, 2, modeImplicit, buildOpUpdateFlag(flagI, false)},
0xB8: opcode{"CLV", 1, 2, modeNone, buildOpUpdateFlag(flagV, false)}, 0xB8: opcode{"CLV", 1, 2, modeImplicit, buildOpUpdateFlag(flagV, false)},
0xE6: opcode{"INC", 2, 5, modeZeroPage, buildOpIncDec(true)}, 0xE6: opcode{"INC", 2, 5, modeZeroPage, buildOpIncDec(true)},
0xF6: opcode{"INC", 2, 6, modeZeroPageX, buildOpIncDec(true)}, 0xF6: opcode{"INC", 2, 6, modeZeroPageX, buildOpIncDec(true)},
@ -438,17 +443,17 @@ var opcodes = [256]opcode{
0xD6: opcode{"DEC", 2, 6, modeZeroPageX, buildOpIncDec(false)}, 0xD6: opcode{"DEC", 2, 6, modeZeroPageX, buildOpIncDec(false)},
0xCE: opcode{"DEC", 3, 6, modeAbsolute, buildOpIncDec(false)}, 0xCE: opcode{"DEC", 3, 6, modeAbsolute, buildOpIncDec(false)},
0xDE: opcode{"DEC", 3, 7, modeAbsoluteX, buildOpIncDec(false)}, 0xDE: opcode{"DEC", 3, 7, modeAbsoluteX, buildOpIncDec(false)},
0xE8: opcode{"INX", 1, 2, modeRegisterX, buildOpIncDec(true)}, 0xE8: opcode{"INX", 1, 2, modeImplicitX, buildOpIncDec(true)},
0xC8: opcode{"INY", 1, 2, modeRegisterY, buildOpIncDec(true)}, 0xC8: opcode{"INY", 1, 2, modeImplicitY, buildOpIncDec(true)},
0xCA: opcode{"DEX", 1, 2, modeRegisterX, buildOpIncDec(false)}, 0xCA: opcode{"DEX", 1, 2, modeImplicitX, buildOpIncDec(false)},
0x88: opcode{"DEY", 1, 2, modeRegisterY, buildOpIncDec(false)}, 0x88: opcode{"DEY", 1, 2, modeImplicitY, buildOpIncDec(false)},
0xAA: opcode{"TAX", 1, 2, modeNone, buildOpTransfer(regA, regX)}, 0xAA: opcode{"TAX", 1, 2, modeImplicit, buildOpTransfer(regA, regX)},
0xA8: opcode{"TAY", 1, 2, modeNone, buildOpTransfer(regA, regY)}, 0xA8: opcode{"TAY", 1, 2, modeImplicit, buildOpTransfer(regA, regY)},
0x8A: opcode{"TXA", 1, 2, modeNone, buildOpTransfer(regX, regA)}, 0x8A: opcode{"TXA", 1, 2, modeImplicit, buildOpTransfer(regX, regA)},
0x98: opcode{"TYA", 1, 2, modeNone, buildOpTransfer(regY, regA)}, 0x98: opcode{"TYA", 1, 2, modeImplicit, buildOpTransfer(regY, regA)},
0x9A: opcode{"TXS", 1, 2, modeNone, buildOpTransfer(regX, regSP)}, 0x9A: opcode{"TXS", 1, 2, modeImplicit, buildOpTransfer(regX, regSP)},
0xBA: opcode{"TSX", 1, 2, modeNone, buildOpTransfer(regSP, regX)}, 0xBA: opcode{"TSX", 1, 2, modeImplicit, buildOpTransfer(regSP, regX)},
0xA9: opcode{"LDA", 2, 2, modeImmediate, buildOpLoad(regA)}, 0xA9: opcode{"LDA", 2, 2, modeImmediate, buildOpLoad(regA)},
0xA5: opcode{"LDA", 2, 3, modeZeroPage, buildOpLoad(regA)}, 0xA5: opcode{"LDA", 2, 3, modeZeroPage, buildOpLoad(regA)},
@ -483,16 +488,16 @@ var opcodes = [256]opcode{
0x94: opcode{"STY", 2, 4, modeZeroPageX, buildOpStore(regY)}, 0x94: opcode{"STY", 2, 4, modeZeroPageX, buildOpStore(regY)},
0x8C: opcode{"STY", 3, 4, modeAbsolute, buildOpStore(regY)}, 0x8C: opcode{"STY", 3, 4, modeAbsolute, buildOpStore(regY)},
0x90: opcode{"BCC", 2, 2, modeNone, buildOpBranch(flagC, false)}, // Extra cycles 0x90: opcode{"BCC", 2, 2, modeRelative, buildOpBranch(flagC, false)}, // Extra cycles
0xB0: opcode{"BCS", 2, 2, modeNone, buildOpBranch(flagC, true)}, // Extra cycles 0xB0: opcode{"BCS", 2, 2, modeRelative, buildOpBranch(flagC, true)}, // Extra cycles
0xD0: opcode{"BNE", 2, 2, modeNone, buildOpBranch(flagZ, false)}, // Extra cycles 0xD0: opcode{"BNE", 2, 2, modeRelative, buildOpBranch(flagZ, false)}, // Extra cycles
0xF0: opcode{"BEQ", 2, 2, modeNone, buildOpBranch(flagZ, true)}, // Extra cycles 0xF0: opcode{"BEQ", 2, 2, modeRelative, buildOpBranch(flagZ, true)}, // Extra cycles
0x10: opcode{"BPL", 2, 2, modeNone, buildOpBranch(flagN, false)}, // Extra cycles 0x10: opcode{"BPL", 2, 2, modeRelative, buildOpBranch(flagN, false)}, // Extra cycles
0x30: opcode{"BMI", 2, 2, modeNone, buildOpBranch(flagN, true)}, // Extra cycles 0x30: opcode{"BMI", 2, 2, modeRelative, buildOpBranch(flagN, true)}, // Extra cycles
0x50: opcode{"BVC", 2, 2, modeNone, buildOpBranch(flagV, false)}, // Extra cycles 0x50: opcode{"BVC", 2, 2, modeRelative, buildOpBranch(flagV, false)}, // Extra cycles
0x70: opcode{"BVS", 2, 2, modeNone, buildOpBranch(flagV, true)}, // Extra cycles 0x70: opcode{"BVS", 2, 2, modeRelative, buildOpBranch(flagV, true)}, // Extra cycles
0xEA: opcode{"NOP", 1, 2, modeNone, opNOP}, 0xEA: opcode{"NOP", 1, 2, modeImplicit, opNOP},
} }
func executeLine(s *state, line []uint8) { func executeLine(s *state, line []uint8) {
@ -503,10 +508,47 @@ func executeLine(s *state, line []uint8) {
func executeInstruction(s *state) { func executeInstruction(s *state) {
pc := s.registers.getPC() pc := s.registers.getPC()
opcode := opcodes[s.memory[pc]] opcode := opcodes[s.memory[pc]]
fmt.Printf("%#04x %s: ", pc, opcode.name)
pcNext := pc + uint16(opcode.bytes) pcNext := pc + uint16(opcode.bytes)
s.registers.setPC(pcNext) s.registers.setPC(pcNext)
line := s.memory[pc:pcNext] line := s.memory[pc:pcNext]
fmt.Printf("%#04x %-10s: ", pc, lineString(s, line, opcode))
opcode.action(s, line, opcode) opcode.action(s, line, opcode)
fmt.Printf("%v, %v\n", s.registers, line) fmt.Printf("%v, %x\n", s.registers, line)
}
func lineString(s *state, line []uint8, opcode opcode) string {
t := opcode.name
switch opcode.addressMode {
case modeImplicit:
case modeImplicitX:
case modeImplicitY:
//Nothing
case modeAccumulator:
t += fmt.Sprintf(" A")
case modeImmediate:
t += fmt.Sprintf(" #%02x", line[1])
case modeZeroPage:
t += fmt.Sprintf(" $%02x", line[1])
case modeZeroPageX:
t += fmt.Sprintf(" $%02x,X", line[1])
case modeZeroPageY:
t += fmt.Sprintf(" $%02x,Y", line[1])
case modeRelative:
t += fmt.Sprintf(" *%+x", int8(line[1]))
case modeAbsolute:
t += fmt.Sprintf(" $%04x", getWordInLine(line))
case modeAbsoluteX:
t += fmt.Sprintf(" $%04x,X", getWordInLine(line))
case modeAbsoluteY:
t += fmt.Sprintf(" $%04x,X", getWordInLine(line))
case modeIndirect:
t += fmt.Sprintf(" ($%04x)", getWordInLine(line))
case modeIndexedIndirectX:
t += fmt.Sprintf(" ($%02x,X)", line[1])
case modeIndirectIndexedY:
t += fmt.Sprintf(" ($%02x),Y", line[1])
default:
t += "UNKNOWN MODE"
}
return t
} }