From b740dbcfd2c0e6d1d17eb578abf6b554cbd3b481 Mon Sep 17 00:00:00 2001 From: Eduardo Vieira Date: Mon, 8 Jun 2026 22:21:40 -0300 Subject: [PATCH] perf(cpu): code-generate the opcode dispatch table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the decorator + string-arg instruction table with per-opcode handlers generated from a compact spec. Memory/modify families (187 opcodes) are emitted as inlined literal handlers — index register, width flag, and operation/source baked in, so PyPy folds them per-opcode trace (~2x faster dispatch on hot read/write instructions; the shared decorator+string dispatch could not). The irregular ops (69: branches, jumps, calls/returns, flags, transfers, push/pull, block move, interrupt, exchanges) are emitted as thin handlers that delegate to the existing addressing functions. opcodes_spec.py compact spec (source of truth) scripts/gen_opcodes.py generator (edit spec -> regenerate -> commit) opcodes_generated.py committed generated handlers + HANDLERS instructions.py 3-line adapter over HANDLERS Removes the now-inlined read.py/write.py/modify.py addressing-mode functions. cpu.py is untouched, so existing save states are unaffected. Verified: 6144 Tom Harte SingleStepTest cases (all opcodes x both M/X widths) and the full unit suite pass; regenerator output is reproducible. Dispatch ~2x faster in a micro-benchmark; in-game effect is within noise (dispatch is a small slice of frame time) — the win here is architectural uniformity. --- .../cpu/wdc65816/addressing_modes/__init__.py | 5 +- .../cpu/wdc65816/addressing_modes/modify.py | 116 - pysnes/cpu/wdc65816/addressing_modes/read.py | 229 -- pysnes/cpu/wdc65816/addressing_modes/write.py | 177 - pysnes/cpu/wdc65816/instructions.py | 278 +- pysnes/cpu/wdc65816/opcodes_generated.py | 3108 +++++++++++++++++ pysnes/cpu/wdc65816/opcodes_spec.py | 270 ++ scripts/bench_cpu.py | 234 ++ scripts/gen_opcodes.py | 327 ++ 9 files changed, 3960 insertions(+), 784 deletions(-) delete mode 100644 pysnes/cpu/wdc65816/addressing_modes/modify.py delete mode 100644 pysnes/cpu/wdc65816/addressing_modes/read.py delete mode 100644 pysnes/cpu/wdc65816/addressing_modes/write.py create mode 100644 pysnes/cpu/wdc65816/opcodes_generated.py create mode 100644 pysnes/cpu/wdc65816/opcodes_spec.py create mode 100644 scripts/bench_cpu.py create mode 100644 scripts/gen_opcodes.py diff --git a/pysnes/cpu/wdc65816/addressing_modes/__init__.py b/pysnes/cpu/wdc65816/addressing_modes/__init__.py index b2861bc..52137f2 100644 --- a/pysnes/cpu/wdc65816/addressing_modes/__init__.py +++ b/pysnes/cpu/wdc65816/addressing_modes/__init__.py @@ -1,7 +1,6 @@ from .decorator import decorator_mode_8bit -from .read import * -from .write import * -from .modify import * +# read/write/modify families are now code-generated (see opcodes_generated.py); +# only the irregular ops in other.py / pc.py are still called as functions. from .other import * from .pc import * diff --git a/pysnes/cpu/wdc65816/addressing_modes/modify.py b/pysnes/cpu/wdc65816/addressing_modes/modify.py deleted file mode 100644 index 145d502..0000000 --- a/pysnes/cpu/wdc65816/addressing_modes/modify.py +++ /dev/null @@ -1,116 +0,0 @@ -from ...cpu import Cpu - -from .decorator import decorator_mode_8bit - - -@decorator_mode_8bit -def ImpliedModify(cpu: Cpu, mode_8bit: bool, func, m: str): - M = getattr(cpu, m) - - if mode_8bit: - cpu.idleIRQ() - M.l = func(cpu, mode_8bit, M.l) - else: - cpu.idleIRQ() - M.w = func(cpu, mode_8bit, M.w) - - -@decorator_mode_8bit -def BankModify(cpu: Cpu, mode_8bit: bool, func): - if mode_8bit: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.W.l = cpu.readBank(cpu.V.w + 0) - # 65816 emulation (EF=1) replays the 6502-era RMW dummy write-back of - # the unmodified value in place of the native-mode internal idle. - if cpu.EF: - cpu.writeBank(cpu.V.w + 0, cpu.W.l) - else: - cpu.idle() - cpu.W.l = func(cpu, mode_8bit, cpu.W.l) - cpu.writeBank(cpu.V.w + 0, cpu.W.l) - else: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.W.l = cpu.readBank(cpu.V.w + 0) - cpu.W.h = cpu.readBank(cpu.V.w + 1) - cpu.idle() - cpu.W.w = func(cpu, mode_8bit, cpu.W.w) - cpu.writeBank(cpu.V.w + 1, cpu.W.h) - cpu.writeBank(cpu.V.w + 0, cpu.W.l) - - -@decorator_mode_8bit -def BankIndexedModify(cpu: Cpu, mode_8bit: bool, func): - if mode_8bit: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.idle() - cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) - # See BankModify: EF=1 dummy write-back in place of the native idle. - if cpu.EF: - cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) - else: - cpu.idle() - cpu.W.l = func(cpu, mode_8bit, cpu.W.l) - cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) - else: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.idle() - cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) - cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) - cpu.idle() - cpu.W.w = func(cpu, mode_8bit, cpu.W.w) - cpu.writeBank(cpu.V.w + cpu.X.w + 1, cpu.W.h) - cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) - - -@decorator_mode_8bit -def DirectModify(cpu: Cpu, mode_8bit: bool, func): - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.W.l = cpu.readDirect(cpu.U.l + 0) - # See BankModify: EF=1 dummy write-back in place of the native idle. - if cpu.EF: - cpu.writeDirect(cpu.U.l + 0, cpu.W.l) - else: - cpu.idle() - cpu.W.l = func(cpu, mode_8bit, cpu.W.l) - cpu.writeDirect(cpu.U.l + 0, cpu.W.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.W.l = cpu.readDirect(cpu.U.l + 0) - cpu.W.h = cpu.readDirect(cpu.U.l + 1) - cpu.idle() - cpu.W.w = func(cpu, mode_8bit, cpu.W.w) - cpu.writeDirect(cpu.U.l + 1, cpu.W.h) - cpu.writeDirect(cpu.U.l + 0, cpu.W.l) - - -@decorator_mode_8bit -def DirectIndexedModify(cpu: Cpu, mode_8bit: bool, func): - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.idle() - cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) - # See BankModify: EF=1 dummy write-back in place of the native idle. - if cpu.EF: - cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) - else: - cpu.idle() - cpu.W.l = func(cpu, mode_8bit, cpu.W.l) - cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.idle() - cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) - cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) - cpu.idle() - cpu.W.w = func(cpu, mode_8bit, cpu.W.w) - cpu.writeDirect(cpu.U.l + cpu.X.w + 1, cpu.W.h) - cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) diff --git a/pysnes/cpu/wdc65816/addressing_modes/read.py b/pysnes/cpu/wdc65816/addressing_modes/read.py deleted file mode 100644 index dcac87b..0000000 --- a/pysnes/cpu/wdc65816/addressing_modes/read.py +++ /dev/null @@ -1,229 +0,0 @@ -from ...cpu import Cpu, Reg - -from .decorator import decorator_mode_8bit - - -""" -//both the accumulator and index registers can independently be in either 8-bit or 16-bit mode. -//controlled via the M/X flags, this changes the execution details of various instructions. -//rather than implement four instruction tables for all possible combinations of these bits, -//instead use macro abuse to generate all four tables based off of a single template table. -auto WDC65816::instruction() -> void { - //a = instructions unaffected by M/X flags - //m = instructions affected by M flag (1 = 8-bit; 0 = 16-bit) - //x = instructions affected by X flag (1 = 8-bit; 0 = 16-bit) -""" - - -@decorator_mode_8bit -def ImmediateRead(cpu: Cpu, mode_8bit: bool, func): - if mode_8bit: - cpu.W.l = cpu.fetch() - func(cpu, mode_8bit, cpu.W.l) - else: - cpu.W.l = cpu.fetch() - cpu.W.h = cpu.fetch() - func(cpu, mode_8bit, cpu.W.w) - - -@decorator_mode_8bit -def BankRead(cpu: Cpu, mode_8bit: bool, func, i: str = ""): - I = getattr(cpu, i, None) - - if mode_8bit: - if I is None: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.W.l = cpu.readBank(cpu.V.w + 0) - func(cpu, mode_8bit, cpu.W.l) - else: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.idle4(cpu.V.w, cpu.V.w + I.w) - cpu.W.l = cpu.readBank(cpu.V.w + I.w + 0) - func(cpu, mode_8bit, cpu.W.l) - else: - if I is None: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.W.l = cpu.readBank(cpu.V.w + 0) - cpu.W.h = cpu.readBank(cpu.V.w + 1) - func(cpu, mode_8bit, cpu.W.w) - else: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.idle4(cpu.V.w, cpu.V.w + I.w) - cpu.W.l = cpu.readBank(cpu.V.w + I.w + 0) - cpu.W.h = cpu.readBank(cpu.V.w + I.w + 1) - func(cpu, mode_8bit, cpu.W.w) - - -@decorator_mode_8bit -def LongRead(cpu: Cpu, mode_8bit: bool, func, i: str = ""): - I = getattr(cpu, i, Reg(16, 0)) - - if mode_8bit: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.V.b = cpu.fetch() - cpu.W.l = cpu.readLong(cpu.V.d + I.w + 0) - func(cpu, mode_8bit, cpu.W.l) - else: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.V.b = cpu.fetch() - cpu.W.l = cpu.readLong(cpu.V.d + I.w + 0) - cpu.W.h = cpu.readLong(cpu.V.d + I.w + 1) - func(cpu, mode_8bit, cpu.W.w) - - -@decorator_mode_8bit -def DirectRead(cpu: Cpu, mode_8bit: bool, func, i: str = ""): - I = getattr(cpu, i, None) - - if mode_8bit: - if I is None: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.W.l = cpu.readDirect(cpu.U.l + 0) - func(cpu, mode_8bit, cpu.W.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.idle() - cpu.W.l = cpu.readDirect(cpu.U.l + I.w + 0) - func(cpu, mode_8bit, cpu.W.l) - else: - if I is None: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.W.l = cpu.readDirect(cpu.U.l + 0) - cpu.W.h = cpu.readDirect(cpu.U.l + 1) - func(cpu, mode_8bit, cpu.W.w) - else: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.idle() - cpu.W.l = cpu.readDirect(cpu.U.l + I.w + 0) - cpu.W.h = cpu.readDirect(cpu.U.l + I.w + 1) - func(cpu, mode_8bit, cpu.W.w) - - -@decorator_mode_8bit -def IndirectRead(cpu: Cpu, mode_8bit: bool, func): - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.V.l = cpu.readDirect(cpu.U.l + 0) - cpu.V.h = cpu.readDirect(cpu.U.l + 1) - cpu.W.l = cpu.readBank(cpu.V.w + 0) - func(cpu, mode_8bit, cpu.W.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.V.l = cpu.readDirect(cpu.U.l + 0) - cpu.V.h = cpu.readDirect(cpu.U.l + 1) - cpu.W.l = cpu.readBank(cpu.V.w + 0) - cpu.W.h = cpu.readBank(cpu.V.w + 1) - func(cpu, mode_8bit, cpu.W.w) - - -@decorator_mode_8bit -def IndexedIndirectRead(cpu: Cpu, mode_8bit: bool, func): - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.idle() - cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) - cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) - cpu.W.l = cpu.readBank(cpu.V.w + 0) - func(cpu, mode_8bit, cpu.W.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.idle() - cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) - cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) - cpu.W.l = cpu.readBank(cpu.V.w + 0) - cpu.W.h = cpu.readBank(cpu.V.w + 1) - func(cpu, mode_8bit, cpu.W.w) - - -@decorator_mode_8bit -def IndirectIndexedRead(cpu: Cpu, mode_8bit: bool, func): - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.V.l = cpu.readDirect(cpu.U.l + 0) - cpu.V.h = cpu.readDirect(cpu.U.l + 1) - cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) - cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) - func(cpu, mode_8bit, cpu.W.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.V.l = cpu.readDirect(cpu.U.l + 0) - cpu.V.h = cpu.readDirect(cpu.U.l + 1) - cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) - cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) - cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) - func(cpu, mode_8bit, cpu.W.w) - - -@decorator_mode_8bit -def IndirectLongRead(cpu: Cpu, mode_8bit: bool, func, i: str = ""): - I = getattr(cpu, i, Reg(16, 0)) - - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.V.l = cpu.readDirectN(cpu.U.l + 0) - cpu.V.h = cpu.readDirectN(cpu.U.l + 1) - cpu.V.b = cpu.readDirectN(cpu.U.l + 2) - cpu.W.l = cpu.readLong(cpu.V.d + I.w + 0) - func(cpu, mode_8bit, cpu.W.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.V.l = cpu.readDirectN(cpu.U.l + 0) - cpu.V.h = cpu.readDirectN(cpu.U.l + 1) - cpu.V.b = cpu.readDirectN(cpu.U.l + 2) - cpu.W.l = cpu.readLong(cpu.V.d + I.w + 0) - cpu.W.h = cpu.readLong(cpu.V.d + I.w + 1) - func(cpu, mode_8bit, cpu.W.w) - - -@decorator_mode_8bit -def StackRead(cpu: Cpu, mode_8bit: bool, func): - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle() - cpu.W.l = cpu.readStack(cpu.U.l + 0) - func(cpu, mode_8bit, cpu.W.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle() - cpu.W.l = cpu.readStack(cpu.U.l + 0) - cpu.W.h = cpu.readStack(cpu.U.l + 1) - func(cpu, mode_8bit, cpu.W.w) - - -@decorator_mode_8bit -def IndirectStackRead(cpu: Cpu, mode_8bit: bool, func): - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle() - cpu.V.l = cpu.readStack(cpu.U.l + 0) - cpu.V.h = cpu.readStack(cpu.U.l + 1) - cpu.idle() - cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) - func(cpu, mode_8bit, cpu.W.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle() - cpu.V.l = cpu.readStack(cpu.U.l + 0) - cpu.V.h = cpu.readStack(cpu.U.l + 1) - cpu.idle() - cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) - cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) - func(cpu, mode_8bit, cpu.W.w) diff --git a/pysnes/cpu/wdc65816/addressing_modes/write.py b/pysnes/cpu/wdc65816/addressing_modes/write.py deleted file mode 100644 index 01587be..0000000 --- a/pysnes/cpu/wdc65816/addressing_modes/write.py +++ /dev/null @@ -1,177 +0,0 @@ -from ...cpu import Cpu, Reg - -from .decorator import decorator_mode_8bit - - -@decorator_mode_8bit -def BankWrite(cpu: Cpu, mode_8bit: bool, f: str, i: str = ""): - F = getattr(cpu, f) - I = getattr(cpu, i, None) - - if mode_8bit: - if I is None: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.writeBank(cpu.V.w + 0, F.l) - else: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.idle() - cpu.writeBank(cpu.V.w + I.w + 0, F.l) - else: - if I is None: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.writeBank(cpu.V.w + 0, F.l) - cpu.writeBank(cpu.V.w + 1, F.h) - else: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.idle() - cpu.writeBank(cpu.V.w + I.w + 0, F.l) - cpu.writeBank(cpu.V.w + I.w + 1, F.h) - - -@decorator_mode_8bit -def LongWrite(cpu: Cpu, mode_8bit: bool, i: str = ""): - I = getattr(cpu, i, Reg(16, 0x0000)) - - if mode_8bit: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.V.b = cpu.fetch() - cpu.writeLong(cpu.V.d + I.w + 0, cpu.A.l) - else: - cpu.V.l = cpu.fetch() - cpu.V.h = cpu.fetch() - cpu.V.b = cpu.fetch() - cpu.writeLong(cpu.V.d + I.w + 0, cpu.A.l) - cpu.writeLong(cpu.V.d + I.w + 1, cpu.A.h) - - -@decorator_mode_8bit -def DirectWrite(cpu: Cpu, mode_8bit: bool, f: str, i: str = ""): - F = getattr(cpu, f) - I = getattr(cpu, i, Reg(16, 0x0000)) - - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle2() - if i: - cpu.idle() - cpu.writeDirect(cpu.U.l + I.w + 0, F.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle2() - if i: - cpu.idle() - cpu.writeDirect(cpu.U.l + I.w + 0, F.l) - cpu.writeDirect(cpu.U.l + I.w + 1, F.h) - - -@decorator_mode_8bit -def IndirectWrite(cpu: Cpu, mode_8bit: bool): - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.V.l = cpu.readDirect(cpu.U.l + 0) - cpu.V.h = cpu.readDirect(cpu.U.l + 1) - cpu.writeBank(cpu.V.w + 0, cpu.A.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.V.l = cpu.readDirect(cpu.U.l + 0) - cpu.V.h = cpu.readDirect(cpu.U.l + 1) - cpu.writeBank(cpu.V.w + 0, cpu.A.l) - cpu.writeBank(cpu.V.w + 1, cpu.A.h) - - -@decorator_mode_8bit -def IndexedIndirectWrite(cpu: Cpu, mode_8bit: bool): - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.idle() - cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) - cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) - cpu.writeBank(cpu.V.w + 0, cpu.A.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.idle() - cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) - cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) - cpu.writeBank(cpu.V.w + 0, cpu.A.l) - cpu.writeBank(cpu.V.w + 1, cpu.A.h) - - -@decorator_mode_8bit -def IndirectIndexedWrite(cpu: Cpu, mode_8bit: bool): - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.V.l = cpu.readDirect(cpu.U.l + 0) - cpu.V.h = cpu.readDirect(cpu.U.l + 1) - cpu.idle() - cpu.writeBank(cpu.V.w + cpu.Y.w + 0, cpu.A.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.V.l = cpu.readDirect(cpu.U.l + 0) - cpu.V.h = cpu.readDirect(cpu.U.l + 1) - cpu.idle() - cpu.writeBank(cpu.V.w + cpu.Y.w + 0, cpu.A.l) - cpu.writeBank(cpu.V.w + cpu.Y.w + 1, cpu.A.h) - - -@decorator_mode_8bit -def IndirectLongWrite(cpu: Cpu, mode_8bit: bool, i: str = ""): - I = getattr(cpu, i, Reg(16, 0x0000)) - - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.V.l = cpu.readDirectN(cpu.U.l + 0) - cpu.V.h = cpu.readDirectN(cpu.U.l + 1) - cpu.V.b = cpu.readDirectN(cpu.U.l + 2) - cpu.writeLong(cpu.V.d + I.w + 0, cpu.A.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle2() - cpu.V.l = cpu.readDirectN(cpu.U.l + 0) - cpu.V.h = cpu.readDirectN(cpu.U.l + 1) - cpu.V.b = cpu.readDirectN(cpu.U.l + 2) - cpu.writeLong(cpu.V.d + I.w + 0, cpu.A.l) - cpu.writeLong(cpu.V.d + I.w + 1, cpu.A.h) - - -@decorator_mode_8bit -def StackWrite(cpu: Cpu, mode_8bit: bool): - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle() - cpu.writeStack(cpu.U.l + 0, cpu.A.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle() - cpu.writeStack(cpu.U.l + 0, cpu.A.l) - cpu.writeStack(cpu.U.l + 1, cpu.A.h) - - -@decorator_mode_8bit -def IndirectStackWrite(cpu: Cpu, mode_8bit: bool): - if mode_8bit: - cpu.U.l = cpu.fetch() - cpu.idle() - cpu.V.l = cpu.readStack(cpu.U.l + 0) - cpu.V.h = cpu.readStack(cpu.U.l + 1) - cpu.idle() - cpu.writeBank(cpu.V.w + cpu.Y.w + 0, cpu.A.l) - else: - cpu.U.l = cpu.fetch() - cpu.idle() - cpu.V.l = cpu.readStack(cpu.U.l + 0) - cpu.V.h = cpu.readStack(cpu.U.l + 1) - cpu.idle() - cpu.writeBank(cpu.V.w + cpu.Y.w + 0, cpu.A.l) - cpu.writeBank(cpu.V.w + cpu.Y.w + 1, cpu.A.h) diff --git a/pysnes/cpu/wdc65816/instructions.py b/pysnes/cpu/wdc65816/instructions.py index aee51e1..901ae85 100644 --- a/pysnes/cpu/wdc65816/instructions.py +++ b/pysnes/cpu/wdc65816/instructions.py @@ -1,261 +1,21 @@ -from . import addressing_modes as AM, opcodes as OP +"""WDC 65816 opcode dispatch table — fully code-generated. +Every opcode (0x00-0xFF) maps to a generated handler that takes only `cpu`. +The handlers are produced from a compact spec: -INSTRUCTIONS = ( - (0x00, AM.Interrupt, lambda cpu: 0xfffe if cpu.EF else 0xffe6), # opA(0x00, Interrupt, EF ? (r16)0xfffe : (r16)0xffe6) - (0x01, AM.IndexedIndirectRead.MF, OP.ORA), # opM(0x01, IndexedIndirectRead, m(ORA)) - (0x02, AM.Interrupt, lambda cpu: 0xfff4 if cpu.EF else 0xffe4), # opA(0x02, Interrupt, EF ? (r16)0xfff4 : (r16)0xffe4) - (0x03, AM.StackRead.MF, OP.ORA), # opM(0x03, StackRead, m(ORA)) - (0x04, AM.DirectModify.MF, OP.TSB), # opM(0x04, DirectModify, m(TSB)) - (0x05, AM.DirectRead.MF, OP.ORA), # opM(0x05, DirectRead, m(ORA)) - (0x06, AM.DirectModify.MF, OP.ASL), # opM(0x06, DirectModify, m(ASL)) - (0x07, AM.IndirectLongRead.MF, OP.ORA), # opM(0x07, IndirectLongRead, m(ORA)) - (0x08, AM.Push8, "P"), # opA(0x08, Push8, (r16)P) - (0x09, AM.ImmediateRead.MF, OP.ORA), # opM(0x09, ImmediateRead, m(ORA)) - (0x0a, AM.ImpliedModify.MF, OP.ASL, "A"), # opM(0x0a, ImpliedModify, m(ASL), A) - (0x0b, AM.PushD), # opA(0x0b, PushD) - (0x0c, AM.BankModify.MF, OP.TSB), # opM(0x0c, BankModify, m(TSB)) - (0x0d, AM.BankRead.MF, OP.ORA), # opM(0x0d, BankRead, m(ORA)) - (0x0e, AM.BankModify.MF, OP.ASL), # opM(0x0e, BankModify, m(ASL)) - (0x0f, AM.LongRead.MF, OP.ORA), # opM(0x0f, LongRead, m(ORA)) - (0x10, AM.Branch, lambda cpu: not cpu.NFlag), # opA(0x10, Branch, NF == 0) - (0x11, AM.IndirectIndexedRead.MF, OP.ORA), # opM(0x11, IndirectIndexedRead, m(ORA)) - (0x12, AM.IndirectRead.MF, OP.ORA), # opM(0x12, IndirectRead, m(ORA)) - (0x13, AM.IndirectStackRead.MF, OP.ORA), # opM(0x13, IndirectStackRead, m(ORA)) - (0x14, AM.DirectModify.MF, OP.TRB), # opM(0x14, DirectModify, m(TRB)) - (0x15, AM.DirectRead.MF, OP.ORA, "X"), # opM(0x15, DirectRead, m(ORA), X) - (0x16, AM.DirectIndexedModify.MF, OP.ASL), # opM(0x16, DirectIndexedModify, m(ASL)) - (0x17, AM.IndirectLongRead.MF, OP.ORA, "Y"), # opM(0x17, IndirectLongRead, m(ORA), Y) - (0x18, AM.ClearFlag, "CFlag"), # opA(0x18, ClearFlag, CF) - (0x19, AM.BankRead.MF, OP.ORA, "Y"), # opM(0x19, BankRead, m(ORA), Y) - (0x1a, AM.ImpliedModify.MF, OP.INC, "A"), # opM(0x1a, ImpliedModify, m(INC), A) - (0x1b, AM.TransferCS), # opA(0x1b, TransferCS) - (0x1c, AM.BankModify.MF, OP.TRB), # opM(0x1c, BankModify, m(TRB)) - (0x1d, AM.BankRead.MF, OP.ORA, "X"), # opM(0x1d, BankRead, m(ORA), X) - (0x1e, AM.BankIndexedModify.MF, OP.ASL), # opM(0x1e, BankIndexedModify, m(ASL)) - (0x1f, AM.LongRead.MF, OP.ORA, "X"), # opM(0x1f, LongRead, m(ORA), X) - (0x20, AM.CallShort), # opA(0x20, CallShort) - (0x21, AM.IndexedIndirectRead.MF, OP.AND), # opM(0x21, IndexedIndirectRead, m(AND)) - (0x22, AM.CallLong), # opA(0x22, CallLong) - (0x23, AM.StackRead.MF, OP.AND), # opM(0x23, StackRead, m(AND)) - (0x24, AM.DirectRead.MF, OP.BIT), # opM(0x24, DirectRead, m(BIT)) - (0x25, AM.DirectRead.MF, OP.AND), # opM(0x25, DirectRead, m(AND)) - (0x26, AM.DirectModify.MF, OP.ROL), # opM(0x26, DirectModify, m(ROL)) - (0x27, AM.IndirectLongRead.MF, OP.AND), # opM(0x27, IndirectLongRead, m(AND)) - (0x28, AM.PullP), # opA(0x28, PullP) - (0x29, AM.ImmediateRead.MF, OP.AND), # opM(0x29, ImmediateRead, m(AND)) - (0x2a, AM.ImpliedModify.MF, OP.ROL, "A"), # opM(0x2a, ImpliedModify, m(ROL), A) - (0x2b, AM.PullD), # opA(0x2b, PullD) - (0x2c, AM.BankRead.MF, OP.BIT), # opM(0x2c, BankRead, m(BIT)) - (0x2d, AM.BankRead.MF, OP.AND), # opM(0x2d, BankRead, m(AND)) - (0x2e, AM.BankModify.MF, OP.ROL), # opM(0x2e, BankModify, m(ROL)) - (0x2f, AM.LongRead.MF, OP.AND), # opM(0x2f, LongRead, m(AND)) - (0x30, AM.Branch, lambda cpu: cpu.NFlag), # opA(0x30, Branch, NF == 1) - (0x31, AM.IndirectIndexedRead.MF, OP.AND), # opM(0x31, IndirectIndexedRead, m(AND)) - (0x32, AM.IndirectRead.MF, OP.AND), # opM(0x32, IndirectRead, m(AND)) - (0x33, AM.IndirectStackRead.MF, OP.AND), # opM(0x33, IndirectStackRead, m(AND)) - (0x34, AM.DirectRead.MF, OP.BIT, "X"), # opM(0x34, DirectRead, m(BIT), X) - (0x35, AM.DirectRead.MF, OP.AND, "X"), # opM(0x35, DirectRead, m(AND), X) - (0x36, AM.DirectIndexedModify.MF, OP.ROL), # opM(0x36, DirectIndexedModify, m(ROL)) - (0x37, AM.IndirectLongRead.MF, OP.AND, "Y"), # opM(0x37, IndirectLongRead, m(AND), Y) - (0x38, AM.SetFlag, "CFlag"), # opA(0x38, SetFlag, CF) - (0x39, AM.BankRead.MF, OP.AND, "Y"), # opM(0x39, BankRead, m(AND), Y) - (0x3a, AM.ImpliedModify.MF, OP.DEC, "A"), # opM(0x3a, ImpliedModify, m(DEC), A) - (0x3b, AM.Transfer16, "S", "A"), # opA(0x3b, Transfer16, S, A) - (0x3c, AM.BankRead.MF, OP.BIT, "X"), # opM(0x3c, BankRead, m(BIT), X) - (0x3d, AM.BankRead.MF, OP.AND, "X"), # opM(0x3d, BankRead, m(AND), X) - (0x3e, AM.BankIndexedModify.MF, OP.ROL), # opM(0x3e, BankIndexedModify, m(ROL)) - (0x3f, AM.LongRead.MF, OP.AND, "X"), # opM(0x3f, LongRead, m(AND), X) - (0x40, AM.ReturnInterrupt), # opA(0x40, ReturnInterrupt) - (0x41, AM.IndexedIndirectRead.MF, OP.EOR), # opM(0x41, IndexedIndirectRead, m(EOR)) - (0x42, AM.Prefix), # opA(0x42, Prefix) - (0x43, AM.StackRead.MF, OP.EOR), # opM(0x43, StackRead, m(EOR)) - (0x44, AM.BlockMove.XF, -1), # opX(0x44, BlockMove, -1) - (0x45, AM.DirectRead.MF, OP.EOR), # opM(0x45, DirectRead, m(EOR)) - (0x46, AM.DirectModify.MF, OP.LSR), # opM(0x46, DirectModify, m(LSR)) - (0x47, AM.IndirectLongRead.MF, OP.EOR), # opM(0x47, IndirectLongRead, m(EOR)) - (0x48, AM.Push.MF, "A"), # opM(0x48, Push, A) - (0x49, AM.ImmediateRead.MF, OP.EOR), # opM(0x49, ImmediateRead, m(EOR)) - (0x4a, AM.ImpliedModify.MF, OP.LSR, "A"), # opM(0x4a, ImpliedModify, m(LSR), A) - (0x4b, AM.Push8, "PC.b"), # opA(0x4b, Push8, (r16)PC.b) - (0x4c, AM.JumpShort), # opA(0x4c, JumpShort) - (0x4d, AM.BankRead.MF, OP.EOR), # opM(0x4d, BankRead, m(EOR)) - (0x4e, AM.BankModify.MF, OP.LSR), # opM(0x4e, BankModify, m(LSR)) - (0x4f, AM.LongRead.MF, OP.EOR), # opM(0x4f, LongRead, m(EOR)) - (0x50, AM.Branch, lambda cpu: not cpu.VFlag), # opA(0x50, Branch, VF == 0) - (0x51, AM.IndirectIndexedRead.MF, OP.EOR), # opM(0x51, IndirectIndexedRead, m(EOR)) - (0x52, AM.IndirectRead.MF, OP.EOR), # opM(0x52, IndirectRead, m(EOR)) - (0x53, AM.IndirectStackRead.MF, OP.EOR), # opM(0x53, IndirectStackRead, m(EOR)) - (0x54, AM.BlockMove.XF, +1), # opX(0x54, BlockMove, +1) - (0x55, AM.DirectRead.MF, OP.EOR, "X"), # opM(0x55, DirectRead, m(EOR), X) - (0x56, AM.DirectIndexedModify.MF, OP.LSR), # opM(0x56, DirectIndexedModify, m(LSR)) - (0x57, AM.IndirectLongRead.MF, OP.EOR, "Y"), # opM(0x57, IndirectLongRead, m(EOR), Y) - (0x58, AM.ClearFlag, "IFlag"), # opA(0x58, ClearFlag, IF) - (0x59, AM.BankRead.MF, OP.EOR, "Y"), # opM(0x59, BankRead, m(EOR), Y) - (0x5a, AM.Push.XF, "Y"), # opX(0x5a, Push, Y) - (0x5b, AM.Transfer16, "A", "D"), # opA(0x5b, Transfer16, A, D) - (0x5c, AM.JumpLong), # opA(0x5c, JumpLong) - (0x5d, AM.BankRead.MF, OP.EOR, "X"), # opM(0x5d, BankRead, m(EOR), X) - (0x5e, AM.BankIndexedModify.MF, OP.LSR), # opM(0x5e, BankIndexedModify, m(LSR)) - (0x5f, AM.LongRead.MF, OP.EOR, "X"), # opM(0x5f, LongRead, m(EOR), X) - (0x60, AM.ReturnShort), # opA(0x60, ReturnShort) - (0x61, AM.IndexedIndirectRead.MF, OP.ADC), # opM(0x61, IndexedIndirectRead, m(ADC)) - (0x62, AM.PushEffectiveRelativeAddress), # opA(0x62, PushEffectiveRelativeAddress) - (0x63, AM.StackRead.MF, OP.ADC), # opM(0x63, StackRead, m(ADC)) - (0x64, AM.DirectWrite.MF, "Z"), # opM(0x64, DirectWrite, Z) - (0x65, AM.DirectRead.MF, OP.ADC), # opM(0x65, DirectRead, m(ADC)) - (0x66, AM.DirectModify.MF, OP.ROR), # opM(0x66, DirectModify, m(ROR)) - (0x67, AM.IndirectLongRead.MF, OP.ADC), # opM(0x67, IndirectLongRead, m(ADC)) - (0x68, AM.Pull.MF, "A"), # opM(0x68, Pull, A) - (0x69, AM.ImmediateRead.MF, OP.ADC), # opM(0x69, ImmediateRead, m(ADC)) - (0x6a, AM.ImpliedModify.MF, OP.ROR, "A"), # opM(0x6a, ImpliedModify, m(ROR), A) - (0x6b, AM.ReturnLong), # opA(0x6b, ReturnLong) - (0x6c, AM.JumpIndirect), # opA(0x6c, JumpIndirect) - (0x6d, AM.BankRead.MF, OP.ADC), # opM(0x6d, BankRead, m(ADC)) - (0x6e, AM.BankModify.MF, OP.ROR), # opM(0x6e, BankModify, m(ROR)) - (0x6f, AM.LongRead.MF, OP.ADC), # opM(0x6f, LongRead, m(ADC)) - (0x70, AM.Branch, lambda cpu: cpu.VFlag), # opA(0x70, Branch, VF == 1) - (0x71, AM.IndirectIndexedRead.MF, OP.ADC), # opM(0x71, IndirectIndexedRead, m(ADC)) - (0x72, AM.IndirectRead.MF, OP.ADC), # opM(0x72, IndirectRead, m(ADC)) - (0x73, AM.IndirectStackRead.MF, OP.ADC), # opM(0x73, IndirectStackRead, m(ADC)) - (0x74, AM.DirectWrite.MF, "Z", "X"), # opM(0x74, DirectWrite, Z, X) - (0x75, AM.DirectRead.MF, OP.ADC, "X"), # opM(0x75, DirectRead, m(ADC), X) - (0x76, AM.DirectIndexedModify.MF, OP.ROR), # opM(0x76, DirectIndexedModify, m(ROR)) - (0x77, AM.IndirectLongRead.MF, OP.ADC, "Y"), # opM(0x77, IndirectLongRead, m(ADC), Y) - (0x78, AM.SetFlag, "IFlag"), # opA(0x78, SetFlag, IFlag) - (0x79, AM.BankRead.MF, OP.ADC, "Y"), # opM(0x79, BankRead, m(ADC), Y) - (0x7a, AM.Pull.XF, "Y"), # opX(0x7a, Pull, Y) - (0x7b, AM.Transfer16, "D", "A"), # opA(0x7b, Transfer16, D, A) - (0x7c, AM.JumpIndexedIndirect), # opA(0x7c, JumpIndexedIndirect) - (0x7d, AM.BankRead.MF, OP.ADC, "X"), # opM(0x7d, BankRead, m(ADC), X) - (0x7e, AM.BankIndexedModify.MF, OP.ROR), # opM(0x7e, BankIndexedModify, m(ROR)) - (0x7f, AM.LongRead.MF, OP.ADC, "X"), # opM(0x7f, LongRead, m(ADC), X) - (0x80, AM.Branch, lambda _: True), # opA(0x80, Branch) - (0x81, AM.IndexedIndirectWrite.MF), # opM(0x81, IndexedIndirectWrite) - (0x82, AM.BranchLong), # opA(0x82, BranchLong) - (0x83, AM.StackWrite.MF), # opM(0x83, StackWrite) - (0x84, AM.DirectWrite.XF, "Y"), # opX(0x84, DirectWrite, Y) - (0x85, AM.DirectWrite.MF, "A"), # opM(0x85, DirectWrite, A) - (0x86, AM.DirectWrite.XF, "X"), # opX(0x86, DirectWrite, X) - (0x87, AM.IndirectLongWrite.MF), # opM(0x87, IndirectLongWrite) - (0x88, AM.ImpliedModify.XF, OP.DEC, "Y"), # opX(0x88, ImpliedModify, x(DEC), Y) - (0x89, AM.BitImmediate.MF), # opM(0x89, BitImmediate) - (0x8a, AM.Transfer.MF, "X", "A"), # opM(0x8a, Transfer, X, A) - (0x8b, AM.Push8, "DB"), # opA(0x8b, Push8, (r16)B) - (0x8c, AM.BankWrite.XF, "Y"), # opX(0x8c, BankWrite, Y) - (0x8d, AM.BankWrite.MF, "A"), # opM(0x8d, BankWrite, A) - (0x8e, AM.BankWrite.XF, "X"), # opX(0x8e, BankWrite, X) - (0x8f, AM.LongWrite.MF), # opM(0x8f, LongWrite) - (0x90, AM.Branch, lambda cpu: not cpu.CFlag), # opA(0x90, Branch, CF == 0) - (0x91, AM.IndirectIndexedWrite.MF), # opM(0x91, IndirectIndexedWrite) - (0x92, AM.IndirectWrite.MF), # opM(0x92, IndirectWrite) - (0x93, AM.IndirectStackWrite.MF), # opM(0x93, IndirectStackWrite) - (0x94, AM.DirectWrite.XF, "Y", "X"), # opX(0x94, DirectWrite, Y, X) - (0x95, AM.DirectWrite.MF, "A", "X"), # opM(0x95, DirectWrite, A, X) - (0x96, AM.DirectWrite.XF, "X", "Y"), # opX(0x96, DirectWrite, X, Y) - (0x97, AM.IndirectLongWrite.MF, "Y"), # opM(0x97, IndirectLongWrite, Y) - (0x98, AM.Transfer.MF, "Y", "A"), # opM(0x98, Transfer, Y, A) - (0x99, AM.BankWrite.MF, "A", "Y"), # opM(0x99, BankWrite, A, Y) - (0x9a, AM.TransferXS), # opA(0x9a, TransferXS) - (0x9b, AM.Transfer.XF, "X", "Y"), # opX(0x9b, Transfer, X, Y) - (0x9c, AM.BankWrite.MF, "Z"), # opM(0x9c, BankWrite, Z) - (0x9d, AM.BankWrite.MF, "A", "X"), # opM(0x9d, BankWrite, A, X) - (0x9e, AM.BankWrite.MF, "Z", "X"), # opM(0x9e, BankWrite, Z, X) - (0x9f, AM.LongWrite.MF, "X"), # opM(0x9f, LongWrite, X) - (0xa0, AM.ImmediateRead.XF, OP.LDY), # opX(0xa0, ImmediateRead, x(LDY)) - (0xa1, AM.IndexedIndirectRead.MF, OP.LDA), # opM(0xa1, IndexedIndirectRead, m(LDA)) - (0xa2, AM.ImmediateRead.XF, OP.LDX), # opX(0xa2, ImmediateRead, x(LDX)) - (0xa3, AM.StackRead.MF, OP.LDA), # opM(0xa3, StackRead, m(LDA)) - (0xa4, AM.DirectRead.XF, OP.LDY), # opX(0xa4, DirectRead, x(LDY)) - (0xa5, AM.DirectRead.MF, OP.LDA), # opM(0xa5, DirectRead, m(LDA)) - (0xa6, AM.DirectRead.XF, OP.LDX), # opX(0xa6, DirectRead, x(LDX)) - (0xa7, AM.IndirectLongRead.MF, OP.LDA), # opM(0xa7, IndirectLongRead, m(LDA)) - (0xa8, AM.Transfer.XF, "A", "Y"), # opX(0xa8, Transfer, A, Y) - (0xa9, AM.ImmediateRead.MF, OP.LDA), # opM(0xa9, ImmediateRead, m(LDA)) - (0xaa, AM.Transfer.XF, "A", "X"), # opX(0xaa, Transfer, A, X) - (0xab, AM.PullB), # opA(0xab, PullB) - (0xac, AM.BankRead.XF, OP.LDY), # opX(0xac, BankRead, x(LDY)) - (0xad, AM.BankRead.MF, OP.LDA), # opM(0xad, BankRead, m(LDA)) - (0xae, AM.BankRead.XF, OP.LDX), # opX(0xae, BankRead, x(LDX)) - (0xaf, AM.LongRead.MF, OP.LDA), # opM(0xaf, LongRead, m(LDA)) - (0xb0, AM.Branch, lambda cpu: cpu.CFlag), # opA(0xb0, Branch, CF == 1) - (0xb1, AM.IndirectIndexedRead.MF, OP.LDA), # opM(0xb1, IndirectIndexedRead, m(LDA)) - (0xb2, AM.IndirectRead.MF, OP.LDA), # opM(0xb2, IndirectRead, m(LDA)) - (0xb3, AM.IndirectStackRead.MF, OP.LDA), # opM(0xb3, IndirectStackRead, m(LDA)) - (0xb4, AM.DirectRead.XF, OP.LDY, "X"), # opX(0xb4, DirectRead, x(LDY), X) - (0xb5, AM.DirectRead.MF, OP.LDA, "X"), # opM(0xb5, DirectRead, m(LDA), X) - (0xb6, AM.DirectRead.XF, OP.LDX, "Y"), # opX(0xb6, DirectRead, x(LDX), Y) - (0xb7, AM.IndirectLongRead.MF, OP.LDA, "Y"), # opM(0xb7, IndirectLongRead, m(LDA), Y) - (0xb8, AM.ClearFlag, "VFlag"), # opA(0xb8, ClearFlag, VF) - (0xb9, AM.BankRead.MF, OP.LDA, "Y"), # opM(0xb9, BankRead, m(LDA), Y) - (0xba, AM.TransferSX.XF), # opX(0xba, TransferSX) - (0xbb, AM.Transfer.XF, "Y", "X"), # opX(0xbb, Transfer, Y, X) - (0xbc, AM.BankRead.XF, OP.LDY, "X"), # opX(0xbc, BankRead, x(LDY), X) - (0xbd, AM.BankRead.MF, OP.LDA, "X"), # opM(0xbd, BankRead, m(LDA), X) - (0xbe, AM.BankRead.XF, OP.LDX, "Y"), # opX(0xbe, BankRead, x(LDX), Y) - (0xbf, AM.LongRead.MF, OP.LDA, "X"), # opM(0xbf, LongRead, m(LDA), X) - (0xc0, AM.ImmediateRead.XF, OP.CPY), # opX(0xc0, ImmediateRead, x(CPY)) - (0xc1, AM.IndexedIndirectRead.MF, OP.CMP), # opM(0xc1, IndexedIndirectRead, m(CMP)) - (0xc2, AM.ResetP), # opA(0xc2, ResetP) - (0xc3, AM.StackRead.MF, OP.CMP), # opM(0xc3, StackRead, m(CMP)) - (0xc4, AM.DirectRead.XF, OP.CPY), # opX(0xc4, DirectRead, x(CPY)) - (0xc5, AM.DirectRead.MF, OP.CMP), # opM(0xc5, DirectRead, m(CMP)) - (0xc6, AM.DirectModify.MF, OP.DEC), # opM(0xc6, DirectModify, m(DEC)) - (0xc7, AM.IndirectLongRead.MF, OP.CMP), # opM(0xc7, IndirectLongRead, m(CMP)) - (0xc8, AM.ImpliedModify.XF, OP.INC, "Y"), # opX(0xc8, ImpliedModify, x(INC), Y) - (0xc9, AM.ImmediateRead.MF, OP.CMP), # opM(0xc9, ImmediateRead, m(CMP)) - (0xca, AM.ImpliedModify.XF, OP.DEC, "X"), # opX(0xca, ImpliedModify, x(DEC), X) - (0xcb, AM.Wait), # opA(0xcb, Wait) - (0xcc, AM.BankRead.XF, OP.CPY), # opX(0xcc, BankRead, x(CPY)) - (0xcd, AM.BankRead.MF, OP.CMP), # opM(0xcd, BankRead, m(CMP)) - (0xce, AM.BankModify.MF, OP.DEC), # opM(0xce, BankModify, m(DEC)) - (0xcf, AM.LongRead.MF, OP.CMP), # opM(0xcf, LongRead, m(CMP)) - (0xd0, AM.Branch, lambda cpu: not cpu.ZFlag), # opA(0xd0, Branch, ZF == 0) - (0xd1, AM.IndirectIndexedRead.MF, OP.CMP), # opM(0xd1, IndirectIndexedRead, m(CMP)) - (0xd2, AM.IndirectRead.MF, OP.CMP), # opM(0xd2, IndirectRead, m(CMP)) - (0xd3, AM.IndirectStackRead.MF, OP.CMP), # opM(0xd3, IndirectStackRead, m(CMP)) - (0xd4, AM.PushEffectiveIndirectAddress), # opA(0xd4, PushEffectiveIndirectAddress) - (0xd5, AM.DirectRead.MF, OP.CMP, "X"), # opM(0xd5, DirectRead, m(CMP), X) - (0xd6, AM.DirectIndexedModify.MF, OP.DEC), # opM(0xd6, DirectIndexedModify, m(DEC)) - (0xd7, AM.IndirectLongRead.MF, OP.CMP, "Y"), # opM(0xd7, IndirectLongRead, m(CMP), Y) - (0xd8, AM.ClearFlag, "DFlag"), # opA(0xd8, ClearFlag, DF) - (0xd9, AM.BankRead.MF, OP.CMP, "Y"), # opM(0xd9, BankRead, m(CMP), Y) - (0xda, AM.Push.XF, "X"), # opX(0xda, Push, X) - (0xdb, AM.Stop), # opA(0xdb, Stop) - (0xdc, AM.JumpIndirectLong), # opA(0xdc, JumpIndirectLong) - (0xdd, AM.BankRead.MF, OP.CMP, "X"), # opM(0xdd, BankRead, m(CMP), X) - (0xde, AM.BankIndexedModify.MF, OP.DEC), # opM(0xde, BankIndexedModify, m(DEC)) - (0xdf, AM.LongRead.MF, OP.CMP, "X"), # opM(0xdf, LongRead, m(CMP), X) - (0xe0, AM.ImmediateRead.XF, OP.CPX), # opX(0xe0, ImmediateRead, x(CPX)) - (0xe1, AM.IndexedIndirectRead.MF, OP.SBC), # opM(0xe1, IndexedIndirectRead, m(SBC)) - (0xe2, AM.SetP), # opA(0xe2, SetP) - (0xe3, AM.StackRead.MF, OP.SBC), # opM(0xe3, StackRead, m(SBC)) - (0xe4, AM.DirectRead.XF, OP.CPX), # opX(0xe4, DirectRead, x(CPX)) - (0xe5, AM.DirectRead.MF, OP.SBC), # opM(0xe5, DirectRead, m(SBC)) - (0xe6, AM.DirectModify.MF, OP.INC), # opM(0xe6, DirectModify, m(INC)) - (0xe7, AM.IndirectLongRead.MF, OP.SBC), # opM(0xe7, IndirectLongRead, m(SBC)) - (0xe8, AM.ImpliedModify.XF, OP.INC, "X"), # opX(0xe8, ImpliedModify, x(INC), X) - (0xe9, AM.ImmediateRead.MF, OP.SBC), # opM(0xe9, ImmediateRead, m(SBC)) - (0xea, AM.NoOperation), # opA(0xea, NoOperation) - (0xeb, AM.ExchangeBA), # opA(0xeb, ExchangeBA) - (0xec, AM.BankRead.XF, OP.CPX), # opX(0xec, BankRead, x(CPX)) - (0xed, AM.BankRead.MF, OP.SBC), # opM(0xed, BankRead, m(SBC)) - (0xee, AM.BankModify.MF, OP.INC), # opM(0xee, BankModify, m(INC)) - (0xef, AM.LongRead.MF, OP.SBC), # opM(0xef, LongRead, m(SBC)) - (0xf0, AM.Branch, lambda cpu: cpu.ZFlag), # opA(0xf0, Branch, ZF == 1) - (0xf1, AM.IndirectIndexedRead.MF, OP.SBC), # opM(0xf1, IndirectIndexedRead, m(SBC)) - (0xf2, AM.IndirectRead.MF, OP.SBC), # opM(0xf2, IndirectRead, m(SBC)) - (0xf3, AM.IndirectStackRead.MF, OP.SBC), # opM(0xf3, IndirectStackRead, m(SBC)) - (0xf4, AM.PushEffectiveAddress), # opA(0xf4, PushEffectiveAddress) - (0xf5, AM.DirectRead.MF, OP.SBC, "X"), # opM(0xf5, DirectRead, m(SBC), X) - (0xf6, AM.DirectIndexedModify.MF, OP.INC), # opM(0xf6, DirectIndexedModify, m(INC)) - (0xf7, AM.IndirectLongRead.MF, OP.SBC, "Y"), # opM(0xf7, IndirectLongRead, m(SBC), Y) - (0xf8, AM.SetFlag, "DFlag"), # opA(0xf8, SetFlag, DF) - (0xf9, AM.BankRead.MF, OP.SBC, "Y"), # opM(0xf9, BankRead, m(SBC), Y) - (0xfa, AM.Pull.XF, "X"), # opX(0xfa, Pull, X) - (0xfb, AM.ExchangeCE), # opA(0xfb, ExchangeCE) - (0xfc, AM.CallIndexedIndirect), # opA(0xfc, CallIndexedIndirect) - (0xfd, AM.BankRead.MF, OP.SBC, "X"), # opM(0xfd, BankRead, m(SBC), X) - (0xfe, AM.BankIndexedModify.MF, OP.INC), # opM(0xfe, BankIndexedModify, m(INC)) - (0xff, AM.LongRead.MF, OP.SBC, "X"), # opM(0xff, LongRead, m(SBC), X) -) + opcodes_spec.py — the human-maintained spec (SPEC + MISC_SPEC) + scripts/gen_opcodes.py — generator: uv run scripts/gen_opcodes.py + opcodes_generated.py — the committed generated handlers + HANDLERS + +Memory/modify families are emitted as inlined literal handlers (index register, +width flag, and operation/source baked in, so PyPy folds them per opcode — ~2x +faster dispatch than the old decorator+string-table). The irregular ops (control +flow, flags, transfers, push/pull, block move, interrupt, exchanges) are emitted +as thin handlers that delegate to the tested addressing functions. Edit the +spec, not this file or the generated one. +""" +from .opcodes_generated import HANDLERS + +# load_instructions() consumes (opcode, handler) rows; each handler takes only +# cpu, so it becomes a nargs=0 instruction slot. +INSTRUCTIONS = tuple((opcode, HANDLERS[opcode]) for opcode in sorted(HANDLERS)) diff --git a/pysnes/cpu/wdc65816/opcodes_generated.py b/pysnes/cpu/wdc65816/opcodes_generated.py new file mode 100644 index 0000000..f7406da --- /dev/null +++ b/pysnes/cpu/wdc65816/opcodes_generated.py @@ -0,0 +1,3108 @@ +# AUTO-GENERATED by scripts/gen_opcodes.py from opcodes_spec.py. +# Do not edit by hand — change the spec/generator and regenerate. + +from . import addressing_modes as AM +from .opcodes import ADC, AND, ASL, BIT, CMP, CPX, CPY, DEC, EOR, INC, LDA, LDX, LDY, LSR, ORA, ROL, ROR, SBC, TRB, TSB + + +def op_01(cpu): # indexed_indirect_read ORA (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + ORA(cpu, False, cpu.W.w) + + +def op_03(cpu): # stack_read ORA (M) + cpu.U.l = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + cpu.W.h = cpu.readStack(cpu.U.l + 1) + ORA(cpu, False, cpu.W.w) + + +def op_04(cpu): # direct_modify TSB (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = TSB(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle() + cpu.W.w = TSB(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + + +def op_05(cpu): # direct_read ORA (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + ORA(cpu, False, cpu.W.w) + + +def op_06(cpu): # direct_modify ASL (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = ASL(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle() + cpu.W.w = ASL(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + + +def op_07(cpu): # indirect_long_read ORA (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + ORA(cpu, False, cpu.W.w) + + +def op_09(cpu): # immediate_read ORA (M) + if cpu.MFlag: + cpu.W.l = cpu.fetch() + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.fetch() + cpu.W.h = cpu.fetch() + ORA(cpu, False, cpu.W.w) + + +def op_0A(cpu): # implied_modify ASL A (M) + cpu.idleIRQ() + if cpu.MFlag: + cpu.A.l = ASL(cpu, True, cpu.A.l) + else: + cpu.A.w = ASL(cpu, False, cpu.A.w) + + +def op_0C(cpu): # bank_modify TSB (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = TSB(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + cpu.idle() + cpu.W.w = TSB(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + + +def op_0D(cpu): # bank_read ORA (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + ORA(cpu, False, cpu.W.w) + + +def op_0E(cpu): # bank_modify ASL (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = ASL(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + cpu.idle() + cpu.W.w = ASL(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + + +def op_0F(cpu): # long_read ORA (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + ORA(cpu, False, cpu.W.w) + + +def op_11(cpu): # indirect_indexed_read ORA (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + ORA(cpu, False, cpu.W.w) + + +def op_12(cpu): # indirect_read ORA (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + ORA(cpu, False, cpu.W.w) + + +def op_13(cpu): # indirect_stack_read ORA (M) + cpu.U.l = cpu.fetch() + cpu.idle() + cpu.V.l = cpu.readStack(cpu.U.l + 0) + cpu.V.h = cpu.readStack(cpu.U.l + 1) + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + ORA(cpu, False, cpu.W.w) + + +def op_14(cpu): # direct_modify TRB (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = TRB(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle() + cpu.W.w = TRB(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + + +def op_15(cpu): # direct_read ORA ,X (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + ORA(cpu, False, cpu.W.w) + + +def op_16(cpu): # direct_indexed_modify ASL (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = ASL(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + cpu.idle() + cpu.W.w = ASL(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + cpu.X.w + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + + +def op_17(cpu): # indirect_long_read ORA ,Y (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.Y.w + 1) + ORA(cpu, False, cpu.W.w) + + +def op_19(cpu): # bank_read ORA ,Y (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + ORA(cpu, False, cpu.W.w) + + +def op_1A(cpu): # implied_modify INC A (M) + cpu.idleIRQ() + if cpu.MFlag: + cpu.A.l = INC(cpu, True, cpu.A.l) + else: + cpu.A.w = INC(cpu, False, cpu.A.w) + + +def op_1C(cpu): # bank_modify TRB (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = TRB(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + cpu.idle() + cpu.W.w = TRB(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + + +def op_1D(cpu): # bank_read ORA ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.X.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + ORA(cpu, False, cpu.W.w) + + +def op_1E(cpu): # bank_indexed_modify ASL (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = ASL(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + cpu.idle() + cpu.W.w = ASL(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + cpu.X.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + + +def op_1F(cpu): # long_read ORA ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + ORA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.X.w + 1) + ORA(cpu, False, cpu.W.w) + + +def op_21(cpu): # indexed_indirect_read AND (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + AND(cpu, False, cpu.W.w) + + +def op_23(cpu): # stack_read AND (M) + cpu.U.l = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + cpu.W.h = cpu.readStack(cpu.U.l + 1) + AND(cpu, False, cpu.W.w) + + +def op_24(cpu): # direct_read BIT (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + BIT(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + BIT(cpu, False, cpu.W.w) + + +def op_25(cpu): # direct_read AND (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + AND(cpu, False, cpu.W.w) + + +def op_26(cpu): # direct_modify ROL (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = ROL(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle() + cpu.W.w = ROL(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + + +def op_27(cpu): # indirect_long_read AND (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + AND(cpu, False, cpu.W.w) + + +def op_29(cpu): # immediate_read AND (M) + if cpu.MFlag: + cpu.W.l = cpu.fetch() + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.fetch() + cpu.W.h = cpu.fetch() + AND(cpu, False, cpu.W.w) + + +def op_2A(cpu): # implied_modify ROL A (M) + cpu.idleIRQ() + if cpu.MFlag: + cpu.A.l = ROL(cpu, True, cpu.A.l) + else: + cpu.A.w = ROL(cpu, False, cpu.A.w) + + +def op_2C(cpu): # bank_read BIT (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + BIT(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + BIT(cpu, False, cpu.W.w) + + +def op_2D(cpu): # bank_read AND (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + AND(cpu, False, cpu.W.w) + + +def op_2E(cpu): # bank_modify ROL (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = ROL(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + cpu.idle() + cpu.W.w = ROL(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + + +def op_2F(cpu): # long_read AND (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + AND(cpu, False, cpu.W.w) + + +def op_31(cpu): # indirect_indexed_read AND (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + AND(cpu, False, cpu.W.w) + + +def op_32(cpu): # indirect_read AND (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + AND(cpu, False, cpu.W.w) + + +def op_33(cpu): # indirect_stack_read AND (M) + cpu.U.l = cpu.fetch() + cpu.idle() + cpu.V.l = cpu.readStack(cpu.U.l + 0) + cpu.V.h = cpu.readStack(cpu.U.l + 1) + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + AND(cpu, False, cpu.W.w) + + +def op_34(cpu): # direct_read BIT ,X (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + BIT(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + BIT(cpu, False, cpu.W.w) + + +def op_35(cpu): # direct_read AND ,X (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + AND(cpu, False, cpu.W.w) + + +def op_36(cpu): # direct_indexed_modify ROL (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = ROL(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + cpu.idle() + cpu.W.w = ROL(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + cpu.X.w + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + + +def op_37(cpu): # indirect_long_read AND ,Y (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.Y.w + 1) + AND(cpu, False, cpu.W.w) + + +def op_39(cpu): # bank_read AND ,Y (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + AND(cpu, False, cpu.W.w) + + +def op_3A(cpu): # implied_modify DEC A (M) + cpu.idleIRQ() + if cpu.MFlag: + cpu.A.l = DEC(cpu, True, cpu.A.l) + else: + cpu.A.w = DEC(cpu, False, cpu.A.w) + + +def op_3C(cpu): # bank_read BIT ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.X.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + BIT(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + BIT(cpu, False, cpu.W.w) + + +def op_3D(cpu): # bank_read AND ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.X.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + AND(cpu, False, cpu.W.w) + + +def op_3E(cpu): # bank_indexed_modify ROL (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = ROL(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + cpu.idle() + cpu.W.w = ROL(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + cpu.X.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + + +def op_3F(cpu): # long_read AND ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + AND(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.X.w + 1) + AND(cpu, False, cpu.W.w) + + +def op_41(cpu): # indexed_indirect_read EOR (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + EOR(cpu, False, cpu.W.w) + + +def op_43(cpu): # stack_read EOR (M) + cpu.U.l = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + cpu.W.h = cpu.readStack(cpu.U.l + 1) + EOR(cpu, False, cpu.W.w) + + +def op_45(cpu): # direct_read EOR (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + EOR(cpu, False, cpu.W.w) + + +def op_46(cpu): # direct_modify LSR (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = LSR(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle() + cpu.W.w = LSR(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + + +def op_47(cpu): # indirect_long_read EOR (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + EOR(cpu, False, cpu.W.w) + + +def op_49(cpu): # immediate_read EOR (M) + if cpu.MFlag: + cpu.W.l = cpu.fetch() + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.fetch() + cpu.W.h = cpu.fetch() + EOR(cpu, False, cpu.W.w) + + +def op_4A(cpu): # implied_modify LSR A (M) + cpu.idleIRQ() + if cpu.MFlag: + cpu.A.l = LSR(cpu, True, cpu.A.l) + else: + cpu.A.w = LSR(cpu, False, cpu.A.w) + + +def op_4D(cpu): # bank_read EOR (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + EOR(cpu, False, cpu.W.w) + + +def op_4E(cpu): # bank_modify LSR (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = LSR(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + cpu.idle() + cpu.W.w = LSR(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + + +def op_4F(cpu): # long_read EOR (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + EOR(cpu, False, cpu.W.w) + + +def op_51(cpu): # indirect_indexed_read EOR (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + EOR(cpu, False, cpu.W.w) + + +def op_52(cpu): # indirect_read EOR (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + EOR(cpu, False, cpu.W.w) + + +def op_53(cpu): # indirect_stack_read EOR (M) + cpu.U.l = cpu.fetch() + cpu.idle() + cpu.V.l = cpu.readStack(cpu.U.l + 0) + cpu.V.h = cpu.readStack(cpu.U.l + 1) + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + EOR(cpu, False, cpu.W.w) + + +def op_55(cpu): # direct_read EOR ,X (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + EOR(cpu, False, cpu.W.w) + + +def op_56(cpu): # direct_indexed_modify LSR (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = LSR(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + cpu.idle() + cpu.W.w = LSR(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + cpu.X.w + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + + +def op_57(cpu): # indirect_long_read EOR ,Y (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.Y.w + 1) + EOR(cpu, False, cpu.W.w) + + +def op_59(cpu): # bank_read EOR ,Y (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + EOR(cpu, False, cpu.W.w) + + +def op_5D(cpu): # bank_read EOR ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.X.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + EOR(cpu, False, cpu.W.w) + + +def op_5E(cpu): # bank_indexed_modify LSR (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = LSR(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + cpu.idle() + cpu.W.w = LSR(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + cpu.X.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + + +def op_5F(cpu): # long_read EOR ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + EOR(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.X.w + 1) + EOR(cpu, False, cpu.W.w) + + +def op_61(cpu): # indexed_indirect_read ADC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + ADC(cpu, False, cpu.W.w) + + +def op_63(cpu): # stack_read ADC (M) + cpu.U.l = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + cpu.W.h = cpu.readStack(cpu.U.l + 1) + ADC(cpu, False, cpu.W.w) + + +def op_64(cpu): # direct_write Z (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.writeDirect(cpu.U.l + 0, cpu.Z.l) + else: + cpu.writeDirect(cpu.U.l + 0, cpu.Z.l) + cpu.writeDirect(cpu.U.l + 1, cpu.Z.h) + + +def op_65(cpu): # direct_read ADC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + ADC(cpu, False, cpu.W.w) + + +def op_66(cpu): # direct_modify ROR (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = ROR(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle() + cpu.W.w = ROR(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + + +def op_67(cpu): # indirect_long_read ADC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + ADC(cpu, False, cpu.W.w) + + +def op_69(cpu): # immediate_read ADC (M) + if cpu.MFlag: + cpu.W.l = cpu.fetch() + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.fetch() + cpu.W.h = cpu.fetch() + ADC(cpu, False, cpu.W.w) + + +def op_6A(cpu): # implied_modify ROR A (M) + cpu.idleIRQ() + if cpu.MFlag: + cpu.A.l = ROR(cpu, True, cpu.A.l) + else: + cpu.A.w = ROR(cpu, False, cpu.A.w) + + +def op_6D(cpu): # bank_read ADC (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + ADC(cpu, False, cpu.W.w) + + +def op_6E(cpu): # bank_modify ROR (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = ROR(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + cpu.idle() + cpu.W.w = ROR(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + + +def op_6F(cpu): # long_read ADC (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + ADC(cpu, False, cpu.W.w) + + +def op_71(cpu): # indirect_indexed_read ADC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + ADC(cpu, False, cpu.W.w) + + +def op_72(cpu): # indirect_read ADC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + ADC(cpu, False, cpu.W.w) + + +def op_73(cpu): # indirect_stack_read ADC (M) + cpu.U.l = cpu.fetch() + cpu.idle() + cpu.V.l = cpu.readStack(cpu.U.l + 0) + cpu.V.h = cpu.readStack(cpu.U.l + 1) + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + ADC(cpu, False, cpu.W.w) + + +def op_74(cpu): # direct_write Z ,X (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.Z.l) + else: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.Z.l) + cpu.writeDirect(cpu.U.l + cpu.X.w + 1, cpu.Z.h) + + +def op_75(cpu): # direct_read ADC ,X (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + ADC(cpu, False, cpu.W.w) + + +def op_76(cpu): # direct_indexed_modify ROR (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = ROR(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + cpu.idle() + cpu.W.w = ROR(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + cpu.X.w + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + + +def op_77(cpu): # indirect_long_read ADC ,Y (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.Y.w + 1) + ADC(cpu, False, cpu.W.w) + + +def op_79(cpu): # bank_read ADC ,Y (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + ADC(cpu, False, cpu.W.w) + + +def op_7D(cpu): # bank_read ADC ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.X.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + ADC(cpu, False, cpu.W.w) + + +def op_7E(cpu): # bank_indexed_modify ROR (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = ROR(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + cpu.idle() + cpu.W.w = ROR(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + cpu.X.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + + +def op_7F(cpu): # long_read ADC ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + ADC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.X.w + 1) + ADC(cpu, False, cpu.W.w) + + +def op_81(cpu): # indexed_indirect_write (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + if cpu.MFlag: + cpu.writeBank(cpu.V.w + 0, cpu.A.l) + else: + cpu.writeBank(cpu.V.w + 0, cpu.A.l) + cpu.writeBank(cpu.V.w + 1, cpu.A.h) + + +def op_83(cpu): # stack_write (M) + cpu.U.l = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.writeStack(cpu.U.l + 0, cpu.A.l) + else: + cpu.writeStack(cpu.U.l + 0, cpu.A.l) + cpu.writeStack(cpu.U.l + 1, cpu.A.h) + + +def op_84(cpu): # direct_write Y (X) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.XFlag: + cpu.writeDirect(cpu.U.l + 0, cpu.Y.l) + else: + cpu.writeDirect(cpu.U.l + 0, cpu.Y.l) + cpu.writeDirect(cpu.U.l + 1, cpu.Y.h) + + +def op_85(cpu): # direct_write A (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.writeDirect(cpu.U.l + 0, cpu.A.l) + else: + cpu.writeDirect(cpu.U.l + 0, cpu.A.l) + cpu.writeDirect(cpu.U.l + 1, cpu.A.h) + + +def op_86(cpu): # direct_write X (X) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.XFlag: + cpu.writeDirect(cpu.U.l + 0, cpu.X.l) + else: + cpu.writeDirect(cpu.U.l + 0, cpu.X.l) + cpu.writeDirect(cpu.U.l + 1, cpu.X.h) + + +def op_87(cpu): # indirect_long_write (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.writeLong(cpu.V.d + 0, cpu.A.l) + else: + cpu.writeLong(cpu.V.d + 0, cpu.A.l) + cpu.writeLong(cpu.V.d + 1, cpu.A.h) + + +def op_88(cpu): # implied_modify DEC Y (X) + cpu.idleIRQ() + if cpu.XFlag: + cpu.Y.l = DEC(cpu, True, cpu.Y.l) + else: + cpu.Y.w = DEC(cpu, False, cpu.Y.w) + + +def op_8C(cpu): # bank_write Y (X) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.XFlag: + cpu.writeBank(cpu.V.w + 0, cpu.Y.l) + else: + cpu.writeBank(cpu.V.w + 0, cpu.Y.l) + cpu.writeBank(cpu.V.w + 1, cpu.Y.h) + + +def op_8D(cpu): # bank_write A (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.writeBank(cpu.V.w + 0, cpu.A.l) + else: + cpu.writeBank(cpu.V.w + 0, cpu.A.l) + cpu.writeBank(cpu.V.w + 1, cpu.A.h) + + +def op_8E(cpu): # bank_write X (X) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.XFlag: + cpu.writeBank(cpu.V.w + 0, cpu.X.l) + else: + cpu.writeBank(cpu.V.w + 0, cpu.X.l) + cpu.writeBank(cpu.V.w + 1, cpu.X.h) + + +def op_8F(cpu): # long_write (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.writeLong(cpu.V.d + 0, cpu.A.l) + else: + cpu.writeLong(cpu.V.d + 0, cpu.A.l) + cpu.writeLong(cpu.V.d + 1, cpu.A.h) + + +def op_91(cpu): # indirect_indexed_write (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle() + if cpu.MFlag: + cpu.writeBank(cpu.V.w + cpu.Y.w + 0, cpu.A.l) + else: + cpu.writeBank(cpu.V.w + cpu.Y.w + 0, cpu.A.l) + cpu.writeBank(cpu.V.w + cpu.Y.w + 1, cpu.A.h) + + +def op_92(cpu): # indirect_write (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + if cpu.MFlag: + cpu.writeBank(cpu.V.w + 0, cpu.A.l) + else: + cpu.writeBank(cpu.V.w + 0, cpu.A.l) + cpu.writeBank(cpu.V.w + 1, cpu.A.h) + + +def op_93(cpu): # indirect_stack_write (M) + cpu.U.l = cpu.fetch() + cpu.idle() + cpu.V.l = cpu.readStack(cpu.U.l + 0) + cpu.V.h = cpu.readStack(cpu.U.l + 1) + cpu.idle() + if cpu.MFlag: + cpu.writeBank(cpu.V.w + cpu.Y.w + 0, cpu.A.l) + else: + cpu.writeBank(cpu.V.w + cpu.Y.w + 0, cpu.A.l) + cpu.writeBank(cpu.V.w + cpu.Y.w + 1, cpu.A.h) + + +def op_94(cpu): # direct_write Y ,X (X) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.XFlag: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.Y.l) + else: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.Y.l) + cpu.writeDirect(cpu.U.l + cpu.X.w + 1, cpu.Y.h) + + +def op_95(cpu): # direct_write A ,X (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.A.l) + else: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.A.l) + cpu.writeDirect(cpu.U.l + cpu.X.w + 1, cpu.A.h) + + +def op_96(cpu): # direct_write X ,Y (X) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.XFlag: + cpu.writeDirect(cpu.U.l + cpu.Y.w + 0, cpu.X.l) + else: + cpu.writeDirect(cpu.U.l + cpu.Y.w + 0, cpu.X.l) + cpu.writeDirect(cpu.U.l + cpu.Y.w + 1, cpu.X.h) + + +def op_97(cpu): # indirect_long_write ,Y (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.writeLong(cpu.V.d + cpu.Y.w + 0, cpu.A.l) + else: + cpu.writeLong(cpu.V.d + cpu.Y.w + 0, cpu.A.l) + cpu.writeLong(cpu.V.d + cpu.Y.w + 1, cpu.A.h) + + +def op_99(cpu): # bank_write A ,Y (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.writeBank(cpu.V.w + cpu.Y.w + 0, cpu.A.l) + else: + cpu.writeBank(cpu.V.w + cpu.Y.w + 0, cpu.A.l) + cpu.writeBank(cpu.V.w + cpu.Y.w + 1, cpu.A.h) + + +def op_9C(cpu): # bank_write Z (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.writeBank(cpu.V.w + 0, cpu.Z.l) + else: + cpu.writeBank(cpu.V.w + 0, cpu.Z.l) + cpu.writeBank(cpu.V.w + 1, cpu.Z.h) + + +def op_9D(cpu): # bank_write A ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.A.l) + else: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.A.l) + cpu.writeBank(cpu.V.w + cpu.X.w + 1, cpu.A.h) + + +def op_9E(cpu): # bank_write Z ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.Z.l) + else: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.Z.l) + cpu.writeBank(cpu.V.w + cpu.X.w + 1, cpu.Z.h) + + +def op_9F(cpu): # long_write ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.writeLong(cpu.V.d + cpu.X.w + 0, cpu.A.l) + else: + cpu.writeLong(cpu.V.d + cpu.X.w + 0, cpu.A.l) + cpu.writeLong(cpu.V.d + cpu.X.w + 1, cpu.A.h) + + +def op_A0(cpu): # immediate_read LDY (X) + if cpu.XFlag: + cpu.W.l = cpu.fetch() + LDY(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.fetch() + cpu.W.h = cpu.fetch() + LDY(cpu, False, cpu.W.w) + + +def op_A1(cpu): # indexed_indirect_read LDA (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + LDA(cpu, False, cpu.W.w) + + +def op_A2(cpu): # immediate_read LDX (X) + if cpu.XFlag: + cpu.W.l = cpu.fetch() + LDX(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.fetch() + cpu.W.h = cpu.fetch() + LDX(cpu, False, cpu.W.w) + + +def op_A3(cpu): # stack_read LDA (M) + cpu.U.l = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + cpu.W.h = cpu.readStack(cpu.U.l + 1) + LDA(cpu, False, cpu.W.w) + + +def op_A4(cpu): # direct_read LDY (X) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.XFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + LDY(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + LDY(cpu, False, cpu.W.w) + + +def op_A5(cpu): # direct_read LDA (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + LDA(cpu, False, cpu.W.w) + + +def op_A6(cpu): # direct_read LDX (X) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.XFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + LDX(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + LDX(cpu, False, cpu.W.w) + + +def op_A7(cpu): # indirect_long_read LDA (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + LDA(cpu, False, cpu.W.w) + + +def op_A9(cpu): # immediate_read LDA (M) + if cpu.MFlag: + cpu.W.l = cpu.fetch() + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.fetch() + cpu.W.h = cpu.fetch() + LDA(cpu, False, cpu.W.w) + + +def op_AC(cpu): # bank_read LDY (X) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.XFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + LDY(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + LDY(cpu, False, cpu.W.w) + + +def op_AD(cpu): # bank_read LDA (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + LDA(cpu, False, cpu.W.w) + + +def op_AE(cpu): # bank_read LDX (X) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.XFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + LDX(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + LDX(cpu, False, cpu.W.w) + + +def op_AF(cpu): # long_read LDA (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + LDA(cpu, False, cpu.W.w) + + +def op_B1(cpu): # indirect_indexed_read LDA (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + LDA(cpu, False, cpu.W.w) + + +def op_B2(cpu): # indirect_read LDA (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + LDA(cpu, False, cpu.W.w) + + +def op_B3(cpu): # indirect_stack_read LDA (M) + cpu.U.l = cpu.fetch() + cpu.idle() + cpu.V.l = cpu.readStack(cpu.U.l + 0) + cpu.V.h = cpu.readStack(cpu.U.l + 1) + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + LDA(cpu, False, cpu.W.w) + + +def op_B4(cpu): # direct_read LDY ,X (X) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.XFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + LDY(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + LDY(cpu, False, cpu.W.w) + + +def op_B5(cpu): # direct_read LDA ,X (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + LDA(cpu, False, cpu.W.w) + + +def op_B6(cpu): # direct_read LDX ,Y (X) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.XFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.Y.w + 0) + LDX(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.Y.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.Y.w + 1) + LDX(cpu, False, cpu.W.w) + + +def op_B7(cpu): # indirect_long_read LDA ,Y (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.Y.w + 1) + LDA(cpu, False, cpu.W.w) + + +def op_B9(cpu): # bank_read LDA ,Y (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + LDA(cpu, False, cpu.W.w) + + +def op_BC(cpu): # bank_read LDY ,X (X) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.X.w) + if cpu.XFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + LDY(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + LDY(cpu, False, cpu.W.w) + + +def op_BD(cpu): # bank_read LDA ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.X.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + LDA(cpu, False, cpu.W.w) + + +def op_BE(cpu): # bank_read LDX ,Y (X) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.XFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + LDX(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + LDX(cpu, False, cpu.W.w) + + +def op_BF(cpu): # long_read LDA ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.X.w + 1) + LDA(cpu, False, cpu.W.w) + + +def op_C0(cpu): # immediate_read CPY (X) + if cpu.XFlag: + cpu.W.l = cpu.fetch() + CPY(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.fetch() + cpu.W.h = cpu.fetch() + CPY(cpu, False, cpu.W.w) + + +def op_C1(cpu): # indexed_indirect_read CMP (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + CMP(cpu, False, cpu.W.w) + + +def op_C3(cpu): # stack_read CMP (M) + cpu.U.l = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + cpu.W.h = cpu.readStack(cpu.U.l + 1) + CMP(cpu, False, cpu.W.w) + + +def op_C4(cpu): # direct_read CPY (X) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.XFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + CPY(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + CPY(cpu, False, cpu.W.w) + + +def op_C5(cpu): # direct_read CMP (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + CMP(cpu, False, cpu.W.w) + + +def op_C6(cpu): # direct_modify DEC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = DEC(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle() + cpu.W.w = DEC(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + + +def op_C7(cpu): # indirect_long_read CMP (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + CMP(cpu, False, cpu.W.w) + + +def op_C8(cpu): # implied_modify INC Y (X) + cpu.idleIRQ() + if cpu.XFlag: + cpu.Y.l = INC(cpu, True, cpu.Y.l) + else: + cpu.Y.w = INC(cpu, False, cpu.Y.w) + + +def op_C9(cpu): # immediate_read CMP (M) + if cpu.MFlag: + cpu.W.l = cpu.fetch() + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.fetch() + cpu.W.h = cpu.fetch() + CMP(cpu, False, cpu.W.w) + + +def op_CA(cpu): # implied_modify DEC X (X) + cpu.idleIRQ() + if cpu.XFlag: + cpu.X.l = DEC(cpu, True, cpu.X.l) + else: + cpu.X.w = DEC(cpu, False, cpu.X.w) + + +def op_CC(cpu): # bank_read CPY (X) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.XFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + CPY(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + CPY(cpu, False, cpu.W.w) + + +def op_CD(cpu): # bank_read CMP (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + CMP(cpu, False, cpu.W.w) + + +def op_CE(cpu): # bank_modify DEC (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = DEC(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + cpu.idle() + cpu.W.w = DEC(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + + +def op_CF(cpu): # long_read CMP (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + CMP(cpu, False, cpu.W.w) + + +def op_D1(cpu): # indirect_indexed_read CMP (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + CMP(cpu, False, cpu.W.w) + + +def op_D2(cpu): # indirect_read CMP (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + CMP(cpu, False, cpu.W.w) + + +def op_D3(cpu): # indirect_stack_read CMP (M) + cpu.U.l = cpu.fetch() + cpu.idle() + cpu.V.l = cpu.readStack(cpu.U.l + 0) + cpu.V.h = cpu.readStack(cpu.U.l + 1) + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + CMP(cpu, False, cpu.W.w) + + +def op_D5(cpu): # direct_read CMP ,X (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + CMP(cpu, False, cpu.W.w) + + +def op_D6(cpu): # direct_indexed_modify DEC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = DEC(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + cpu.idle() + cpu.W.w = DEC(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + cpu.X.w + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + + +def op_D7(cpu): # indirect_long_read CMP ,Y (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.Y.w + 1) + CMP(cpu, False, cpu.W.w) + + +def op_D9(cpu): # bank_read CMP ,Y (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + CMP(cpu, False, cpu.W.w) + + +def op_DD(cpu): # bank_read CMP ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.X.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + CMP(cpu, False, cpu.W.w) + + +def op_DE(cpu): # bank_indexed_modify DEC (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = DEC(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + cpu.idle() + cpu.W.w = DEC(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + cpu.X.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + + +def op_DF(cpu): # long_read CMP ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + CMP(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.X.w + 1) + CMP(cpu, False, cpu.W.w) + + +def op_E0(cpu): # immediate_read CPX (X) + if cpu.XFlag: + cpu.W.l = cpu.fetch() + CPX(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.fetch() + cpu.W.h = cpu.fetch() + CPX(cpu, False, cpu.W.w) + + +def op_E1(cpu): # indexed_indirect_read SBC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + SBC(cpu, False, cpu.W.w) + + +def op_E3(cpu): # stack_read SBC (M) + cpu.U.l = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readStack(cpu.U.l + 0) + cpu.W.h = cpu.readStack(cpu.U.l + 1) + SBC(cpu, False, cpu.W.w) + + +def op_E4(cpu): # direct_read CPX (X) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.XFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + CPX(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + CPX(cpu, False, cpu.W.w) + + +def op_E5(cpu): # direct_read SBC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + SBC(cpu, False, cpu.W.w) + + +def op_E6(cpu): # direct_modify INC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = INC(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle() + cpu.W.w = INC(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + 0, cpu.W.l) + + +def op_E7(cpu): # indirect_long_read SBC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + SBC(cpu, False, cpu.W.w) + + +def op_E8(cpu): # implied_modify INC X (X) + cpu.idleIRQ() + if cpu.XFlag: + cpu.X.l = INC(cpu, True, cpu.X.l) + else: + cpu.X.w = INC(cpu, False, cpu.X.w) + + +def op_E9(cpu): # immediate_read SBC (M) + if cpu.MFlag: + cpu.W.l = cpu.fetch() + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.fetch() + cpu.W.h = cpu.fetch() + SBC(cpu, False, cpu.W.w) + + +def op_EC(cpu): # bank_read CPX (X) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.XFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + CPX(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + CPX(cpu, False, cpu.W.w) + + +def op_ED(cpu): # bank_read SBC (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + SBC(cpu, False, cpu.W.w) + + +def op_EE(cpu): # bank_modify INC (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = INC(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + cpu.idle() + cpu.W.w = INC(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + 0, cpu.W.l) + + +def op_EF(cpu): # long_read SBC (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + 0) + cpu.W.h = cpu.readLong(cpu.V.d + 1) + SBC(cpu, False, cpu.W.w) + + +def op_F1(cpu): # indirect_indexed_read SBC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + SBC(cpu, False, cpu.W.w) + + +def op_F2(cpu): # indirect_read SBC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirect(cpu.U.l + 0) + cpu.V.h = cpu.readDirect(cpu.U.l + 1) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + 1) + SBC(cpu, False, cpu.W.w) + + +def op_F3(cpu): # indirect_stack_read SBC (M) + cpu.U.l = cpu.fetch() + cpu.idle() + cpu.V.l = cpu.readStack(cpu.U.l + 0) + cpu.V.h = cpu.readStack(cpu.U.l + 1) + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + SBC(cpu, False, cpu.W.w) + + +def op_F5(cpu): # direct_read SBC ,X (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + SBC(cpu, False, cpu.W.w) + + +def op_F6(cpu): # direct_indexed_modify INC (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + if cpu.EF: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = INC(cpu, True, cpu.W.l) + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + cpu.idle() + cpu.W.w = INC(cpu, False, cpu.W.w) + cpu.writeDirect(cpu.U.l + cpu.X.w + 1, cpu.W.h) + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.W.l) + + +def op_F7(cpu): # indirect_long_read SBC ,Y (M) + cpu.U.l = cpu.fetch() + cpu.idle2() + cpu.V.l = cpu.readDirectN(cpu.U.l + 0) + cpu.V.h = cpu.readDirectN(cpu.U.l + 1) + cpu.V.b = cpu.readDirectN(cpu.U.l + 2) + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.Y.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.Y.w + 1) + SBC(cpu, False, cpu.W.w) + + +def op_F9(cpu): # bank_read SBC ,Y (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.Y.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.Y.w + 1) + SBC(cpu, False, cpu.W.w) + + +def op_FD(cpu): # bank_read SBC ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.X.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + SBC(cpu, False, cpu.W.w) + + +def op_FE(cpu): # bank_indexed_modify INC (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + if cpu.EF: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + else: + cpu.idle() + cpu.W.l = INC(cpu, True, cpu.W.l) + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + cpu.idle() + cpu.W.w = INC(cpu, False, cpu.W.w) + cpu.writeBank(cpu.V.w + cpu.X.w + 1, cpu.W.h) + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.W.l) + + +def op_FF(cpu): # long_read SBC ,X (M) + cpu.V.l = cpu.fetch() + cpu.V.h = cpu.fetch() + cpu.V.b = cpu.fetch() + if cpu.MFlag: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + SBC(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readLong(cpu.V.d + cpu.X.w + 0) + cpu.W.h = cpu.readLong(cpu.V.d + cpu.X.w + 1) + SBC(cpu, False, cpu.W.w) + + +_arg_00 = lambda cpu: 0xfffe if cpu.EF else 0xffe6 +def op_00(cpu): # Interrupt + AM.Interrupt(cpu, _arg_00) + + +_arg_02 = lambda cpu: 0xfff4 if cpu.EF else 0xffe4 +def op_02(cpu): # Interrupt + AM.Interrupt(cpu, _arg_02) + + +def op_08(cpu): # Push8 + AM.Push8(cpu, "P") + + +def op_0B(cpu): # PushD + AM.PushD(cpu) + + +_arg_10 = lambda cpu: not cpu.NFlag +def op_10(cpu): # Branch + AM.Branch(cpu, _arg_10) + + +def op_18(cpu): # ClearFlag + AM.ClearFlag(cpu, "CFlag") + + +def op_1B(cpu): # TransferCS + AM.TransferCS(cpu) + + +def op_20(cpu): # CallShort + AM.CallShort(cpu) + + +def op_22(cpu): # CallLong + AM.CallLong(cpu) + + +def op_28(cpu): # PullP + AM.PullP(cpu) + + +def op_2B(cpu): # PullD + AM.PullD(cpu) + + +_arg_30 = lambda cpu: cpu.NFlag +def op_30(cpu): # Branch + AM.Branch(cpu, _arg_30) + + +def op_38(cpu): # SetFlag + AM.SetFlag(cpu, "CFlag") + + +def op_3B(cpu): # Transfer16 + AM.Transfer16(cpu, "S", "A") + + +def op_40(cpu): # ReturnInterrupt + AM.ReturnInterrupt(cpu) + + +def op_42(cpu): # Prefix + AM.Prefix(cpu) + + +def op_44(cpu): # BlockMove + AM.BlockMove(cpu, cpu.XFlag, -1) + + +def op_48(cpu): # Push + AM.Push(cpu, cpu.MFlag, "A") + + +def op_4B(cpu): # Push8 + AM.Push8(cpu, "PC.b") + + +def op_4C(cpu): # JumpShort + AM.JumpShort(cpu) + + +_arg_50 = lambda cpu: not cpu.VFlag +def op_50(cpu): # Branch + AM.Branch(cpu, _arg_50) + + +def op_54(cpu): # BlockMove + AM.BlockMove(cpu, cpu.XFlag, +1) + + +def op_58(cpu): # ClearFlag + AM.ClearFlag(cpu, "IFlag") + + +def op_5A(cpu): # Push + AM.Push(cpu, cpu.XFlag, "Y") + + +def op_5B(cpu): # Transfer16 + AM.Transfer16(cpu, "A", "D") + + +def op_5C(cpu): # JumpLong + AM.JumpLong(cpu) + + +def op_60(cpu): # ReturnShort + AM.ReturnShort(cpu) + + +def op_62(cpu): # PushEffectiveRelativeAddress + AM.PushEffectiveRelativeAddress(cpu) + + +def op_68(cpu): # Pull + AM.Pull(cpu, cpu.MFlag, "A") + + +def op_6B(cpu): # ReturnLong + AM.ReturnLong(cpu) + + +def op_6C(cpu): # JumpIndirect + AM.JumpIndirect(cpu) + + +_arg_70 = lambda cpu: cpu.VFlag +def op_70(cpu): # Branch + AM.Branch(cpu, _arg_70) + + +def op_78(cpu): # SetFlag + AM.SetFlag(cpu, "IFlag") + + +def op_7A(cpu): # Pull + AM.Pull(cpu, cpu.XFlag, "Y") + + +def op_7B(cpu): # Transfer16 + AM.Transfer16(cpu, "D", "A") + + +def op_7C(cpu): # JumpIndexedIndirect + AM.JumpIndexedIndirect(cpu) + + +_arg_80 = lambda _: True +def op_80(cpu): # Branch + AM.Branch(cpu, _arg_80) + + +def op_82(cpu): # BranchLong + AM.BranchLong(cpu) + + +def op_89(cpu): # BitImmediate + AM.BitImmediate(cpu, cpu.MFlag) + + +def op_8A(cpu): # Transfer + AM.Transfer(cpu, cpu.MFlag, "X", "A") + + +def op_8B(cpu): # Push8 + AM.Push8(cpu, "DB") + + +_arg_90 = lambda cpu: not cpu.CFlag +def op_90(cpu): # Branch + AM.Branch(cpu, _arg_90) + + +def op_98(cpu): # Transfer + AM.Transfer(cpu, cpu.MFlag, "Y", "A") + + +def op_9A(cpu): # TransferXS + AM.TransferXS(cpu) + + +def op_9B(cpu): # Transfer + AM.Transfer(cpu, cpu.XFlag, "X", "Y") + + +def op_A8(cpu): # Transfer + AM.Transfer(cpu, cpu.XFlag, "A", "Y") + + +def op_AA(cpu): # Transfer + AM.Transfer(cpu, cpu.XFlag, "A", "X") + + +def op_AB(cpu): # PullB + AM.PullB(cpu) + + +_arg_B0 = lambda cpu: cpu.CFlag +def op_B0(cpu): # Branch + AM.Branch(cpu, _arg_B0) + + +def op_B8(cpu): # ClearFlag + AM.ClearFlag(cpu, "VFlag") + + +def op_BA(cpu): # TransferSX + AM.TransferSX(cpu, cpu.XFlag) + + +def op_BB(cpu): # Transfer + AM.Transfer(cpu, cpu.XFlag, "Y", "X") + + +def op_C2(cpu): # ResetP + AM.ResetP(cpu) + + +def op_CB(cpu): # Wait + AM.Wait(cpu) + + +_arg_D0 = lambda cpu: not cpu.ZFlag +def op_D0(cpu): # Branch + AM.Branch(cpu, _arg_D0) + + +def op_D4(cpu): # PushEffectiveIndirectAddress + AM.PushEffectiveIndirectAddress(cpu) + + +def op_D8(cpu): # ClearFlag + AM.ClearFlag(cpu, "DFlag") + + +def op_DA(cpu): # Push + AM.Push(cpu, cpu.XFlag, "X") + + +def op_DB(cpu): # Stop + AM.Stop(cpu) + + +def op_DC(cpu): # JumpIndirectLong + AM.JumpIndirectLong(cpu) + + +def op_E2(cpu): # SetP + AM.SetP(cpu) + + +def op_EA(cpu): # NoOperation + AM.NoOperation(cpu) + + +def op_EB(cpu): # ExchangeBA + AM.ExchangeBA(cpu) + + +_arg_F0 = lambda cpu: cpu.ZFlag +def op_F0(cpu): # Branch + AM.Branch(cpu, _arg_F0) + + +def op_F4(cpu): # PushEffectiveAddress + AM.PushEffectiveAddress(cpu) + + +def op_F8(cpu): # SetFlag + AM.SetFlag(cpu, "DFlag") + + +def op_FA(cpu): # Pull + AM.Pull(cpu, cpu.XFlag, "X") + + +def op_FB(cpu): # ExchangeCE + AM.ExchangeCE(cpu) + + +def op_FC(cpu): # CallIndexedIndirect + AM.CallIndexedIndirect(cpu) + + +HANDLERS = { + 0x00: op_00, + 0x01: op_01, + 0x02: op_02, + 0x03: op_03, + 0x04: op_04, + 0x05: op_05, + 0x06: op_06, + 0x07: op_07, + 0x08: op_08, + 0x09: op_09, + 0x0A: op_0A, + 0x0B: op_0B, + 0x0C: op_0C, + 0x0D: op_0D, + 0x0E: op_0E, + 0x0F: op_0F, + 0x10: op_10, + 0x11: op_11, + 0x12: op_12, + 0x13: op_13, + 0x14: op_14, + 0x15: op_15, + 0x16: op_16, + 0x17: op_17, + 0x18: op_18, + 0x19: op_19, + 0x1A: op_1A, + 0x1B: op_1B, + 0x1C: op_1C, + 0x1D: op_1D, + 0x1E: op_1E, + 0x1F: op_1F, + 0x20: op_20, + 0x21: op_21, + 0x22: op_22, + 0x23: op_23, + 0x24: op_24, + 0x25: op_25, + 0x26: op_26, + 0x27: op_27, + 0x28: op_28, + 0x29: op_29, + 0x2A: op_2A, + 0x2B: op_2B, + 0x2C: op_2C, + 0x2D: op_2D, + 0x2E: op_2E, + 0x2F: op_2F, + 0x30: op_30, + 0x31: op_31, + 0x32: op_32, + 0x33: op_33, + 0x34: op_34, + 0x35: op_35, + 0x36: op_36, + 0x37: op_37, + 0x38: op_38, + 0x39: op_39, + 0x3A: op_3A, + 0x3B: op_3B, + 0x3C: op_3C, + 0x3D: op_3D, + 0x3E: op_3E, + 0x3F: op_3F, + 0x40: op_40, + 0x41: op_41, + 0x42: op_42, + 0x43: op_43, + 0x44: op_44, + 0x45: op_45, + 0x46: op_46, + 0x47: op_47, + 0x48: op_48, + 0x49: op_49, + 0x4A: op_4A, + 0x4B: op_4B, + 0x4C: op_4C, + 0x4D: op_4D, + 0x4E: op_4E, + 0x4F: op_4F, + 0x50: op_50, + 0x51: op_51, + 0x52: op_52, + 0x53: op_53, + 0x54: op_54, + 0x55: op_55, + 0x56: op_56, + 0x57: op_57, + 0x58: op_58, + 0x59: op_59, + 0x5A: op_5A, + 0x5B: op_5B, + 0x5C: op_5C, + 0x5D: op_5D, + 0x5E: op_5E, + 0x5F: op_5F, + 0x60: op_60, + 0x61: op_61, + 0x62: op_62, + 0x63: op_63, + 0x64: op_64, + 0x65: op_65, + 0x66: op_66, + 0x67: op_67, + 0x68: op_68, + 0x69: op_69, + 0x6A: op_6A, + 0x6B: op_6B, + 0x6C: op_6C, + 0x6D: op_6D, + 0x6E: op_6E, + 0x6F: op_6F, + 0x70: op_70, + 0x71: op_71, + 0x72: op_72, + 0x73: op_73, + 0x74: op_74, + 0x75: op_75, + 0x76: op_76, + 0x77: op_77, + 0x78: op_78, + 0x79: op_79, + 0x7A: op_7A, + 0x7B: op_7B, + 0x7C: op_7C, + 0x7D: op_7D, + 0x7E: op_7E, + 0x7F: op_7F, + 0x80: op_80, + 0x81: op_81, + 0x82: op_82, + 0x83: op_83, + 0x84: op_84, + 0x85: op_85, + 0x86: op_86, + 0x87: op_87, + 0x88: op_88, + 0x89: op_89, + 0x8A: op_8A, + 0x8B: op_8B, + 0x8C: op_8C, + 0x8D: op_8D, + 0x8E: op_8E, + 0x8F: op_8F, + 0x90: op_90, + 0x91: op_91, + 0x92: op_92, + 0x93: op_93, + 0x94: op_94, + 0x95: op_95, + 0x96: op_96, + 0x97: op_97, + 0x98: op_98, + 0x99: op_99, + 0x9A: op_9A, + 0x9B: op_9B, + 0x9C: op_9C, + 0x9D: op_9D, + 0x9E: op_9E, + 0x9F: op_9F, + 0xA0: op_A0, + 0xA1: op_A1, + 0xA2: op_A2, + 0xA3: op_A3, + 0xA4: op_A4, + 0xA5: op_A5, + 0xA6: op_A6, + 0xA7: op_A7, + 0xA8: op_A8, + 0xA9: op_A9, + 0xAA: op_AA, + 0xAB: op_AB, + 0xAC: op_AC, + 0xAD: op_AD, + 0xAE: op_AE, + 0xAF: op_AF, + 0xB0: op_B0, + 0xB1: op_B1, + 0xB2: op_B2, + 0xB3: op_B3, + 0xB4: op_B4, + 0xB5: op_B5, + 0xB6: op_B6, + 0xB7: op_B7, + 0xB8: op_B8, + 0xB9: op_B9, + 0xBA: op_BA, + 0xBB: op_BB, + 0xBC: op_BC, + 0xBD: op_BD, + 0xBE: op_BE, + 0xBF: op_BF, + 0xC0: op_C0, + 0xC1: op_C1, + 0xC2: op_C2, + 0xC3: op_C3, + 0xC4: op_C4, + 0xC5: op_C5, + 0xC6: op_C6, + 0xC7: op_C7, + 0xC8: op_C8, + 0xC9: op_C9, + 0xCA: op_CA, + 0xCB: op_CB, + 0xCC: op_CC, + 0xCD: op_CD, + 0xCE: op_CE, + 0xCF: op_CF, + 0xD0: op_D0, + 0xD1: op_D1, + 0xD2: op_D2, + 0xD3: op_D3, + 0xD4: op_D4, + 0xD5: op_D5, + 0xD6: op_D6, + 0xD7: op_D7, + 0xD8: op_D8, + 0xD9: op_D9, + 0xDA: op_DA, + 0xDB: op_DB, + 0xDC: op_DC, + 0xDD: op_DD, + 0xDE: op_DE, + 0xDF: op_DF, + 0xE0: op_E0, + 0xE1: op_E1, + 0xE2: op_E2, + 0xE3: op_E3, + 0xE4: op_E4, + 0xE5: op_E5, + 0xE6: op_E6, + 0xE7: op_E7, + 0xE8: op_E8, + 0xE9: op_E9, + 0xEA: op_EA, + 0xEB: op_EB, + 0xEC: op_EC, + 0xED: op_ED, + 0xEE: op_EE, + 0xEF: op_EF, + 0xF0: op_F0, + 0xF1: op_F1, + 0xF2: op_F2, + 0xF3: op_F3, + 0xF4: op_F4, + 0xF5: op_F5, + 0xF6: op_F6, + 0xF7: op_F7, + 0xF8: op_F8, + 0xF9: op_F9, + 0xFA: op_FA, + 0xFB: op_FB, + 0xFC: op_FC, + 0xFD: op_FD, + 0xFE: op_FE, + 0xFF: op_FF, +} diff --git a/pysnes/cpu/wdc65816/opcodes_spec.py b/pysnes/cpu/wdc65816/opcodes_spec.py new file mode 100644 index 0000000..865aa0f --- /dev/null +++ b/pysnes/cpu/wdc65816/opcodes_spec.py @@ -0,0 +1,270 @@ +"""Spec for code-generated opcode handlers (source of truth for gen_opcodes.py). + +SPEC: memory/modify families. (opcode, family, target, index, reg, flag) + target: operation (read/modify) or source register (write); "" => implicit A +MISC_SPEC: everything else. (opcode, func, flag, args) args = verbatim call args. + +Regenerate handlers: uv run scripts/gen_opcodes.py +""" + +SPEC = [ + (0x01, "indexed_indirect_read", "ORA", "", "", "M"), + (0x03, "stack_read", "ORA", "", "", "M"), + (0x04, "direct_modify", "TSB", "", "", "M"), + (0x05, "direct_read", "ORA", "", "", "M"), + (0x06, "direct_modify", "ASL", "", "", "M"), + (0x07, "indirect_long_read", "ORA", "", "", "M"), + (0x09, "immediate_read", "ORA", "", "", "M"), + (0x0A, "implied_modify", "ASL", "", "A", "M"), + (0x0C, "bank_modify", "TSB", "", "", "M"), + (0x0D, "bank_read", "ORA", "", "", "M"), + (0x0E, "bank_modify", "ASL", "", "", "M"), + (0x0F, "long_read", "ORA", "", "", "M"), + (0x11, "indirect_indexed_read", "ORA", "", "", "M"), + (0x12, "indirect_read", "ORA", "", "", "M"), + (0x13, "indirect_stack_read", "ORA", "", "", "M"), + (0x14, "direct_modify", "TRB", "", "", "M"), + (0x15, "direct_read", "ORA", "X", "", "M"), + (0x16, "direct_indexed_modify", "ASL", "", "", "M"), + (0x17, "indirect_long_read", "ORA", "Y", "", "M"), + (0x19, "bank_read", "ORA", "Y", "", "M"), + (0x1A, "implied_modify", "INC", "", "A", "M"), + (0x1C, "bank_modify", "TRB", "", "", "M"), + (0x1D, "bank_read", "ORA", "X", "", "M"), + (0x1E, "bank_indexed_modify", "ASL", "", "", "M"), + (0x1F, "long_read", "ORA", "X", "", "M"), + (0x21, "indexed_indirect_read", "AND", "", "", "M"), + (0x23, "stack_read", "AND", "", "", "M"), + (0x24, "direct_read", "BIT", "", "", "M"), + (0x25, "direct_read", "AND", "", "", "M"), + (0x26, "direct_modify", "ROL", "", "", "M"), + (0x27, "indirect_long_read", "AND", "", "", "M"), + (0x29, "immediate_read", "AND", "", "", "M"), + (0x2A, "implied_modify", "ROL", "", "A", "M"), + (0x2C, "bank_read", "BIT", "", "", "M"), + (0x2D, "bank_read", "AND", "", "", "M"), + (0x2E, "bank_modify", "ROL", "", "", "M"), + (0x2F, "long_read", "AND", "", "", "M"), + (0x31, "indirect_indexed_read", "AND", "", "", "M"), + (0x32, "indirect_read", "AND", "", "", "M"), + (0x33, "indirect_stack_read", "AND", "", "", "M"), + (0x34, "direct_read", "BIT", "X", "", "M"), + (0x35, "direct_read", "AND", "X", "", "M"), + (0x36, "direct_indexed_modify", "ROL", "", "", "M"), + (0x37, "indirect_long_read", "AND", "Y", "", "M"), + (0x39, "bank_read", "AND", "Y", "", "M"), + (0x3A, "implied_modify", "DEC", "", "A", "M"), + (0x3C, "bank_read", "BIT", "X", "", "M"), + (0x3D, "bank_read", "AND", "X", "", "M"), + (0x3E, "bank_indexed_modify", "ROL", "", "", "M"), + (0x3F, "long_read", "AND", "X", "", "M"), + (0x41, "indexed_indirect_read", "EOR", "", "", "M"), + (0x43, "stack_read", "EOR", "", "", "M"), + (0x45, "direct_read", "EOR", "", "", "M"), + (0x46, "direct_modify", "LSR", "", "", "M"), + (0x47, "indirect_long_read", "EOR", "", "", "M"), + (0x49, "immediate_read", "EOR", "", "", "M"), + (0x4A, "implied_modify", "LSR", "", "A", "M"), + (0x4D, "bank_read", "EOR", "", "", "M"), + (0x4E, "bank_modify", "LSR", "", "", "M"), + (0x4F, "long_read", "EOR", "", "", "M"), + (0x51, "indirect_indexed_read", "EOR", "", "", "M"), + (0x52, "indirect_read", "EOR", "", "", "M"), + (0x53, "indirect_stack_read", "EOR", "", "", "M"), + (0x55, "direct_read", "EOR", "X", "", "M"), + (0x56, "direct_indexed_modify", "LSR", "", "", "M"), + (0x57, "indirect_long_read", "EOR", "Y", "", "M"), + (0x59, "bank_read", "EOR", "Y", "", "M"), + (0x5D, "bank_read", "EOR", "X", "", "M"), + (0x5E, "bank_indexed_modify", "LSR", "", "", "M"), + (0x5F, "long_read", "EOR", "X", "", "M"), + (0x61, "indexed_indirect_read", "ADC", "", "", "M"), + (0x63, "stack_read", "ADC", "", "", "M"), + (0x64, "direct_write", "Z", "", "", "M"), + (0x65, "direct_read", "ADC", "", "", "M"), + (0x66, "direct_modify", "ROR", "", "", "M"), + (0x67, "indirect_long_read", "ADC", "", "", "M"), + (0x69, "immediate_read", "ADC", "", "", "M"), + (0x6A, "implied_modify", "ROR", "", "A", "M"), + (0x6D, "bank_read", "ADC", "", "", "M"), + (0x6E, "bank_modify", "ROR", "", "", "M"), + (0x6F, "long_read", "ADC", "", "", "M"), + (0x71, "indirect_indexed_read", "ADC", "", "", "M"), + (0x72, "indirect_read", "ADC", "", "", "M"), + (0x73, "indirect_stack_read", "ADC", "", "", "M"), + (0x74, "direct_write", "Z", "X", "", "M"), + (0x75, "direct_read", "ADC", "X", "", "M"), + (0x76, "direct_indexed_modify", "ROR", "", "", "M"), + (0x77, "indirect_long_read", "ADC", "Y", "", "M"), + (0x79, "bank_read", "ADC", "Y", "", "M"), + (0x7D, "bank_read", "ADC", "X", "", "M"), + (0x7E, "bank_indexed_modify", "ROR", "", "", "M"), + (0x7F, "long_read", "ADC", "X", "", "M"), + (0x81, "indexed_indirect_write", "", "", "", "M"), + (0x83, "stack_write", "", "", "", "M"), + (0x84, "direct_write", "Y", "", "", "X"), + (0x85, "direct_write", "A", "", "", "M"), + (0x86, "direct_write", "X", "", "", "X"), + (0x87, "indirect_long_write", "", "", "", "M"), + (0x88, "implied_modify", "DEC", "", "Y", "X"), + (0x8C, "bank_write", "Y", "", "", "X"), + (0x8D, "bank_write", "A", "", "", "M"), + (0x8E, "bank_write", "X", "", "", "X"), + (0x8F, "long_write", "", "", "", "M"), + (0x91, "indirect_indexed_write", "", "", "", "M"), + (0x92, "indirect_write", "", "", "", "M"), + (0x93, "indirect_stack_write", "", "", "", "M"), + (0x94, "direct_write", "Y", "X", "", "X"), + (0x95, "direct_write", "A", "X", "", "M"), + (0x96, "direct_write", "X", "Y", "", "X"), + (0x97, "indirect_long_write", "", "Y", "", "M"), + (0x99, "bank_write", "A", "Y", "", "M"), + (0x9C, "bank_write", "Z", "", "", "M"), + (0x9D, "bank_write", "A", "X", "", "M"), + (0x9E, "bank_write", "Z", "X", "", "M"), + (0x9F, "long_write", "", "X", "", "M"), + (0xA0, "immediate_read", "LDY", "", "", "X"), + (0xA1, "indexed_indirect_read", "LDA", "", "", "M"), + (0xA2, "immediate_read", "LDX", "", "", "X"), + (0xA3, "stack_read", "LDA", "", "", "M"), + (0xA4, "direct_read", "LDY", "", "", "X"), + (0xA5, "direct_read", "LDA", "", "", "M"), + (0xA6, "direct_read", "LDX", "", "", "X"), + (0xA7, "indirect_long_read", "LDA", "", "", "M"), + (0xA9, "immediate_read", "LDA", "", "", "M"), + (0xAC, "bank_read", "LDY", "", "", "X"), + (0xAD, "bank_read", "LDA", "", "", "M"), + (0xAE, "bank_read", "LDX", "", "", "X"), + (0xAF, "long_read", "LDA", "", "", "M"), + (0xB1, "indirect_indexed_read", "LDA", "", "", "M"), + (0xB2, "indirect_read", "LDA", "", "", "M"), + (0xB3, "indirect_stack_read", "LDA", "", "", "M"), + (0xB4, "direct_read", "LDY", "X", "", "X"), + (0xB5, "direct_read", "LDA", "X", "", "M"), + (0xB6, "direct_read", "LDX", "Y", "", "X"), + (0xB7, "indirect_long_read", "LDA", "Y", "", "M"), + (0xB9, "bank_read", "LDA", "Y", "", "M"), + (0xBC, "bank_read", "LDY", "X", "", "X"), + (0xBD, "bank_read", "LDA", "X", "", "M"), + (0xBE, "bank_read", "LDX", "Y", "", "X"), + (0xBF, "long_read", "LDA", "X", "", "M"), + (0xC0, "immediate_read", "CPY", "", "", "X"), + (0xC1, "indexed_indirect_read", "CMP", "", "", "M"), + (0xC3, "stack_read", "CMP", "", "", "M"), + (0xC4, "direct_read", "CPY", "", "", "X"), + (0xC5, "direct_read", "CMP", "", "", "M"), + (0xC6, "direct_modify", "DEC", "", "", "M"), + (0xC7, "indirect_long_read", "CMP", "", "", "M"), + (0xC8, "implied_modify", "INC", "", "Y", "X"), + (0xC9, "immediate_read", "CMP", "", "", "M"), + (0xCA, "implied_modify", "DEC", "", "X", "X"), + (0xCC, "bank_read", "CPY", "", "", "X"), + (0xCD, "bank_read", "CMP", "", "", "M"), + (0xCE, "bank_modify", "DEC", "", "", "M"), + (0xCF, "long_read", "CMP", "", "", "M"), + (0xD1, "indirect_indexed_read", "CMP", "", "", "M"), + (0xD2, "indirect_read", "CMP", "", "", "M"), + (0xD3, "indirect_stack_read", "CMP", "", "", "M"), + (0xD5, "direct_read", "CMP", "X", "", "M"), + (0xD6, "direct_indexed_modify", "DEC", "", "", "M"), + (0xD7, "indirect_long_read", "CMP", "Y", "", "M"), + (0xD9, "bank_read", "CMP", "Y", "", "M"), + (0xDD, "bank_read", "CMP", "X", "", "M"), + (0xDE, "bank_indexed_modify", "DEC", "", "", "M"), + (0xDF, "long_read", "CMP", "X", "", "M"), + (0xE0, "immediate_read", "CPX", "", "", "X"), + (0xE1, "indexed_indirect_read", "SBC", "", "", "M"), + (0xE3, "stack_read", "SBC", "", "", "M"), + (0xE4, "direct_read", "CPX", "", "", "X"), + (0xE5, "direct_read", "SBC", "", "", "M"), + (0xE6, "direct_modify", "INC", "", "", "M"), + (0xE7, "indirect_long_read", "SBC", "", "", "M"), + (0xE8, "implied_modify", "INC", "", "X", "X"), + (0xE9, "immediate_read", "SBC", "", "", "M"), + (0xEC, "bank_read", "CPX", "", "", "X"), + (0xED, "bank_read", "SBC", "", "", "M"), + (0xEE, "bank_modify", "INC", "", "", "M"), + (0xEF, "long_read", "SBC", "", "", "M"), + (0xF1, "indirect_indexed_read", "SBC", "", "", "M"), + (0xF2, "indirect_read", "SBC", "", "", "M"), + (0xF3, "indirect_stack_read", "SBC", "", "", "M"), + (0xF5, "direct_read", "SBC", "X", "", "M"), + (0xF6, "direct_indexed_modify", "INC", "", "", "M"), + (0xF7, "indirect_long_read", "SBC", "Y", "", "M"), + (0xF9, "bank_read", "SBC", "Y", "", "M"), + (0xFD, "bank_read", "SBC", "X", "", "M"), + (0xFE, "bank_indexed_modify", "INC", "", "", "M"), + (0xFF, "long_read", "SBC", "X", "", "M"), +] + +MISC_SPEC = [ + (0x00, "Interrupt", "", 'lambda cpu: 0xfffe if cpu.EF else 0xffe6'), + (0x02, "Interrupt", "", 'lambda cpu: 0xfff4 if cpu.EF else 0xffe4'), + (0x08, "Push8", "", '"P"'), + (0x0B, "PushD", "", ''), + (0x10, "Branch", "", 'lambda cpu: not cpu.NFlag'), + (0x18, "ClearFlag", "", '"CFlag"'), + (0x1B, "TransferCS", "", ''), + (0x20, "CallShort", "", ''), + (0x22, "CallLong", "", ''), + (0x28, "PullP", "", ''), + (0x2B, "PullD", "", ''), + (0x30, "Branch", "", 'lambda cpu: cpu.NFlag'), + (0x38, "SetFlag", "", '"CFlag"'), + (0x3B, "Transfer16", "", '"S", "A"'), + (0x40, "ReturnInterrupt", "", ''), + (0x42, "Prefix", "", ''), + (0x44, "BlockMove", "X", '-1'), + (0x48, "Push", "M", '"A"'), + (0x4B, "Push8", "", '"PC.b"'), + (0x4C, "JumpShort", "", ''), + (0x50, "Branch", "", 'lambda cpu: not cpu.VFlag'), + (0x54, "BlockMove", "X", '+1'), + (0x58, "ClearFlag", "", '"IFlag"'), + (0x5A, "Push", "X", '"Y"'), + (0x5B, "Transfer16", "", '"A", "D"'), + (0x5C, "JumpLong", "", ''), + (0x60, "ReturnShort", "", ''), + (0x62, "PushEffectiveRelativeAddress", "", ''), + (0x68, "Pull", "M", '"A"'), + (0x6B, "ReturnLong", "", ''), + (0x6C, "JumpIndirect", "", ''), + (0x70, "Branch", "", 'lambda cpu: cpu.VFlag'), + (0x78, "SetFlag", "", '"IFlag"'), + (0x7A, "Pull", "X", '"Y"'), + (0x7B, "Transfer16", "", '"D", "A"'), + (0x7C, "JumpIndexedIndirect", "", ''), + (0x80, "Branch", "", 'lambda _: True'), + (0x82, "BranchLong", "", ''), + (0x89, "BitImmediate", "M", ''), + (0x8A, "Transfer", "M", '"X", "A"'), + (0x8B, "Push8", "", '"DB"'), + (0x90, "Branch", "", 'lambda cpu: not cpu.CFlag'), + (0x98, "Transfer", "M", '"Y", "A"'), + (0x9A, "TransferXS", "", ''), + (0x9B, "Transfer", "X", '"X", "Y"'), + (0xA8, "Transfer", "X", '"A", "Y"'), + (0xAA, "Transfer", "X", '"A", "X"'), + (0xAB, "PullB", "", ''), + (0xB0, "Branch", "", 'lambda cpu: cpu.CFlag'), + (0xB8, "ClearFlag", "", '"VFlag"'), + (0xBA, "TransferSX", "X", ''), + (0xBB, "Transfer", "X", '"Y", "X"'), + (0xC2, "ResetP", "", ''), + (0xCB, "Wait", "", ''), + (0xD0, "Branch", "", 'lambda cpu: not cpu.ZFlag'), + (0xD4, "PushEffectiveIndirectAddress", "", ''), + (0xD8, "ClearFlag", "", '"DFlag"'), + (0xDA, "Push", "X", '"X"'), + (0xDB, "Stop", "", ''), + (0xDC, "JumpIndirectLong", "", ''), + (0xE2, "SetP", "", ''), + (0xEA, "NoOperation", "", ''), + (0xEB, "ExchangeBA", "", ''), + (0xF0, "Branch", "", 'lambda cpu: cpu.ZFlag'), + (0xF4, "PushEffectiveAddress", "", ''), + (0xF8, "SetFlag", "", '"DFlag"'), + (0xFA, "Pull", "X", '"X"'), + (0xFB, "ExchangeCE", "", ''), + (0xFC, "CallIndexedIndirect", "", ''), +] diff --git a/scripts/bench_cpu.py b/scripts/bench_cpu.py new file mode 100644 index 0000000..362f1c5 --- /dev/null +++ b/scripts/bench_cpu.py @@ -0,0 +1,234 @@ +"""Deterministic CPU dispatch micro-benchmark. + +Runs a tight loop of indexed read/write instructions (the addressing modes most +exercised in-game) through the real fetch_and_execute path, so dispatch-layer +changes can be measured without scene/JIT/OS noise. +""" +import sys, time +from pathlib import Path +sys.path.insert(0, str(Path(__file__).parent.parent)) + +from types import SimpleNamespace +from pysnes.scheduler import Scheduler +from pysnes.bus import Bus +from pysnes.cpu import Cpu +from pysnes.apu import Apu +from pysnes.ppu import Ppu +from pysnes.controller import Controller +from pysnes.rom import HardwareVectors, InterruptVectors, MappingMode + +# Program at LoROM bank0 $8000 (rom offset 0): a loop of indexed mem ops. +# BD 00 10 LDA $1000,X (BankRead, i=X) +# 9D 00 10 STA $1000,X (BankWrite, i=X) +# B5 20 LDA $20,X (DirectRead, i=X) +# 95 20 STA $20,X (DirectWrite, i=X) +# 80 F4 BRA -12 (loop to start) +PROGRAM = bytes([0xBD, 0x00, 0x10, 0x9D, 0x00, 0x10, 0xB5, 0x20, 0x95, 0x20, 0x80, 0xF4]) + + +class StubRom: + def __init__(self, size=512 * 1024): + self.rom = bytearray(size) + self.rom[0:len(PROGRAM)] = PROGRAM + self.snes_header = SimpleNamespace(mapping_mode=MappingMode.LOROM) + self.hardware_vectors = HardwareVectors( + native=InterruptVectors(cop=0x8000, brk=0x8000, abort=0x8000, nmi=0x8000, reset=0x8000, irq=0x8000), + emulation=InterruptVectors(cop=0x8000, brk=0x8000, abort=0x8000, nmi=0x8000, reset=0x8000, irq=0x8000), + ) + + def __getitem__(self, addr): + return self.rom[addr] if 0 <= addr < len(self.rom) else 0 + + def read(self, addr): + return self.rom[addr] if 0 <= addr < len(self.rom) else 0 + + +def make_cpu(): + rom = StubRom() + sched = Scheduler() + cpu = Cpu(rom.hardware_vectors) + bus = Bus(rom, cpu, Apu(), Ppu(), [Controller(), Controller(disabled=True)], sched) + cpu.attach(bus) + cpu.PC.d = 0x008000 + cpu.EF = False # native mode + cpu.MFlag = False # 16-bit A + cpu.XFlag = False # 16-bit X/Y + cpu.DB.value = 0x00 + cpu.D.value = 0x0000 + cpu.X.value = 0x0000 + return cpu + + +def install_fused(cpu): + """Replace the 4 benchmark opcodes with fully-fused, monomorphic handlers + (no .MF wrapper, no string arg, no nargs branch) to measure the theoretical + dispatch ceiling. Logic mirrors BankRead/DirectRead/BankWrite/DirectWrite + with index=X exactly (same idle cycles).""" + from pysnes.cpu.cpu import InstructionSlot + from pysnes.cpu.wdc65816 import opcodes as OP + LDA = OP.LDA + + def lda_abs_x(cpu): + cpu.V.l = cpu.fetch(); cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.X.w) + if cpu.MFlag: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1) + LDA(cpu, False, cpu.W.w) + + def sta_abs_x(cpu): + cpu.V.l = cpu.fetch(); cpu.V.h = cpu.fetch(); cpu.idle() + if cpu.MFlag: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.A.l) + else: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.A.l) + cpu.writeBank(cpu.V.w + cpu.X.w + 1, cpu.A.h) + + def lda_dp_x(cpu): + cpu.U.l = cpu.fetch(); cpu.idle2(); cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + LDA(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1) + LDA(cpu, False, cpu.W.w) + + def sta_dp_x(cpu): + cpu.U.l = cpu.fetch(); cpu.idle2(); cpu.idle() + if cpu.MFlag: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.A.l) + else: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.A.l) + cpu.writeDirect(cpu.U.l + cpu.X.w + 1, cpu.A.h) + + cpu.instructions[0xBD] = InstructionSlot(lda_abs_x, nargs=0) + cpu.instructions[0x9D] = InstructionSlot(sta_abs_x, nargs=0) + cpu.instructions[0xB5] = InstructionSlot(lda_dp_x, nargs=0) + cpu.instructions[0x95] = InstructionSlot(sta_dp_x, nargs=0) + + +def install_closure(cpu): + """Clean closure-factory version: op/index/flag captured as freevars, with + branches the JIT may or may not fold. This is the readable implementation + candidate — compare it to the literal 'fused' ceiling.""" + from pysnes.cpu.cpu import InstructionSlot + from pysnes.cpu.wdc65816 import opcodes as OP + LDA = OP.LDA + + # Per-(mode,index) factory: ONLY the operation is a freevar; index register + # and memory accessor are baked as literals (monomorphic body, no branches + # on captured constants). This is the clean factory we'd ship if it's fast. + def bank_read_x(op, xflag=False): + def execute(cpu): + cpu.V.l = cpu.fetch(); cpu.V.h = cpu.fetch() + cpu.idle4(cpu.V.w, cpu.V.w + cpu.X.w) + if (cpu.XFlag if xflag else cpu.MFlag): + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0); op(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readBank(cpu.V.w + cpu.X.w + 0) + cpu.W.h = cpu.readBank(cpu.V.w + cpu.X.w + 1); op(cpu, False, cpu.W.w) + return execute + + def direct_read_x(op): + def execute(cpu): + cpu.U.l = cpu.fetch(); cpu.idle2(); cpu.idle() + if cpu.MFlag: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0); op(cpu, True, cpu.W.l) + else: + cpu.W.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0) + cpu.W.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1); op(cpu, False, cpu.W.w) + return execute + + def sta_abs_x(): + def execute(cpu): + cpu.V.l = cpu.fetch(); cpu.V.h = cpu.fetch(); cpu.idle() + if cpu.MFlag: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.A.l) + else: + cpu.writeBank(cpu.V.w + cpu.X.w + 0, cpu.A.l) + cpu.writeBank(cpu.V.w + cpu.X.w + 1, cpu.A.h) + return execute + + def sta_dp_x(): + def execute(cpu): + cpu.U.l = cpu.fetch(); cpu.idle2(); cpu.idle() + if cpu.MFlag: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.A.l) + else: + cpu.writeDirect(cpu.U.l + cpu.X.w + 0, cpu.A.l) + cpu.writeDirect(cpu.U.l + cpu.X.w + 1, cpu.A.h) + return execute + + cpu.instructions[0xBD] = InstructionSlot(bank_read_x(LDA), nargs=0) + cpu.instructions[0x9D] = InstructionSlot(sta_abs_x(), nargs=0) + cpu.instructions[0xB5] = InstructionSlot(direct_read_x(LDA), nargs=0) + cpu.instructions[0x95] = InstructionSlot(sta_dp_x(), nargs=0) + + +def install_writeclosure(cpu): + """DRY write factory: source register name as a freevar (resolved per call). + Measures whether the compact version is fast enough vs literal variants.""" + from pysnes.cpu.cpu import InstructionSlot + + def bank_write(src, index="", xflag=False): + def execute(cpu): + cpu.V.l = cpu.fetch(); cpu.V.h = cpu.fetch() + if index: + cpu.idle() + iw = cpu.X.w if index == "X" else (cpu.Y.w if index == "Y" else 0) + S = cpu.A if src == "A" else (cpu.X if src == "X" else (cpu.Y if src == "Y" else cpu.Z)) + if (cpu.XFlag if xflag else cpu.MFlag): + cpu.writeBank(cpu.V.w + iw + 0, S.l) + else: + cpu.writeBank(cpu.V.w + iw + 0, S.l) + cpu.writeBank(cpu.V.w + iw + 1, S.h) + return execute + + def direct_write(src, index="", xflag=False): + def execute(cpu): + cpu.U.l = cpu.fetch(); cpu.idle2() + if index: + cpu.idle() + iw = cpu.X.w if index == "X" else (cpu.Y.w if index == "Y" else 0) + S = cpu.A if src == "A" else (cpu.X if src == "X" else (cpu.Y if src == "Y" else cpu.Z)) + if (cpu.XFlag if xflag else cpu.MFlag): + cpu.writeDirect(cpu.U.l + iw + 0, S.l) + else: + cpu.writeDirect(cpu.U.l + iw + 0, S.l) + cpu.writeDirect(cpu.U.l + iw + 1, S.h) + return execute + + cpu.instructions[0x9D] = InstructionSlot(bank_write("A", "X"), nargs=0) + cpu.instructions[0x95] = InstructionSlot(direct_write("A", "X"), nargs=0) + + +def run(cpu, n): + fae = cpu.fetch_and_execute + for _ in range(n): + fae() + + +def main(): + n = next((int(a) for a in sys.argv[1:] if a.isdigit()), 400_000) + cpu = make_cpu() + if "--fused" in sys.argv: + install_fused(cpu) + elif "--closure" in sys.argv: + install_closure(cpu) + elif "--writeclosure" in sys.argv: + install_writeclosure(cpu) + run(cpu, 100_000) # warmup + best = 1e9 + for _ in range(5): + t0 = time.perf_counter() + run(cpu, n) + best = min(best, (time.perf_counter() - t0) / n * 1e9) + print(f"PC=0x{cpu.PC.d:06X} (looping ok) -> {best:.1f} ns/instruction (best of 5)") + + +if __name__ == "__main__": + main() diff --git a/scripts/gen_opcodes.py b/scripts/gen_opcodes.py new file mode 100644 index 0000000..2847da9 --- /dev/null +++ b/scripts/gen_opcodes.py @@ -0,0 +1,327 @@ +"""Generate literal opcode handlers from opcodes_spec.py -> opcodes_generated.py. + +Reads the compact spec (SPEC for memory/modify families, MISC_SPEC for the +irregular ops) and emits one straight-line handler per opcode. For the +memory/modify families the index register, width flag, and operation/source are +baked in as literals, so PyPy folds them per-opcode trace (the decorator+string +table dispatch could not — ~2x faster on hot reads/writes; see bench_cpu.py). +The irregular ops are emitted as thin handlers that delegate to the tested +addressing functions, with lambda args hoisted to module level. + +Build tool: edit opcodes_spec.py, rerun, commit the regenerated output. + + uv run scripts/gen_opcodes.py +""" +import sys +from pathlib import Path + +ROOT = Path(__file__).parent.parent +sys.path.insert(0, str(ROOT)) + +GEN_OUT = ROOT / "pysnes" / "cpu" / "wdc65816" / "opcodes_generated.py" + +# AM addressing-mode name -> (family, kind). kind: read/write/modify/implied. +FAMILY = { + "ImmediateRead": ("immediate_read", "read"), + "BankRead": ("bank_read", "read"), + "DirectRead": ("direct_read", "read"), + "LongRead": ("long_read", "read"), + "IndirectRead": ("indirect_read", "read"), + "IndexedIndirectRead": ("indexed_indirect_read", "read"), + "IndirectIndexedRead": ("indirect_indexed_read", "read"), + "IndirectLongRead": ("indirect_long_read", "read"), + "StackRead": ("stack_read", "read"), + "IndirectStackRead": ("indirect_stack_read", "read"), + "BankWrite": ("bank_write", "write"), + "DirectWrite": ("direct_write", "write"), + "LongWrite": ("long_write", "write"), + "IndirectWrite": ("indirect_write", "write"), + "IndexedIndirectWrite": ("indexed_indirect_write", "write"), + "IndirectIndexedWrite": ("indirect_indexed_write", "write"), + "IndirectLongWrite": ("indirect_long_write", "write"), + "StackWrite": ("stack_write", "write"), + "IndirectStackWrite": ("indirect_stack_write", "write"), + "BankModify": ("bank_modify", "modify"), + "BankIndexedModify": ("bank_indexed_modify", "modify"), + "DirectModify": ("direct_modify", "modify"), + "DirectIndexedModify": ("direct_indexed_modify", "modify"), + "ImpliedModify": ("implied_modify", "implied"), +} + +# --- code templates ------------------------------------------------------- +def _flag(f): + return "cpu.MFlag" if f == "M" else "cpu.XFlag" + + +def _idx(index): + return {"": "", "X": " + cpu.X.w", "Y": " + cpu.Y.w"}[index] + + +def body_read(family, op, index, flag): + iw = _idx(index) + f = _flag(flag) + L = [] + if family == "immediate_read": + return [f" if {f}:", + " cpu.W.l = cpu.fetch()", + f" {op}(cpu, True, cpu.W.l)", + " else:", + " cpu.W.l = cpu.fetch()", + " cpu.W.h = cpu.fetch()", + f" {op}(cpu, False, cpu.W.w)"] + if family == "bank_read": + L += [" cpu.V.l = cpu.fetch()", " cpu.V.h = cpu.fetch()"] + if index: + L.append(f" cpu.idle4(cpu.V.w, cpu.V.w{iw})") + return L + _read_tail("cpu.readBank", f"cpu.V.w{iw}", op, f) + if family == "direct_read": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle2()"] + if index: + L.append(" cpu.idle()") + return L + _read_tail("cpu.readDirect", f"cpu.U.l{iw}", op, f) + if family == "long_read": + L += [" cpu.V.l = cpu.fetch()", " cpu.V.h = cpu.fetch()", " cpu.V.b = cpu.fetch()"] + return L + _read_tail("cpu.readLong", f"cpu.V.d{iw}", op, f) + if family == "indirect_read": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle2()", + " cpu.V.l = cpu.readDirect(cpu.U.l + 0)", + " cpu.V.h = cpu.readDirect(cpu.U.l + 1)"] + return L + _read_tail("cpu.readBank", "cpu.V.w", op, f) + if family == "indexed_indirect_read": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle2()", " cpu.idle()", + " cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0)", + " cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1)"] + return L + _read_tail("cpu.readBank", "cpu.V.w", op, f) + if family == "indirect_indexed_read": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle2()", + " cpu.V.l = cpu.readDirect(cpu.U.l + 0)", + " cpu.V.h = cpu.readDirect(cpu.U.l + 1)", + " cpu.idle4(cpu.V.w, cpu.V.w + cpu.Y.w)"] + return L + _read_tail("cpu.readBank", "cpu.V.w + cpu.Y.w", op, f) + if family == "indirect_long_read": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle2()", + " cpu.V.l = cpu.readDirectN(cpu.U.l + 0)", + " cpu.V.h = cpu.readDirectN(cpu.U.l + 1)", + " cpu.V.b = cpu.readDirectN(cpu.U.l + 2)"] + return L + _read_tail("cpu.readLong", f"cpu.V.d{iw}", op, f) + if family == "stack_read": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle()"] + return L + _read_tail("cpu.readStack", "cpu.U.l", op, f) + if family == "indirect_stack_read": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle()", + " cpu.V.l = cpu.readStack(cpu.U.l + 0)", + " cpu.V.h = cpu.readStack(cpu.U.l + 1)", " cpu.idle()"] + return L + _read_tail("cpu.readBank", "cpu.V.w + cpu.Y.w", op, f) + raise ValueError(family) + + +def _read_tail(rd, addr, op, f): + return [f" if {f}:", + f" cpu.W.l = {rd}({addr} + 0)", + f" {op}(cpu, True, cpu.W.l)", + " else:", + f" cpu.W.l = {rd}({addr} + 0)", + f" cpu.W.h = {rd}({addr} + 1)", + f" {op}(cpu, False, cpu.W.w)"] + + +def body_write(family, src, index, flag): + iw = _idx(index) + f = _flag(flag) + s = f"cpu.{src}" if src else "cpu.A" + L = [] + if family == "bank_write": + L += [" cpu.V.l = cpu.fetch()", " cpu.V.h = cpu.fetch()"] + if index: + L.append(" cpu.idle()") + return L + _write_tail("cpu.writeBank", f"cpu.V.w{iw}", s, f) + if family == "direct_write": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle2()"] + if index: + L.append(" cpu.idle()") + return L + _write_tail("cpu.writeDirect", f"cpu.U.l{iw}", s, f) + if family == "long_write": + L += [" cpu.V.l = cpu.fetch()", " cpu.V.h = cpu.fetch()", " cpu.V.b = cpu.fetch()"] + return L + _write_tail("cpu.writeLong", f"cpu.V.d{iw}", s, f) + if family == "indirect_write": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle2()", + " cpu.V.l = cpu.readDirect(cpu.U.l + 0)", + " cpu.V.h = cpu.readDirect(cpu.U.l + 1)"] + return L + _write_tail("cpu.writeBank", "cpu.V.w", s, f) + if family == "indexed_indirect_write": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle2()", " cpu.idle()", + " cpu.V.l = cpu.readDirect(cpu.U.l + cpu.X.w + 0)", + " cpu.V.h = cpu.readDirect(cpu.U.l + cpu.X.w + 1)"] + return L + _write_tail("cpu.writeBank", "cpu.V.w", s, f) + if family == "indirect_indexed_write": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle2()", + " cpu.V.l = cpu.readDirect(cpu.U.l + 0)", + " cpu.V.h = cpu.readDirect(cpu.U.l + 1)", " cpu.idle()"] + return L + _write_tail("cpu.writeBank", "cpu.V.w + cpu.Y.w", s, f) + if family == "indirect_long_write": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle2()", + " cpu.V.l = cpu.readDirectN(cpu.U.l + 0)", + " cpu.V.h = cpu.readDirectN(cpu.U.l + 1)", + " cpu.V.b = cpu.readDirectN(cpu.U.l + 2)"] + return L + _write_tail("cpu.writeLong", f"cpu.V.d{iw}", s, f) + if family == "stack_write": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle()"] + return L + _write_tail("cpu.writeStack", "cpu.U.l", s, f) + if family == "indirect_stack_write": + L += [" cpu.U.l = cpu.fetch()", " cpu.idle()", + " cpu.V.l = cpu.readStack(cpu.U.l + 0)", + " cpu.V.h = cpu.readStack(cpu.U.l + 1)", " cpu.idle()"] + return L + _write_tail("cpu.writeBank", "cpu.V.w + cpu.Y.w", s, f) + raise ValueError(family) + + +def _write_tail(wr, addr, s, f): + return [f" if {f}:", + f" {wr}({addr} + 0, {s}.l)", + " else:", + f" {wr}({addr} + 0, {s}.l)", + f" {wr}({addr} + 1, {s}.h)"] + + +def body_modify(family, op, index, flag): + """RMW families. EF=1 replays a dummy write-back in place of the native idle.""" + f = _flag(flag) + if family == "implied_modify": + # `index` carries the target register here. + reg = f"cpu.{index}" + return [f" cpu.idleIRQ()", + f" if {f}:", + f" {reg}.l = {op}(cpu, True, {reg}.l)", + " else:", + f" {reg}.w = {op}(cpu, False, {reg}.w)"] + if family in ("bank_modify", "bank_indexed_modify"): + ix = " + cpu.X.w" if family == "bank_indexed_modify" else "" + addr = f"cpu.V.w{ix}" + L = [" cpu.V.l = cpu.fetch()", " cpu.V.h = cpu.fetch()"] + if family == "bank_indexed_modify": + L.append(" cpu.idle()") + L += [f" if {f}:", + f" cpu.W.l = cpu.readBank({addr} + 0)", + " if cpu.EF:", + f" cpu.writeBank({addr} + 0, cpu.W.l)", + " else:", + " cpu.idle()", + f" cpu.W.l = {op}(cpu, True, cpu.W.l)", + f" cpu.writeBank({addr} + 0, cpu.W.l)", + " else:", + f" cpu.W.l = cpu.readBank({addr} + 0)", + f" cpu.W.h = cpu.readBank({addr} + 1)", + " cpu.idle()", + f" cpu.W.w = {op}(cpu, False, cpu.W.w)", + f" cpu.writeBank({addr} + 1, cpu.W.h)", + f" cpu.writeBank({addr} + 0, cpu.W.l)"] + return L + if family in ("direct_modify", "direct_indexed_modify"): + ix = " + cpu.X.w" if family == "direct_indexed_modify" else "" + addr = f"cpu.U.l{ix}" + L = [" cpu.U.l = cpu.fetch()", " cpu.idle2()"] + if family == "direct_indexed_modify": + L.append(" cpu.idle()") + L += [f" if {f}:", + f" cpu.W.l = cpu.readDirect({addr} + 0)", + " if cpu.EF:", + f" cpu.writeDirect({addr} + 0, cpu.W.l)", + " else:", + " cpu.idle()", + f" cpu.W.l = {op}(cpu, True, cpu.W.l)", + f" cpu.writeDirect({addr} + 0, cpu.W.l)", + " else:", + f" cpu.W.l = cpu.readDirect({addr} + 0)", + f" cpu.W.h = cpu.readDirect({addr} + 1)", + " cpu.idle()", + f" cpu.W.w = {op}(cpu, False, cpu.W.w)", + f" cpu.writeDirect({addr} + 1, cpu.W.h)", + f" cpu.writeDirect({addr} + 0, cpu.W.l)"] + return L + raise ValueError(family) + + +def gen_body(family, kind, target, index, reg, flag): + if kind == "read": + return body_read(family, target, index, flag) + if kind == "write": + return body_write(family, target, index, flag) + if kind == "modify": + return body_modify(family, target, index, flag) + if kind == "implied": + return body_modify(family, target, reg, flag) # reg passed as index slot + raise ValueError(kind) + + +def misc_body(func, flag, args): + """Delegating handler for an irregular op: bake args, call the tested fn. + + Returns (preamble_lines, body_line). Lambda args are hoisted to a module + level _arg_NN so they're built once, not per call. + """ + call = ["cpu"] + if flag: + call.append("cpu.MFlag" if flag == "M" else "cpu.XFlag") + if args: + call.append(args) + return [f" AM.{func}({', '.join(call)})"] + + +def write_generated(spec, misc): + # Only read/modify/implied families call an operation (OP.xxx); writes don't. + ops = sorted({tgt for op, fam, tgt, idx, reg, fl in spec + if FAMILY_KIND(fam) in ("read", "modify", "implied") and tgt}) + out = [ + "# AUTO-GENERATED by scripts/gen_opcodes.py from opcodes_spec.py.", + "# Do not edit by hand — change the spec/generator and regenerate.", + "", + "from . import addressing_modes as AM", + "from .opcodes import " + ", ".join(sorted(ops)), + "", + "", + ] + names = {} + # Memory / modify families: inlined literal handlers. + for op, fam, tgt, idx, reg, flag in spec: + kind = FAMILY_KIND(fam) + name = f"op_{op:02X}" + names[op] = name + label = f"{fam} {tgt}{(' ,' + idx) if idx else ''}{(' ' + reg) if reg else ''} ({flag})" + out.append(f"def {name}(cpu): # {label}") + out += gen_body(fam, kind, tgt, idx, reg, flag) + out += ["", ""] + # Irregular ops: delegating handlers (args baked; lambdas hoisted). + for op, func, flag, args in misc: + name = f"op_{op:02X}" + names[op] = name + if "lambda" in args: + argname = f"_arg_{op:02X}" + out.append(f"{argname} = {args}") + args = argname + out.append(f"def {name}(cpu): # {func}") + out += misc_body(func, flag, args) + out += ["", ""] + out.append("HANDLERS = {") + for op in sorted(names): + out.append(f" 0x{op:02X}: {names[op]},") + out.append("}") + GEN_OUT.write_text("\n".join(out) + "\n") + return len(names) + + +def FAMILY_KIND(family): + for fam, kind in FAMILY.values(): + if fam == family: + return kind + raise ValueError(family) + + +def main(): + from pysnes.cpu.wdc65816.opcodes_spec import SPEC, MISC_SPEC + n = write_generated(SPEC, MISC_SPEC) + print(f"read {len(SPEC)} + {len(MISC_SPEC)} spec rows; " + f"wrote {GEN_OUT.relative_to(ROOT)} ({n} handlers)") + + +if __name__ == "__main__": + main()