# This file is part of Gopher2600.
#
# Gopher2600 is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Gopher2600 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gopher2600.  If not, see <https://www.gnu.org/licenses/>.


# instruction table entries are defined by the following fields: 
#
#	opcode, operator (mnemonic), cycles, addressing mode, page sensitivity, [effect category]
#
# effect category can be one of three types (READ is the default if no effect category is given)
#
# 1. READ			(instruction only reads from memory - or not at all in the case of IMPLIED instructions)
# 2. WRITE			(instruction changes memory)
# 3. RMW			(instruction reads, modifies and writes to memory)
# 4. FLOW			(instruction explicitely affects the program counter)
# 5. SUB-ROUTINE	(like FLOW but also writes to the stack)
#
# in the 6507 all instructions are considered to *read* from memory, even
# register only instructions (the IMPLIED addressing mode). in the hardware,
# this meant that the chip could forego a "read" pin - the electrical
# connection that switched on access to memory - and thereby save on
# manufacturing costs.
# 
# only some instructions however, ever *write* to memory. in the 6507 this is
# accomplished with a "read/write" pin - an electrical connection to memory
# that causes bits to be written as well as read. in our emulation, we mark the
# instructions that write to memory by specifying the WRITE effect category
# 
# a small class of instructions read AND write to memory (using the same
# address), these are the RMW class of instructions.
# 
# note that the addressing mode /implies/ the number of bytes each instruction
# requires: (including the 1 byte required for the opcode)
#
#		IMPLIED = 1
#		IMMEDIATE = 2
#		ZERO PAGE = 2
#		all others = 3
#
# !!TODO: maybe the number of cycles can be inferred in a similar way

# no operation
0xea, nop, 2, IMPLIED, False

# status flags
0x58, cli, 2, IMPLIED, False
0x78, sei, 2, IMPLIED, False
0x18, clc, 2, IMPLIED, False
0x38, sec, 2, IMPLIED, False
0xd8, cld, 2, IMPLIED, False
0xf8, sed, 2, IMPLIED, False
0xb8, clv, 2, IMPLIED, False

# stack
0x48, pha, 3, IMPLIED, False, WRITE
0x68, pla, 4, IMPLIED, False
0x08, php, 3, IMPLIED, False, WRITE
0x28, plp, 4, IMPLIED, False

# register transfer
0x8a, txa, 2, IMPLIED, False
0xaa, tax, 2, IMPLIED, False
0xa8, tay, 2, IMPLIED, False
0x98, tya, 2, IMPLIED, False
0xba, tsx, 2, IMPLIED, False
0x9a, txs, 2, IMPLIED, False

# bitwise operations
0x49, eor, 2, IMMEDIATE, False
0x45, eor, 3, ZEROPAGE, False
0x55, eor, 4, ZEROPAGE_INDEXED_X, False
0x4d, eor, 4, ABSOLUTE, False
0x5d, eor, 4, ABSOLUTE_INDEXED_X, True
0x59, eor, 4, ABSOLUTE_INDEXED_Y, True
0x41, eor, 6, INDEXED_INDIRECT, False
0x51, eor, 5, INDIRECT_INDEXED, True

0x09, ora, 2, IMMEDIATE, False
0x05, ora, 3, ZEROPAGE, False
0x15, ora, 4, ZEROPAGE_INDEXED_X, False
0x0d, ora, 4, ABSOLUTE, False
0x1d, ora, 4, ABSOLUTE_INDEXED_X, True
0x19, ora, 4, ABSOLUTE_INDEXED_Y, True
0x01, ora, 6, INDEXED_INDIRECT, False
0x11, ora, 5, INDIRECT_INDEXED, True

0x29, and, 2, IMMEDIATE, False
0x25, and, 3, ZEROPAGE, False
0x35, and, 4, ZEROPAGE_INDEXED_X, False
0x2d, and, 4, ABSOLUTE, False
0x3d, and, 4, ABSOLUTE_INDEXED_X, True
0x39, and, 4, ABSOLUTE_INDEXED_Y, True
0x21, and, 6, INDEXED_INDIRECT, False
0x31, and, 5, INDIRECT_INDEXED, True

