2019-02-28 22:54:38 +00:00
|
|
|
package core6502
|
|
|
|
|
2019-10-10 22:06:42 +00:00
|
|
|
import "fmt"
|
|
|
|
|
2019-02-28 22:54:38 +00:00
|
|
|
const (
|
|
|
|
modeImplicit = iota + 1
|
|
|
|
modeImplicitX
|
|
|
|
modeImplicitY
|
|
|
|
modeAccumulator
|
|
|
|
modeImmediate
|
|
|
|
modeZeroPage
|
|
|
|
modeZeroPageX
|
|
|
|
modeZeroPageY
|
|
|
|
modeRelative
|
|
|
|
modeAbsolute
|
|
|
|
modeAbsoluteX
|
|
|
|
modeAbsoluteY
|
|
|
|
modeIndirect
|
|
|
|
modeIndexedIndirectX
|
|
|
|
modeIndirectIndexedY
|
2019-10-10 22:06:42 +00:00
|
|
|
// Added on the 65c02
|
|
|
|
modeIndirectZeroPage
|
|
|
|
modeAbsoluteIndexedIndirectX
|
|
|
|
modeZeroPageAndRelative
|
2019-02-28 22:54:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func getWordInLine(line []uint8) uint16 {
|
|
|
|
return uint16(line[1]) + 0x100*uint16(line[2])
|
|
|
|
}
|
|
|
|
|
|
|
|
func resolveValue(s *State, line []uint8, opcode opcode) uint8 {
|
|
|
|
getValue, _, _ := resolve(s, line, opcode)
|
|
|
|
return getValue()
|
|
|
|
}
|
|
|
|
|
|
|
|
func resolveGetSetValue(s *State, line []uint8, opcode opcode) (value uint8, setValue func(uint8)) {
|
|
|
|
getValue, setValue, _ := resolve(s, line, opcode)
|
|
|
|
value = getValue()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func resolveSetValue(s *State, line []uint8, opcode opcode) func(uint8) {
|
|
|
|
_, setValue, _ := resolve(s, line, opcode)
|
|
|
|
return setValue
|
|
|
|
}
|
|
|
|
|
|
|
|
func resolveAddress(s *State, line []uint8, opcode opcode) uint16 {
|
|
|
|
_, _, address := resolve(s, line, opcode)
|
|
|
|
return address
|
|
|
|
}
|
|
|
|
|
|
|
|
func resolve(s *State, line []uint8, opcode opcode) (getValue func() uint8, setValue func(uint8), address uint16) {
|
|
|
|
hasAddress := true
|
|
|
|
register := regNone
|
|
|
|
|
|
|
|
switch opcode.addressMode {
|
|
|
|
case modeAccumulator:
|
|
|
|
getValue = func() uint8 { return s.reg.getA() }
|
|
|
|
hasAddress = false
|
|
|
|
register = regA
|
|
|
|
case modeImplicitX:
|
|
|
|
getValue = func() uint8 { return s.reg.getX() }
|
|
|
|
hasAddress = false
|
|
|
|
register = regX
|
|
|
|
case modeImplicitY:
|
|
|
|
getValue = func() uint8 { return s.reg.getY() }
|
|
|
|
hasAddress = false
|
|
|
|
register = regY
|
|
|
|
case modeImmediate:
|
|
|
|
getValue = func() uint8 { return line[1] }
|
|
|
|
hasAddress = false
|
|
|
|
case modeZeroPage:
|
|
|
|
address = uint16(line[1])
|
|
|
|
case modeZeroPageX:
|
|
|
|
address = uint16(line[1] + s.reg.getX())
|
|
|
|
case modeZeroPageY:
|
|
|
|
address = uint16(line[1] + s.reg.getY())
|
|
|
|
case modeAbsolute:
|
|
|
|
address = getWordInLine(line)
|
|
|
|
case modeAbsoluteX:
|
|
|
|
address = getWordInLine(line) + uint16(s.reg.getX())
|
|
|
|
case modeAbsoluteY:
|
|
|
|
address = getWordInLine(line) + uint16(s.reg.getY())
|
|
|
|
case modeIndexedIndirectX:
|
|
|
|
addressAddress := uint8(line[1] + s.reg.getX())
|
|
|
|
address = getZeroPageWord(s.mem, addressAddress)
|
|
|
|
case modeIndirect:
|
|
|
|
addressAddress := getWordInLine(line)
|
|
|
|
address = getWord(s.mem, addressAddress)
|
|
|
|
case modeIndirectIndexedY:
|
|
|
|
address = getZeroPageWord(s.mem, line[1]) +
|
|
|
|
uint16(s.reg.getY())
|
2019-10-10 22:06:42 +00:00
|
|
|
// 65c02 additions
|
|
|
|
case modeIndirectZeroPage:
|
|
|
|
address = getZeroPageWord(s.mem, line[1])
|
|
|
|
case modeAbsoluteIndexedIndirectX:
|
|
|
|
addressAddress := getWordInLine(line) + uint16(s.reg.getX())
|
|
|
|
address = getWord(s.mem, addressAddress)
|
|
|
|
case modeRelative:
|
|
|
|
// This assumes that PC is already pointing to the next instruction
|
|
|
|
address = s.reg.getPC() + uint16(int8(line[1])) // Note: line[1] is signed
|
|
|
|
case modeZeroPageAndRelative:
|
|
|
|
// Two addressing modes combined. We refer to the second one, relative,
|
|
|
|
// placed one byte after the zeropage reference
|
|
|
|
address = s.reg.getPC() + uint16(int8(line[2])) // Note: line[2] is signed
|
|
|
|
|
|
|
|
default:
|
|
|
|
panic("Assert failed. Missing addressing mode")
|
2019-02-28 22:54:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if hasAddress {
|
|
|
|
getValue = func() uint8 { return s.mem.Peek(address) }
|
|
|
|
}
|
|
|
|
|
|
|
|
setValue = func(value uint8) {
|
|
|
|
if hasAddress {
|
|
|
|
s.mem.Poke(address, value)
|
|
|
|
} else if register != regNone {
|
|
|
|
s.reg.setRegister(register, value)
|
|
|
|
} else {
|
2019-10-05 23:26:00 +00:00
|
|
|
panic("Assert failed. Should never happen")
|
2019-02-28 22:54:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2019-10-10 22:06:42 +00:00
|
|
|
|
|
|
|
func lineString(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,Y", 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])
|
|
|
|
// 65c02 additions:
|
|
|
|
case modeIndirectZeroPage:
|
|
|
|
t += fmt.Sprintf(" ($%02x)", line[1])
|
|
|
|
case modeAbsoluteIndexedIndirectX:
|
|
|
|
t += fmt.Sprintf(" ($%04x,X)", getWordInLine(line))
|
|
|
|
case modeZeroPageAndRelative:
|
|
|
|
t += fmt.Sprintf(" $%02x *%+x", line[1], int8(line[2]))
|
|
|
|
default:
|
|
|
|
t += "UNKNOWN MODE"
|
|
|
|
}
|
|
|
|
return t
|
|
|
|
}
|