1
0
mirror of https://github.com/zellyn/go6502.git synced 2024-11-05 07:04:41 +00:00
go6502/opcodes/opcodes.go
2014-05-01 08:23:26 -07:00

301 lines
8.3 KiB
Go

/*
Package opcodes stores metadata/information about 6502 opcodes. It's
used for disassembly, and (in the future) for building the opcode
function tables.
*/
package opcodes
// Opcode addressing modes.
type AddressingMode uint
const MODE_UNKNOWN = 0
const (
MODE_IMPLIED AddressingMode = 1 << iota
MODE_ABSOLUTE
MODE_INDIRECT
MODE_RELATIVE
MODE_IMMEDIATE
MODE_ABS_X
MODE_ABS_Y
MODE_ZP
MODE_ZP_X
MODE_ZP_Y
MODE_INDIRECT_Y
MODE_INDIRECT_X
MODE_A
)
// Logical OR of the three indirect modes
const MODE_INDIRECT_ANY AddressingMode = MODE_INDIRECT | MODE_INDIRECT_X | MODE_INDIRECT_Y
// Opcode read/write semantics: does the opcode read, write, or
// rmw. Useful to distinguish between instructions further than just
// addressing mode.
type ReadWrite int
const (
RW_X ReadWrite = 0 // Don't care
RW_R ReadWrite = 1
RW_W ReadWrite = 2
RW_RMW ReadWrite = 3
)
// Lengths of instructions for each addressing mode.
var ModeLengths = map[AddressingMode]int{
MODE_IMPLIED: 1,
MODE_ABSOLUTE: 3,
MODE_INDIRECT: 3,
MODE_RELATIVE: 2,
MODE_IMMEDIATE: 2,
MODE_ABS_X: 3,
MODE_ABS_Y: 3,
MODE_ZP: 2,
MODE_ZP_X: 2,
MODE_ZP_Y: 2,
MODE_INDIRECT_Y: 2,
MODE_INDIRECT_X: 2,
MODE_A: 1,
}
// Opcode stores information about instructions.
type Opcode struct {
Name string
Mode AddressingMode
RW ReadWrite
}
// Fake NoOp instruction used when disassembling.
var NoOp = Opcode{"???", MODE_IMPLIED, RW_X}
// The list of Opcodes.
var Opcodes = map[byte]Opcode{
// BUG(zellyn): Add 65C02 instructions.
// Flag set and clear
0x18: {"CLC", MODE_IMPLIED, RW_X}, // CLC
0xD8: {"CLD", MODE_IMPLIED, RW_X}, // CLD
0x58: {"CLI", MODE_IMPLIED, RW_X}, // CLI
0xB8: {"CLV", MODE_IMPLIED, RW_X}, // CLV
0x38: {"SEC", MODE_IMPLIED, RW_X}, // SEC
0xF8: {"SED", MODE_IMPLIED, RW_X}, // SED
0x78: {"SEI", MODE_IMPLIED, RW_X}, // SEI
// Very simple 1-opcode instructions
0xEA: {"NOP", MODE_IMPLIED, RW_X},
0xAA: {"TAX", MODE_IMPLIED, RW_X},
0xA8: {"TAY", MODE_IMPLIED, RW_X},
0xBA: {"TSX", MODE_IMPLIED, RW_X},
0x8A: {"TXA", MODE_IMPLIED, RW_X},
0x9A: {"TXS", MODE_IMPLIED, RW_X},
0x98: {"TYA", MODE_IMPLIED, RW_X},
// Slightly more complex 1-opcode instructions
0xCA: {"DEX", MODE_IMPLIED, RW_X},
0x88: {"DEY", MODE_IMPLIED, RW_X},
0xE8: {"INX", MODE_IMPLIED, RW_X},
0xC8: {"INY", MODE_IMPLIED, RW_X},
0x48: {"PHA", MODE_IMPLIED, RW_X},
0x08: {"PHP", MODE_IMPLIED, RW_X},
0x68: {"PLA", MODE_IMPLIED, RW_X},
0x28: {"PLP", MODE_IMPLIED, RW_X},
// Jumps, returns, etc.
0x4C: {"JMP", MODE_ABSOLUTE, RW_X},
0x6C: {"JMP", MODE_INDIRECT, RW_X},
0x20: {"JSR", MODE_ABSOLUTE, RW_X},
0x60: {"RTS", MODE_IMPLIED, RW_X},
0x40: {"RTI", MODE_IMPLIED, RW_X},
0x00: {"BRK", MODE_IMPLIED, RW_X},
// Branches
0x90: {"BCC", MODE_RELATIVE, RW_X}, // BCC
0xB0: {"BCS", MODE_RELATIVE, RW_X}, // BCS
0xF0: {"BEQ", MODE_RELATIVE, RW_X}, // BEQ
0x30: {"BMI", MODE_RELATIVE, RW_X}, // BMI
0xD0: {"BNE", MODE_RELATIVE, RW_X}, // BNE
0x10: {"BPL", MODE_RELATIVE, RW_X}, // BPL
0x50: {"BVC", MODE_RELATIVE, RW_X}, // BVC
0x70: {"BVS", MODE_RELATIVE, RW_X}, // BVS
// 2-opcode, 2-cycle immediate mode
0x09: {"ORA", MODE_IMMEDIATE, RW_R},
0x29: {"AND", MODE_IMMEDIATE, RW_R},
0x49: {"EOR", MODE_IMMEDIATE, RW_R},
0x69: {"ADC", MODE_IMMEDIATE, RW_R},
0xC0: {"CPY", MODE_IMMEDIATE, RW_R},
0xC9: {"CMP", MODE_IMMEDIATE, RW_R},
0xA0: {"LDY", MODE_IMMEDIATE, RW_R},
0xA2: {"LDX", MODE_IMMEDIATE, RW_R},
0xA9: {"LDA", MODE_IMMEDIATE, RW_R},
0xE0: {"CPX", MODE_IMMEDIATE, RW_R},
0xE9: {"SBC", MODE_IMMEDIATE, RW_R},
// 3-opcode, 4-cycle absolute mode
0x8D: {"STA", MODE_ABSOLUTE, RW_W},
0x8E: {"STX", MODE_ABSOLUTE, RW_W},
0x8C: {"STY", MODE_ABSOLUTE, RW_W},
0x6D: {"ADC", MODE_ABSOLUTE, RW_R},
0x2D: {"AND", MODE_ABSOLUTE, RW_R},
0x2C: {"BIT", MODE_ABSOLUTE, RW_R},
0xCD: {"CMP", MODE_ABSOLUTE, RW_R},
0xEC: {"CPX", MODE_ABSOLUTE, RW_R},
0xCC: {"CPY", MODE_ABSOLUTE, RW_R},
0x4D: {"EOR", MODE_ABSOLUTE, RW_R},
0xAD: {"LDA", MODE_ABSOLUTE, RW_R},
0xAE: {"LDX", MODE_ABSOLUTE, RW_R},
0xAC: {"LDY", MODE_ABSOLUTE, RW_R},
0x0D: {"ORA", MODE_ABSOLUTE, RW_R},
0xED: {"SBC", MODE_ABSOLUTE, RW_R},
// 2-opcode, 3-cycle zero page
0x05: {"ORA", MODE_ZP, RW_R},
0x24: {"BIT", MODE_ZP, RW_R},
0x25: {"AND", MODE_ZP, RW_R},
0x45: {"EOR", MODE_ZP, RW_R},
0x65: {"ADC", MODE_ZP, RW_R},
0x84: {"STY", MODE_ZP, RW_W},
0x85: {"STA", MODE_ZP, RW_W},
0x86: {"STX", MODE_ZP, RW_W},
0xA4: {"LDY", MODE_ZP, RW_R},
0xA5: {"LDA", MODE_ZP, RW_R},
0xA6: {"LDX", MODE_ZP, RW_R},
0xC4: {"CPY", MODE_ZP, RW_R},
0xC5: {"CMP", MODE_ZP, RW_R},
0xE4: {"CPX", MODE_ZP, RW_R},
0xE5: {"SBC", MODE_ZP, RW_R},
// 3-opcode, 4*-cycle abs,X/Y
0x1D: {"ORA", MODE_ABS_X, RW_R},
0x19: {"ORA", MODE_ABS_Y, RW_R},
0x39: {"AND", MODE_ABS_Y, RW_R},
0x3D: {"AND", MODE_ABS_X, RW_R},
0x59: {"EOR", MODE_ABS_Y, RW_R},
0x5D: {"EOR", MODE_ABS_X, RW_R},
0x79: {"ADC", MODE_ABS_Y, RW_R},
0x7D: {"ADC", MODE_ABS_X, RW_R},
0xB9: {"LDA", MODE_ABS_Y, RW_R},
0xBD: {"LDA", MODE_ABS_X, RW_R},
0xD9: {"CMP", MODE_ABS_Y, RW_R},
0xDD: {"CMP", MODE_ABS_X, RW_R},
0xF9: {"SBC", MODE_ABS_Y, RW_R},
0xFD: {"SBC", MODE_ABS_X, RW_R},
0xBE: {"LDX", MODE_ABS_Y, RW_R},
0xBC: {"LDY", MODE_ABS_X, RW_R},
// 3-opcode, 5-cycle abs,X/Y
0x99: {"STA", MODE_ABS_Y, RW_W},
0x9D: {"STA", MODE_ABS_X, RW_W},
// 2-opcode, 4-cycle zp,X/Y
0x15: {"ORA", MODE_ZP_X, RW_R},
0x35: {"AND", MODE_ZP_X, RW_R},
0x55: {"EOR", MODE_ZP_X, RW_R},
0x75: {"ADC", MODE_ZP_X, RW_R},
0x95: {"STA", MODE_ZP_X, RW_W},
0xB5: {"LDA", MODE_ZP_X, RW_R},
0xD5: {"CMP", MODE_ZP_X, RW_R},
0xF5: {"SBC", MODE_ZP_X, RW_R},
0x96: {"STX", MODE_ZP_Y, RW_W},
0xB6: {"LDX", MODE_ZP_Y, RW_R},
0x94: {"STY", MODE_ZP_X, RW_W},
0xB4: {"LDY", MODE_ZP_X, RW_R},
// 2-opcode, 5*-cycle zero-page indirect Y
0x11: {"ORA", MODE_INDIRECT_Y, RW_R},
0x31: {"AND", MODE_INDIRECT_Y, RW_R},
0x51: {"EOR", MODE_INDIRECT_Y, RW_R},
0x71: {"ADC", MODE_INDIRECT_Y, RW_R},
0x91: {"STA", MODE_INDIRECT_Y, RW_W},
0xB1: {"LDA", MODE_INDIRECT_Y, RW_R},
0xD1: {"CMP", MODE_INDIRECT_Y, RW_R},
0xF1: {"SBC", MODE_INDIRECT_Y, RW_R},
// 2-opcode, 6-cycle zero-page X indirect
0x01: {"ORA", MODE_INDIRECT_X, RW_R},
0x21: {"AND", MODE_INDIRECT_X, RW_R},
0x41: {"EOR", MODE_INDIRECT_X, RW_R},
0x61: {"ADC", MODE_INDIRECT_X, RW_R},
0x81: {"STA", MODE_INDIRECT_X, RW_W},
0xA1: {"LDA", MODE_INDIRECT_X, RW_R},
0xC1: {"CMP", MODE_INDIRECT_X, RW_R},
0xE1: {"SBC", MODE_INDIRECT_X, RW_R},
// 1-opcode, 2-cycle, accumulator rmw
0x0A: {"ASL", MODE_A, RW_RMW},
0x2A: {"ROL", MODE_A, RW_RMW},
0x4A: {"LSR", MODE_A, RW_RMW},
0x6A: {"ROR", MODE_A, RW_RMW},
// 2-opcode, 5-cycle, zp rmw
0x06: {"ASL", MODE_ZP, RW_RMW},
0x26: {"ROL", MODE_ZP, RW_RMW},
0x46: {"LSR", MODE_ZP, RW_RMW},
0x66: {"ROR", MODE_ZP, RW_RMW},
0xC6: {"DEC", MODE_ZP, RW_RMW},
0xE6: {"INC", MODE_ZP, RW_RMW},
// 3-opcode, 6-cycle, abs rmw
0x0E: {"ASL", MODE_ABSOLUTE, RW_RMW},
0x2E: {"ROL", MODE_ABSOLUTE, RW_RMW},
0x4E: {"LSR", MODE_ABSOLUTE, RW_RMW},
0x6E: {"ROR", MODE_ABSOLUTE, RW_RMW},
0xCE: {"DEC", MODE_ABSOLUTE, RW_RMW},
0xEE: {"INC", MODE_ABSOLUTE, RW_RMW},
// 2-opcode, 6-cycle, zp,X rmw
0x16: {"ASL", MODE_ZP_X, RW_RMW},
0x36: {"ROL", MODE_ZP_X, RW_RMW},
0x56: {"LSR", MODE_ZP_X, RW_RMW},
0x76: {"ROR", MODE_ZP_X, RW_RMW},
0xD6: {"DEC", MODE_ZP_X, RW_RMW},
0xF6: {"INC", MODE_ZP_X, RW_RMW},
// 3-opcode, 7-cycle, abs,X rmw
0x1E: {"ASL", MODE_ABS_X, RW_RMW},
0x3E: {"ROL", MODE_ABS_X, RW_RMW},
0x5E: {"LSR", MODE_ABS_X, RW_RMW},
0x7E: {"ROR", MODE_ABS_X, RW_RMW},
0xDE: {"DEC", MODE_ABS_X, RW_RMW},
0xFE: {"INC", MODE_ABS_X, RW_RMW},
}
// Information for lookup of opcodes by name and mode -------------------------
type OpInfo struct {
Mode AddressingMode
Length int
Byte byte
}
type OpSummary struct {
Modes AddressingMode // bitmask of supported modes
Ops []OpInfo
}
var ByName map[string]OpSummary
func init() {
ByName = make(map[string]OpSummary)
for b, oc := range Opcodes {
info := OpInfo{oc.Mode, ModeLengths[oc.Mode], b}
summary := ByName[oc.Name]
summary.Modes |= oc.Mode
summary.Ops = append(summary.Ops, info)
ByName[oc.Name] = summary
}
}
func (s OpSummary) AnyModes(modes AddressingMode) bool {
return modes&s.Modes != 0
}
func (s OpSummary) OpForMode(mode AddressingMode) (OpInfo, bool) {
for _, o := range s.Ops {
if o.Mode == mode {
return o, true
}
}
return OpInfo{}, false
}