# load register
0xa9, lda, 2, IMMEDIATE, False
0xa5, lda, 3, ZEROPAGE, False
0xb5, lda, 4, ZEROPAGE_INDEXED_X, False
0xad, lda, 4, ABSOLUTE, False
0xbd, lda, 4, ABSOLUTE_INDEXED_X, True
0xb9, lda, 4, ABSOLUTE_INDEXED_Y, True
0xa1, lda, 6, INDEXED_INDIRECT, False
0xb1, lda, 5, INDIRECT_INDEXED, True

0xa2, ldx, 2, IMMEDIATE, False
0xa6, ldx, 3, ZEROPAGE, False
0xb6, ldx, 4, ZEROPAGE_INDEXED_Y, False
0xae, ldx, 4, ABSOLUTE, False
0xbe, ldx, 4, ABSOLUTE_INDEXED_Y, True

0xa0, ldy, 2, IMMEDIATE, False
0xa4, ldy, 3, ZEROPAGE, False
0xb4, ldy, 4, ZEROPAGE_INDEXED_X, False
0xac, ldy, 4, ABSOLUTE, False
0xbc, ldy, 4, ABSOLUTE_INDEXED_X, True

# register operations
0xe8, inx, 2, IMPLIED, False
0xc8, iny, 2, IMPLIED, False
0xca, dex, 2, IMPLIED, False
0x88, dey, 2, IMPLIED, False

0x0a, asl, 2, IMPLIED, False
0x06, asl, 5, ZEROPAGE, False, RMW
0x16, asl, 6, ZEROPAGE_INDEXED_X, False, RMW
0x0e, asl, 6, ABSOLUTE, False, RMW
0x1e, asl, 7, ABSOLUTE_INDEXED_X, False, RMW

0x4a, lsr, 2, IMPLIED, False
0x46, lsr, 5, ZEROPAGE, False, RMW
0x56, lsr, 6, ZEROPAGE_INDEXED_X, False, RMW
0x4e, lsr, 6, ABSOLUTE, False, RMW
0x5e, lsr, 7, ABSOLUTE_INDEXED_X, False, RMW

0x69, adc, 2, IMMEDIATE, False
0x65, adc, 3, ZEROPAGE, False
0x75, adc, 4, ZEROPAGE_INDEXED_X, False
0x6d, adc, 4, ABSOLUTE, False
0x7d, adc, 4, ABSOLUTE_INDEXED_X, True
0x79, adc, 4, ABSOLUTE_INDEXED_Y, True
0x61, adc, 6, INDEXED_INDIRECT, False
0x71, adc, 5, INDIRECT_INDEXED, True

0xe9, sbc, 2, IMMEDIATE, False
0xe5, sbc, 3, ZEROPAGE, False
0xf5, sbc, 4, ZEROPAGE_INDEXED_X, False
0xed, sbc, 4, ABSOLUTE, False
0xfd, sbc, 4, ABSOLUTE_INDEXED_X, True
0xf9, sbc, 4, ABSOLUTE_INDEXED_Y, True
0xe1, sbc, 6, INDEXED_INDIRECT, False
0xf1, sbc, 5, INDIRECT_INDEXED, True

0x6a, ror, 2, IMPLIED, False
0x66, ror, 5, ZEROPAGE, False, RMW
0x76, ror, 6, ZEROPAGE_INDEXED_X, False, RMW
0x6e, ror, 6, ABSOLUTE, False, RMW
0x7e, ror, 7, ABSOLUTE_INDEXED_X, False, RMW

0x2a, rol, 2, IMPLIED, False
0x26, rol, 5, ZEROPAGE, False, RMW
0x36, rol, 6, ZEROPAGE_INDEXED_X, False, RMW
0x2e, rol, 6, ABSOLUTE, False, RMW
0x3e, rol, 7, ABSOLUTE_INDEXED_X, False, RMW

