mirror of
https://github.com/ivanizag/izapple2.git
synced 2024-06-15 08:29:28 +00:00
Fixed JSR and BRK. Added disassemble.
This commit is contained in:
parent
ff0d3d10c9
commit
6e524093c1
160
execute.go
160
execute.go
|
@ -11,20 +11,23 @@ func step(s *state) {
|
|||
|
||||
}
|
||||
|
||||
const modeNone = -1
|
||||
const modeImmediate = 0
|
||||
const modeZeroPage = 1
|
||||
const modeZeroPageX = 3
|
||||
const modeZeroPageY = 6
|
||||
const modeAbsolute = 2
|
||||
const modeAbsoluteX = 4
|
||||
const modeAbsoluteY = 5
|
||||
const modeIndexedIndirectX = 7
|
||||
const modeIndirectIndexedY = 8
|
||||
const modeAccumulator = 9
|
||||
const modeRegisterX = 10
|
||||
const modeRegisterY = 11
|
||||
const modeIndirect = 12
|
||||
const (
|
||||
modeImplicit = iota + 1
|
||||
modeImplicitX
|
||||
modeImplicitY
|
||||
modeAccumulator
|
||||
modeImmediate
|
||||
modeZeroPage
|
||||
modeZeroPageX
|
||||
modeZeroPageY
|
||||
modeRelative
|
||||
modeAbsolute
|
||||
modeAbsoluteX
|
||||
modeAbsoluteY
|
||||
modeIndirect
|
||||
modeIndexedIndirectX
|
||||
modeIndirectIndexedY
|
||||
)
|
||||
|
||||
// https://www.masswerk.at/6502/6502_instruction_set.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()
|
||||
hasAddress = false
|
||||
register = regA
|
||||
case modeRegisterX:
|
||||
case modeImplicitX:
|
||||
value = s.registers.getX()
|
||||
hasAddress = false
|
||||
register = regX
|
||||
case modeRegisterY:
|
||||
case modeImplicitY:
|
||||
value = s.registers.getY()
|
||||
hasAddress = false
|
||||
register = regY
|
||||
|
@ -219,7 +222,7 @@ func opADC(s *state, line []uint8, opcode opcode) {
|
|||
value, _, _ := resolve(s, line, opcode)
|
||||
if s.registers.getFlag(flagD) {
|
||||
// TODO BCD. See http://www.6502.org/tutorials/decimal_mode.html
|
||||
|
||||
panic("BCD not supported")
|
||||
} else {
|
||||
total := uint16(s.registers.getA()) +
|
||||
uint16(value) +
|
||||
|
@ -236,6 +239,7 @@ func opSBC(s *state, line []uint8, opcode opcode) {
|
|||
value, _, _ := resolve(s, line, opcode)
|
||||
if s.registers.getFlag(flagD) {
|
||||
// TODO BCD
|
||||
panic("BCD not supported")
|
||||
} else {
|
||||
total := 0x100 + uint16(s.registers.getA()) -
|
||||
uint16(value) -
|
||||
|
@ -300,8 +304,9 @@ func opJMP(s *state, line []uint8, opcode opcode) {
|
|||
func opNOP(s *state, line []uint8, opcode opcode) {}
|
||||
|
||||
func opJSR(s *state, line []uint8, opcode opcode) {
|
||||
pushWord(s, s.registers.getPC())
|
||||
s.registers.setPC(getWordInLine(line))
|
||||
pushWord(s, s.registers.getPC()-1)
|
||||
_, address, _ := resolve(s, line, opcode)
|
||||
s.registers.setPC(address)
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
s.registers.setFlag(flagI)
|
||||
pushWord(s, s.registers.getPC()+1) // TODO: De we have to add 1 or 2?
|
||||
pushWord(s, s.registers.getPC()+1)
|
||||
pushByte(s, s.registers.getP()|(flagB+flag5))
|
||||
s.registers.setFlag(flagI)
|
||||
s.registers.setPC(s.memory.getWord(0xFFFE))
|
||||
}
|
||||
|
||||
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},
|
||||
0x6C: opcode{"JMP", 3, 3, modeIndirect, opJMP},
|
||||
0x20: opcode{"JSR", 3, 6, modeNone, opJSR},
|
||||
0x40: opcode{"RTI", 1, 6, modeNone, opRTI},
|
||||
0x60: opcode{"RTS", 1, 6, modeNone, opRTS},
|
||||
0x20: opcode{"JSR", 3, 6, modeAbsolute, opJSR},
|
||||
0x40: opcode{"RTI", 1, 6, modeImplicit, opRTI},
|
||||
0x60: opcode{"RTS", 1, 6, modeImplicit, opRTS},
|
||||
|
||||
0x48: opcode{"PHA", 1, 3, modeNone, opPHA},
|
||||
0x08: opcode{"PHP", 1, 3, modeNone, opPHP},
|
||||
0x68: opcode{"PLA", 1, 4, modeNone, opPLA},
|
||||
0x28: opcode{"PLP", 1, 4, modeNone, opPLP},
|
||||
0x48: opcode{"PHA", 1, 3, modeImplicit, opPHA},
|
||||
0x08: opcode{"PHP", 1, 3, modeImplicit, opPHP},
|
||||
0x68: opcode{"PLA", 1, 4, modeImplicit, opPLA},
|
||||
0x28: opcode{"PLP", 1, 4, modeImplicit, opPLP},
|
||||
|
||||
0x09: opcode{"ORA", 2, 2, modeImmediate, 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
|
||||
|
||||
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)},
|
||||
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)},
|
||||
0x5E: opcode{"LSR", 3, 7, modeAbsoluteX, buildOpShift(false, false)},
|
||||
|
||||
0x38: opcode{"SEC", 1, 2, modeNone, buildOpUpdateFlag(flagC, true)},
|
||||
0xF8: opcode{"SED", 1, 2, modeNone, buildOpUpdateFlag(flagD, true)},
|
||||
0x78: opcode{"SEI", 1, 2, modeNone, buildOpUpdateFlag(flagI, true)},
|
||||
0x18: opcode{"CLC", 1, 2, modeNone, buildOpUpdateFlag(flagC, false)},
|
||||
0xD8: opcode{"CLD", 1, 2, modeNone, buildOpUpdateFlag(flagD, false)},
|
||||
0x58: opcode{"CLI", 1, 2, modeNone, buildOpUpdateFlag(flagI, false)},
|
||||
0xB8: opcode{"CLV", 1, 2, modeNone, buildOpUpdateFlag(flagV, false)},
|
||||
0x38: opcode{"SEC", 1, 2, modeImplicit, buildOpUpdateFlag(flagC, true)},
|
||||
0xF8: opcode{"SED", 1, 2, modeImplicit, buildOpUpdateFlag(flagD, true)},
|
||||
0x78: opcode{"SEI", 1, 2, modeImplicit, buildOpUpdateFlag(flagI, true)},
|
||||
0x18: opcode{"CLC", 1, 2, modeImplicit, buildOpUpdateFlag(flagC, false)},
|
||||
0xD8: opcode{"CLD", 1, 2, modeImplicit, buildOpUpdateFlag(flagD, false)},
|
||||
0x58: opcode{"CLI", 1, 2, modeImplicit, buildOpUpdateFlag(flagI, false)},
|
||||
0xB8: opcode{"CLV", 1, 2, modeImplicit, buildOpUpdateFlag(flagV, false)},
|
||||
|
||||
0xE6: opcode{"INC", 2, 5, modeZeroPage, 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)},
|
||||
0xCE: opcode{"DEC", 3, 6, modeAbsolute, buildOpIncDec(false)},
|
||||
0xDE: opcode{"DEC", 3, 7, modeAbsoluteX, buildOpIncDec(false)},
|
||||
0xE8: opcode{"INX", 1, 2, modeRegisterX, buildOpIncDec(true)},
|
||||
0xC8: opcode{"INY", 1, 2, modeRegisterY, buildOpIncDec(true)},
|
||||
0xCA: opcode{"DEX", 1, 2, modeRegisterX, buildOpIncDec(false)},
|
||||
0x88: opcode{"DEY", 1, 2, modeRegisterY, buildOpIncDec(false)},
|
||||
0xE8: opcode{"INX", 1, 2, modeImplicitX, buildOpIncDec(true)},
|
||||
0xC8: opcode{"INY", 1, 2, modeImplicitY, buildOpIncDec(true)},
|
||||
0xCA: opcode{"DEX", 1, 2, modeImplicitX, buildOpIncDec(false)},
|
||||
0x88: opcode{"DEY", 1, 2, modeImplicitY, buildOpIncDec(false)},
|
||||
|
||||
0xAA: opcode{"TAX", 1, 2, modeNone, buildOpTransfer(regA, regX)},
|
||||
0xA8: opcode{"TAY", 1, 2, modeNone, buildOpTransfer(regA, regY)},
|
||||
0x8A: opcode{"TXA", 1, 2, modeNone, buildOpTransfer(regX, regA)},
|
||||
0x98: opcode{"TYA", 1, 2, modeNone, buildOpTransfer(regY, regA)},
|
||||
0x9A: opcode{"TXS", 1, 2, modeNone, buildOpTransfer(regX, regSP)},
|
||||
0xBA: opcode{"TSX", 1, 2, modeNone, buildOpTransfer(regSP, regX)},
|
||||
0xAA: opcode{"TAX", 1, 2, modeImplicit, buildOpTransfer(regA, regX)},
|
||||
0xA8: opcode{"TAY", 1, 2, modeImplicit, buildOpTransfer(regA, regY)},
|
||||
0x8A: opcode{"TXA", 1, 2, modeImplicit, buildOpTransfer(regX, regA)},
|
||||
0x98: opcode{"TYA", 1, 2, modeImplicit, buildOpTransfer(regY, regA)},
|
||||
0x9A: opcode{"TXS", 1, 2, modeImplicit, buildOpTransfer(regX, regSP)},
|
||||
0xBA: opcode{"TSX", 1, 2, modeImplicit, buildOpTransfer(regSP, regX)},
|
||||
|
||||
0xA9: opcode{"LDA", 2, 2, modeImmediate, 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)},
|
||||
0x8C: opcode{"STY", 3, 4, modeAbsolute, buildOpStore(regY)},
|
||||
|
||||
0x90: opcode{"BCC", 2, 2, modeNone, buildOpBranch(flagC, false)}, // Extra cycles
|
||||
0xB0: opcode{"BCS", 2, 2, modeNone, buildOpBranch(flagC, true)}, // Extra cycles
|
||||
0xD0: opcode{"BNE", 2, 2, modeNone, buildOpBranch(flagZ, false)}, // Extra cycles
|
||||
0xF0: opcode{"BEQ", 2, 2, modeNone, buildOpBranch(flagZ, true)}, // Extra cycles
|
||||
0x10: opcode{"BPL", 2, 2, modeNone, buildOpBranch(flagN, false)}, // Extra cycles
|
||||
0x30: opcode{"BMI", 2, 2, modeNone, buildOpBranch(flagN, true)}, // Extra cycles
|
||||
0x50: opcode{"BVC", 2, 2, modeNone, buildOpBranch(flagV, false)}, // Extra cycles
|
||||
0x70: opcode{"BVS", 2, 2, modeNone, buildOpBranch(flagV, true)}, // Extra cycles
|
||||
0x90: opcode{"BCC", 2, 2, modeRelative, buildOpBranch(flagC, false)}, // Extra cycles
|
||||
0xB0: opcode{"BCS", 2, 2, modeRelative, buildOpBranch(flagC, true)}, // Extra cycles
|
||||
0xD0: opcode{"BNE", 2, 2, modeRelative, buildOpBranch(flagZ, false)}, // Extra cycles
|
||||
0xF0: opcode{"BEQ", 2, 2, modeRelative, buildOpBranch(flagZ, true)}, // Extra cycles
|
||||
0x10: opcode{"BPL", 2, 2, modeRelative, buildOpBranch(flagN, false)}, // Extra cycles
|
||||
0x30: opcode{"BMI", 2, 2, modeRelative, buildOpBranch(flagN, true)}, // Extra cycles
|
||||
0x50: opcode{"BVC", 2, 2, modeRelative, buildOpBranch(flagV, false)}, // 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) {
|
||||
|
@ -503,10 +508,47 @@ func executeLine(s *state, line []uint8) {
|
|||
func executeInstruction(s *state) {
|
||||
pc := s.registers.getPC()
|
||||
opcode := opcodes[s.memory[pc]]
|
||||
fmt.Printf("%#04x %s: ", pc, opcode.name)
|
||||
pcNext := pc + uint16(opcode.bytes)
|
||||
s.registers.setPC(pcNext)
|
||||
line := s.memory[pc:pcNext]
|
||||
fmt.Printf("%#04x %-10s: ", pc, lineString(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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user