# compare instructions
0xc9, cmp, 2, IMMEDIATE, False
0xc5, cmp, 3, ZEROPAGE, False
0xd5, cmp, 4, ZEROPAGE_INDEXED_X, False
0xcd, cmp, 4, ABSOLUTE, False
0xdd, cmp, 4, ABSOLUTE_INDEXED_X, True
0xd9, cmp, 4, ABSOLUTE_INDEXED_Y, True
0xc1, cmp, 6, INDEXED_INDIRECT, False
0xd1, cmp, 5, INDIRECT_INDEXED, True

0xe0, cpx, 2, IMMEDIATE, False
0xe4, cpx, 3, ZEROPAGE, False
0xec, cpx, 4, ABSOLUTE, False

0xc0, cpy, 2, IMMEDIATE, False
0xc4, cpy, 3, ZEROPAGE, False
0xcc, cpy, 4, ABSOLUTE, False

0x24, bit, 3, ZEROPAGE, False
0x2c, bit, 4, ABSOLUTE, False

# store register
0x85, sta, 3, ZEROPAGE, False, WRITE
0x95, sta, 4, ZEROPAGE_INDEXED_X, False, WRITE
0x8d, sta, 4, ABSOLUTE, False, WRITE
0x9d, sta, 5, ABSOLUTE_INDEXED_X, False, WRITE
0x99, sta, 5, ABSOLUTE_INDEXED_Y, False, WRITE
0x81, sta, 6, INDEXED_INDIRECT, False, WRITE
0x91, sta, 6, INDIRECT_INDEXED, False, WRITE

0x86, stx, 3, ZEROPAGE, False, WRITE
0x96, stx, 4, ZEROPAGE_INDEXED_Y, False, WRITE
0x8e, stx, 4, ABSOLUTE, False, WRITE

0x84, sty, 3, ZEROPAGE, False, WRITE
0x94, sty, 4, ZEROPAGE_INDEXED_X, False, WRITE
0x8c, sty, 4, ABSOLUTE, False, WRITE

# memory instructions
0xe6, inc, 5, ZEROPAGE, False, RMW
0xf6, inc, 6, ZEROPAGE_INDEXED_X, False, RMW
0xee, inc, 6, ABSOLUTE, False, RMW
0xfe, inc, 7, ABSOLUTE_INDEXED_X, False, RMW

0xc6, dec, 5, ZEROPAGE, False, RMW
0xd6, dec, 6, ZEROPAGE_INDEXED_X, False, RMW
0xce, dec, 6, ABSOLUTE, False, RMW
0xde, dec, 7, ABSOLUTE_INDEXED_X, False, RMW

# flow control
0x4c, jmp, 3, ABSOLUTE, False, FLOW
0x6c, jmp, 5, INDIRECT, False, FLOW

# flow control (branch instructions) -- machine cycles count column is the fail count
# ie. when the branch condition isfalse and the PC allowed to advance as normal. if the
# branch succeeds then the PC is adjusted, taking an additional cycle.
0x90, bcc, 2, RELATIVE, True, FLOW
0xb0, bcs, 2, RELATIVE, True, FLOW
0xf0, beq, 2, RELATIVE, True, FLOW
0x30, bmi, 2, RELATIVE, True, FLOW
0xd0, bne, 2, RELATIVE, True, FLOW
0x10, bpl, 2, RELATIVE, True, FLOW
0x50, bvc, 2, RELATIVE, True, FLOW
0x70, bvs, 2, RELATIVE, True, FLOW

0x20, jsr, 6, ABSOLUTE, False, SUB-ROUTINE
0x60, rts, 6, IMPLIED, False, SUB-ROUTINE

# interrupts
0x00, brk, 7, IMPLIED, False, INTERRUPT
0x40, rti, 6, IMPLIED, False, INTERRUPT

# undocumented instructions
# - by convention, I've decided to user upper-case mnemonics for documented
# instructions and lower-case mnemonics for undocumented instructions
# - where there is a controversy over the mnemonic, I have preferred the
# mnemonic used by the stella emulator (alternatives are commented as
# appropriate)
# - nop instructions of all cycle/byte counts are labelled as nop
#
#
# Reference for undocumented instruction
#
# "6502/6510/8500/8502 Opcode matrix" © 2002-2012 Graham. Last change on 03.11.2012
#
# http://www.oxyron.de/html/opcodes02.html

0x04, NOP, 3, ZEROPAGE, False
0x0c, NOP, 4, ABSOLUTE, False
0x14, NOP, 4, ZEROPAGE_INDEXED_X, False
0x1a, NOP, 2, IMPLIED, False
0x1c, NOP, 4, ABSOLUTE_INDEXED_X, True
0x34, NOP, 4, ZEROPAGE_INDEXED_X, False
0x3a, NOP, 2, IMPLIED, False
0x3c, NOP, 4, ABSOLUTE_INDEXED_X, True
0x44, NOP, 3, ZEROPAGE, False
0x54, NOP, 4, ZEROPAGE_INDEXED_X, False
0x5a, NOP, 2, IMPLIED, False
0x5c, NOP, 4, ABSOLUTE_INDEXED_X, True
0x64, NOP, 3, ZEROPAGE, False
0x74, NOP, 4, ZEROPAGE_INDEXED_X, False
0x7a, NOP, 2, IMPLIED, False
0x7c, NOP, 4, ABSOLUTE_INDEXED_X, True
0x80, NOP, 2, IMMEDIATE, False
0x82, NOP, 2, IMMEDIATE, False
0x89, NOP, 2, IMMEDIATE, False
0xc2, NOP, 2, IMMEDIATE, False
0xd4, NOP, 4, ZEROPAGE_INDEXED_X, False
0xda, NOP, 2, IMPLIED, False
0xdc, NOP, 4, ABSOLUTE_INDEXED_X, True
0xe2, NOP, 2, IMMEDIATE, False
0xf4, NOP, 4, ZEROPAGE_INDEXED_X, False
0xfa, NOP, 2, IMPLIED, False
0xfc, NOP, 4, ABSOLUTE_INDEXED_X, True

0x03, SLO, 8, INDEXED_INDIRECT, False, RMW		# ASO
0x07, SLO, 5, ZEROPAGE, False, RMW				# ASO
0x0f, SLO, 6, ABSOLUTE, False, RMW				# ASO
0x13, SLO, 8, INDIRECT_INDEXED, False, RMW		# ASO
0x17, SLO, 6, ZEROPAGE_INDEXED_X, False, RMW    # ASO
0x1b, SLO, 7, ABSOLUTE_INDEXED_Y, False , RMW   # ASO
0x1f, SLO, 7, ABSOLUTE_INDEXED_X, False , RMW   # ASO

0x0b, ANC, 2, IMMEDIATE, False
0x2b, ANC, 2, IMMEDIATE, False

0x23, RLA, 8, INDEXED_INDIRECT, False, RMW
0x27, RLA, 5, ZEROPAGE, False, RMW
0x2f, RLA, 6, ABSOLUTE, False, RMW
0x33, RLA, 8, INDIRECT_INDEXED, False, RMW
0x37, RLA, 6, ZEROPAGE_INDEXED_X, False, RMW
0x3b, RLA, 7, ABSOLUTE_INDEXED_Y, False, RMW
0x3f, RLA, 7, ABSOLUTE_INDEXED_X, False, RMW

0x43, SRE, 8, INDEXED_INDIRECT, False, RMW      # LSE
0x47, SRE, 5, ZEROPAGE, False, RMW              # LSE
0x4f, SRE, 6, ABSOLUTE, False, RMW              # LSE
0x53, SRE, 8, INDIRECT_INDEXED, False, RMW      # LSE
0x57, SRE, 6, ZEROPAGE_INDEXED_X, False, RMW    # LSE
0x5b, SRE, 7, ABSOLUTE_INDEXED_Y, False, RMW    # LSE
0x5f, SRE, 7, ABSOLUTE_INDEXED_X, False, RMW    # LSE

0x4b, ASR, 2, IMMEDIATE, False					# ALR

0x63, RRA, 8, INDEXED_INDIRECT, False, RMW
0x67, RRA, 5, ZEROPAGE, False, RMW
0x6f, RRA, 6, ABSOLUTE, False, RMW
0x73, RRA, 8, INDIRECT_INDEXED, False, RMW
0x77, RRA, 6, ZEROPAGE_INDEXED_X, False, RMW
0x7b, RRA, 7, ABSOLUTE_INDEXED_Y, False, RMW
0x7f, RRA, 7, ABSOLUTE_INDEXED_X, False, RMW

0x6b, ARR, 2, IMMEDIATE, False

# XAA is highly unstable
0x8b, XAA, 2, IMMEDIATE, False

0x83, SAX, 6, INDEXED_INDIRECT, False, WRITE
0x87, SAX, 3, ZEROPAGE, False, WRITE
0x8f, SAX, 4, ABSOLUTE, False, WRITE
0x97, SAX, 4, ZEROPAGE_INDEXED_Y, False, WRITE

## AHX is unstable
0x93, AHX, 6, INDIRECT_INDEXED, False, WRITE
0x9f, AHX, 5, ABSOLUTE_INDEXED_Y, False, WRITE

## TAS is unstable
0x9b, TAS, 5, ABSOLUTE_INDEXED_Y, False, WRITE

## SHY is unstable
0x9c, SHY, 5, ABSOLUTE_INDEXED_X, False, WRITE

## SHX is unstable
0x9e, SHX, 5, ABSOLUTE_INDEXED_Y, False, WRITE

# LAX is highly unstable
0xa3, LAX, 6, INDEXED_INDIRECT, False
0xa7, LAX, 3, ZEROPAGE, False
0xab, LAX, 2, IMMEDIATE, False
0xaf, LAX, 4, ABSOLUTE, False
0xb3, LAX, 5, INDIRECT_INDEXED, True
0xb7, LAX, 4, ZEROPAGE_INDEXED_Y, False
0xbf, LAX, 4, ABSOLUTE_INDEXED_Y, True

0xbb, LAS, 4, ABSOLUTE_INDEXED_Y, True   # LAR

0xc3, DCP, 8, INDEXED_INDIRECT, False, RMW      # DCM
0xc7, DCP, 5, ZEROPAGE, False, RMW				# DCM
0xcf, DCP, 6, ABSOLUTE, False, RMW              # DCM
0xd3, DCP, 8, INDIRECT_INDEXED, False, RMW      # DCM
0xd7, DCP, 6, ZEROPAGE_INDEXED_X, False, RMW	# DCM
0xdb, DCP, 7, ABSOLUTE_INDEXED_Y, False, RMW    # DCM
0xdf, DCP, 7, ABSOLUTE_INDEXED_X, False, RMW    # DCM

0xcb, AXS, 2, IMMEDIATE, False

0xe3, ISC, 8, INDEXED_INDIRECT, False, RMW      # ISB
0xe7, ISC, 5, ZEROPAGE, False, RMW              # ISB
0xef, ISC, 6, ABSOLUTE, False, RMW              # ISB
0xf3, ISC, 8, INDIRECT_INDEXED, False, RMW      # ISB
0xf7, ISC, 6, ZEROPAGE_INDEXED_X, False, RMW    # ISB
0xfb, ISC, 7, ABSOLUTE_INDEXED_Y, False, RMW    # ISB
0xff, ISC, 7, ABSOLUTE_INDEXED_X, False, RMW    # ISB

# this is just the same as opcode e9 which is a documented instruction
# I'm not sure why this is considered to be undocumented
0xeb, SBC, 2, IMMEDIATE, False

# KIL is sometimes called HLT or JAM
0x02, KIL, 2, IMPLIED, False
0x12, KIL, 2, IMPLIED, False
0x22, KIL, 2, IMPLIED, False
0x32, KIL, 2, IMPLIED, False
0x42, KIL, 2, IMPLIED, False
0x52, KIL, 2, IMPLIED, False
0x62, KIL, 2, IMPLIED, False
0x72, KIL, 2, IMPLIED, False
0x92, KIL, 2, IMPLIED, False
0xb2, KIL, 2, IMPLIED, False
0xd2, KIL, 2, IMPLIED, False
0xf2, KIL, 2, IMPLIED, False



