;
;	fram65ca.s
;
;	P/ECE MOS6502 Emulator (高速版)
;
;	CLiP - Common Library for P/ECE
;	Copyright (C) 2001-2005 Naoyuki Sawa
;
;	* Fri Jan 28 03:55:00 JST 2005 Naoyuki Sawa
;	- 作成開始。
;	* Mon Mar 07 02:08:00 JST 2005 Naoyuki Sawa
;	- WAI=1の状態でm6502cpu_runが呼ばれたときに、m6502cpu.cycle=0で終了するよう修正。
;	  これまでは、m6502cpu.cycleを変化せずに終了してしまっていたために、
;	  Cycleの端数を次回のm6502cpu_runへ繰り延べるような処理に不具合が生じていました。
;	* Wed Mar 17 06:43:00 JST 2005 Naoyuki Sawa
;	- CMP,CPX,CPY命令ルーチンの最後の"ld.ub %NZ,%NZ"を遅延スロットへ移動しました。
;	  (ld.ubが遅延可能な命令であることが判明したため)
;	* Thu Mar 17 18:45:00 JST 2005 Naoyuki Sawa
;	- m6502cpu_runにトレースデバッグ用ブロックを追加しました。
;	  トレースデバッグを行うときは、M6502CPU_RUN_TRACEシンボルを定義してください。
;	* Fri Mar 18 07:27:00 JST 2005 Naoyuki Sawa
;	- AddressMode関数にて、ZeroPage内のWraparoundに対応しました。
;	- AddressMode関数にて、    64KB内のWraparoundに対応しました。
;	* Wed Mar 23 06:04:00 JST 2005 Naoyuki Sawa
;	- m6502cpu_pack中のext命令を、pp33のビットフィールド取得演算子を使って、判り易く書き直しました。
;	  ソースコードが判り易くなっただけで、生成バイナリには変化ありません。
;	  展開結果が変更前と同じであることを、変更前と変更後のfram65ca.msを比較して確認しました。
;	* Wed Apr 13 06:48:00 JST 2005 Naoyuki Sawa
;	- CMP Immediate のサイクル数を [誤]3cycle→[正]2cycle に修正しました。
;
#include "clip65ca.h"

	.code
	.align 1

;****************************************************************************
;	
;****************************************************************************

; 実行コンテキストを取り出します。
;
; [in]
;	ありません。
;
; [out]
;	規定のレジスタを設定します。
;
; [use]
;	規定のレジスタを設定すること以外は、全レジスタを保存します。
;
; [note]
;	* 実行コンテキスト外からのみ呼び出し可能です。
;	  このルーチンを呼び出すと、実行コンテキスト内に入ります。
;
	.global	m6502cpu_enter
m6502cpu_enter:
	xld.w	%TBL  , m6502tbl+3		; 書き戻し不要
	xld.w	%CPU  , m6502cpu		; 書き戻し不要
	xld.ub	%A    , [%CPU+CA+0   ]
	xld.ub	%X    , [%CPU+_X_    ]
	xld.ub	%Y    , [%CPU+_Y_    ]
	xld.uh	%NZ   , [%CPU+_NZ_   ]
	xld.w	%PC   , [%CPU+_PC_   ]
	xld.ub	%SP   , [%CPU+_SP_   ]
	xld.w	%CYCLE, [%CPU+_CYCLE_]
	ret

; 実行コンテキストを書き戻します。
;
; [in]
;	規定のレジスタが設定されていること。
;
; [out]
;	ありません。
;
; [use]
;	全レジスタを保存します。
;
; [note]
;	* 実行コンテキスト内からのみ呼び出し可能です。
;	  このルーチンを呼び出すと、実行コンテキストを抜けます。
;
	.global	m6502cpu_leave
m6502cpu_leave:
	xld.b	[%CPU+CA+0   ], %A
	xld.b	[%CPU+_X_    ], %X
	xld.b	[%CPU+_Y_    ], %Y
	xld.h	[%CPU+_NZ_   ], %NZ
	xld.w	[%CPU+_PC_   ], %PC
	xld.b	[%CPU+_SP_   ], %SP
	xld.w	[%CPU+_CYCLE_], %CYCLE
	ret

;****************************************************************************
;	
;****************************************************************************

; 単純なメモリ読み出しルーチンです。
;
; [in]
;	%addr		読み出すアドレス。
;
; [out]
;	%data		読み出したデータ。
;
; [use]
;	戻り値以外は、全レジスタを保存します。
;
; [note]
;	* 実行コンテキスト内からのみ呼び出し可能です。
;	  実行コンテキスト外から呼び出すことはできません。
;
;	* m6502cpu_reset()にて、メモリ読み出しルーチンが指定されなかった場合は、
;	  このルーチンを利用します。
;
	.global	m6502mem_read
m6502mem_read:
	ext	m6502mem@ah
	ext	m6502mem@al
	ld.ub	%data, [%addr]
	ret

; 単純なメモリ書き込みルーチンです。
;
; [in]
;	%addr		読み出すアドレス。
;	%data		書き込むデータ。
;
; [out]
;	ありません。
;
; [use]
;	全レジスタを保存します。
;
; [note]
;	* 実行コンテキスト内からのみ呼び出し可能です。
;	  実行コンテキスト外から呼び出すことはできません。
;
;	* m6502cpu_reset()にて、メモリ書き込みルーチンが指定されなかった場合は、
;	  このルーチンを利用します。
;
	.global	m6502mem_write
m6502mem_write:
	ext	m6502mem@ah
	ext	m6502mem@al
	ld.b	[%addr], %data
	ret

;****************************************************************************
;	
;****************************************************************************

; PSRをパックします。
;
; [in,out]
;	m6502cpu.ca --------+
;	m6502cpu.bdi --++++ |
;	m6502cpu.v ---+|||| |
;	              ||||| |
;	             NV1BDIZC --> %data
;	              |     |
;	%NZ ----------+-----+
;
; [use]
;	%dataに戻り値を設定すること以外は、全レジスタを保存します。
;
; [note]
;	* 実行コンテキスト内からのみ呼び出し可能です。
;	  実行コンテキスト外から呼び出すことはできません。
;
	.global	m6502cpu_pack
m6502cpu_pack:
	xld.ub	%data, [%CPU+BDI]		; %data |= 001BDI00
	;
	xbtst	[%CPU+V], 7			; %data |= 0V000000
	jreq	3
	;ext	1<<(6-6)			; (skip?)
	;or	%data, 0			; (skip?)
	;↓* Wed Mar 23 06:04:00 JST 2005 Naoyuki Sawa
	;↓- m6502cpu_pack中のext命令を、pp33のビットフィールド取得演算子を使って、判り易く書き直しました。
	;↓  ソースコードが判り易くなっただけで、生成バイナリには変化ありません。
	;↓  展開結果が変更前と同じであることを、変更前と変更後のfram65ca.msを比較して確認しました。
	ext	       (1<<6)^M			; (skip?)
	or	%data, (1<<6)^L			; (skip?)
	;
	xbtst	[%CPU+CA+1], 0			; %data |= 0000000C
	jreq	2
	or	%data, 1<<0			; (skip?)
	;
	xand	%r9, %NZ, 0x8080		; %data |= N0000000
	jreq	3
	;ext	1<<(7-6)			; (skip?)
	;or	%data, 0			; (skip?)
	;↓* Wed Mar 23 06:04:00 JST 2005 Naoyuki Sawa
	;↓- m6502cpu_pack中のext命令を、pp33のビットフィールド取得演算子を使って、判り易く書き直しました。
	;↓  ソースコードが判り易くなっただけで、生成バイナリには変化ありません。
	;↓  展開結果が変更前と同じであることを、変更前と変更後のfram65ca.msを比較して確認しました。
	ext	       (1<<7)^M			; (skip?)
	or	%data, (1<<7)^L			; (skip?)
	;
	xand	%r9, %NZ, 0xff			; %data |= 000000Z0
	jrne	2
	or	%data, 1<<1			; (skip?)
	;
	ret

; PSRをアンパックします。
;
; [in,out]
;	          +--------> m6502cpu.v
;	          |++++----> m6502cpu.bdi
;	          ||||| +--> m6502cpu.ca
;	          |1||| |
;	data --> NV-BDIZC
;	         |     |
;	         +-----+---> %NZ
;
; [use]
;	%NZに戻り値を設定すること以外は、全レジスタを保存します。
;
; [note]
;	* 実行コンテキスト内からのみ呼び出し可能です。
;	  実行コンテキスト外から呼び出すことはできません。
;
	.global	m6502cpu_unpack
m6502cpu_unpack:
	xand	%r9, %data, 0x1c		; BDI = 001BDI00
	xadd	%r9, %r9, 1<<5			;         +------ 必ず1に!
	xld.b	[%CPU+BDI], %r9
	;
	xand	%r9, %data, 1<<6		; V   = V0000000
	xsll	%r9, 1
	xld.b	[%CPU+V], %r9
	;
	xand	%r9, %data, 1<<0		; C   = 0000000C
	xld.b	[%CPU+CA+1], %r9
	;
	xand	%NZ, %data, 1<<7		; %NZ = N0000000 00000000
	xsll	%NZ, 8
	;
	xand	%r9, %data, 1<<1		; %NZ = N0000000 00000010 (Z=0)
	xxor	%r9, %r9,   1<<1		;       N0000000 00000000 (Z=1)
	ret.d
	or	%NZ, %r9			; *delay*

;****************************************************************************
;	
;****************************************************************************

; * スタック領域($100-$1FF)はすべてメインメモリと仮定して、高速化してあります。
;   Push/PullでI/Oアクセスを行うようなプログラムは、正しく動作しません。

; * スタック領域内のWraparoundに依存するプログラムは無いと仮定して、高速化してあります。
;   もしもスタック領域内のWraparoundに依存するプログラムがあったならば、変更が必要です。
;   ↓(2005/03/12追記)
;   SPのWraparoundに対応しました。
;   ファミコン用ゲームでは、SPのWraparoundに依存するソフトはほとんどありませんが、
;   ATARI VCS用ゲームの多くが、初期化時にSPのWraparoundに依存しているため、必要です。

; 1バイト値をスタックに積みます。
;
; [in]
;	%data[7:0]	スタックに積む値。
;			%data[31:8]は不定で構いません。
;
; [use]
;	%SPが適切に変化すること以外は、全レジスタを保存します。
;
; [note]
;	* 実行コンテキスト内からのみ呼び出し可能です。
;	  実行コンテキスト外から呼び出すことはできません。
;
;	* PCをスタックに積む手順は、次のようになります。
;
;	m6502cpu_CALL:
;		ld.w	%t0, [%ptbl]+		; %t0 = AddressMode
;		call	%t0			; %addr = AddressMode()
;		;
;		ext	m6502mem+1@ah		; %data = PC-1 (仕様)
;		ext	m6502mem+1@al
;		sub	%data, %PC
;		xcall.d	m6502cpu_push		; Push HI(PC-1)
;		rr	%data, 8		; *delay*
;		xcall.d	m6502cpu_push		; Push LO(PC-1)
;		rl	%data, 8		; *delay*
;		;
;		ext	m6502mem@ah		; %PC = &mem[addr]
;		ext	m6502mem@al
;		add	%PC, %addr
;		ret
;
	.global	m6502cpu_push
m6502cpu_push:
	ext	m6502mem+0x100@ah		; %r9 = &mem[$100|SP]
	ext	m6502mem+0x100@al
	add	%r9, %SP
	ld.b	[%r9], %data			; mem[$100|SP] = data
	xsub	%SP, %SP, 1			; %SP = SP-1
	ret.d
	ld.ub	%SP, %SP			; Wraparound *delay*

; 1バイト値をスタックから取り出します。
;
; [out]
;	%data[7:0]	スタックから取り出した値。
;			%data[31:8]は必ず0になります。
;
; [use]
;	%SPが適切に変化すること以外は、全レジスタを保存します。
;
; [note]
;	* 実行コンテキスト内からのみ呼び出し可能です。
;	  実行コンテキスト外から呼び出すことはできません。
;
;	* PCをスタックから取り出す手順は、次のようになります。
;
;	m6502cpu_RTS:
;		xcall	m6502cpu_pull		; Pull LO(PC-1)
;		xcall.d	m6502cpu_pull		; Pull HI(PC-1)
;		ld.w	%PC, %data		; *delay*
;		xsll	%data, 8		; %PC = PC-1 (仕様)
;		or	%PC, %data
;		;
;		ext	m6502mem+1@ah		; %PC = &mem[PC]
;		ext	m6502mem+1@al
;		add	%PC, %PC
;		ret
;
	.global	m6502cpu_pull
m6502cpu_pull:
	xadd	%SP, %SP, 1			; %SP = SP+1
	ld.ub	%SP, %SP			; Wraparound
	ext	m6502mem+0x100@ah		; %r9 = &mem[$100|SP+1]
	ext	m6502mem+0x100@al
	add	%r9, %SP
	ld.ub	%data, [%r9]
	ret

;****************************************************************************
;	
;****************************************************************************

	.global	m6502cpu_run
m6502cpu_run:
	pushn	%r3
	;
	xld.w	[m6502cpu+_CYCLE_], %r12	; 必要!!
	xcall	m6502cpu_enter			; 実行コンテキストを取り出します。
	;
	xbtst	[%CPU+FLAGS], 0			; 既にWAI中ならば、残り実行サイクル数を0にして、
	jreq	2				;  すぐにループを抜けます。(m6502cpu.cycle=0で終了。)
	ld.w	%CYCLE, 0			; (skip?)
	;
	xjp	m6502cpu_run_LOOP		; Cycle=0が指定された場合のために、まず条件判定から。
m6502cpu_run_DO:
;----------------------------------------------------------------------------
//#define M6502CPU_RUN_TRACE
#ifdef M6502CPU_RUN_TRACE
	; トレースデバッグを行う場合は、このブロックを有効にしてください。
	; その際、m6502cpu_trace()は、アプリケーションにて定義してください。
	; m6502cpu_trace()は、ライブラリ内では定義していません。
	xcall  m6502cpu_leave
	xcall  m6502cpu_trace
	xcall  m6502cpu_enter
#endif /*M6502CPU_RUN_TRACE*/
;----------------------------------------------------------------------------
	ld.ub	%ptbl, [%PC]+			; %ptbl = OpCode
	xsll	%ptbl, 4			; %ptbl = &(tbl+3)[OpCode<<4]
	add	%ptbl, %TBL
	ld.ub	%t0, [%ptbl]+			; %t0 = 消費Cycle
	ld.w	%t1, [%ptbl]+			; %t1 = Action or Operation
	call.d	%t1
	sub	%CYCLE, %t0			; Cycle - 消費Cycle *delay*
m6502cpu_run_LOOP:
	xcmp	%CYCLE, 0			; Cycleが0以下になるまで繰り返します。
	xjrgt	m6502cpu_run_DO
	;
	xcall	m6502cpu_leave			; 実行コンテキストを書き戻します。
	;
	popn	%r3
	ret

;****************************************************************************
;	Action
;****************************************************************************

m6502cpu_ACCUMULATOR:
	ld.w	%t0, [%ptbl]			; %t0 = Operation
	call.d	%t0				; %data = Operation(data)
	ld.w	%data, %A			; %data = A *delay*
	ret.d
	ld.w	%A, %data			; %A = data *delay*

m6502cpu_IMMEDIATE:
	ld.w	%t0, [%ptbl]			; %t0 = Operation
	ld.ub	%data, [%PC]+			; %data = imm
	jp	%t0				; Operation(data)

m6502cpu_READ:
	ld.w	%t0, [%ptbl]+			; %t0 = AddressMode
	call	%t0				; %addr = AddressMode()
	xld.w	%t0, [%CPU+READ]		; %data = Read(addr)
	call	%t0
	ld.w	%t0, [%ptbl]			; %t0 = Operation
	jp	%t0				; Operation(data)

m6502cpu_WRITE:
	ld.w	%t0, [%ptbl]+			; %t0 = AddressMode
	call	%t0				; %addr = AddressMode()
	ld.w	%t0, [%ptbl]			; %t0 = Operation
	call	%t0				; %data = Operation(data)
	xld.w	%t0, [%CPU+WRITE]		; Write(addr, data)
	jp	%t0

m6502cpu_READ_WRITE:
	ld.w	%t0, [%ptbl]+			; %t0 = AddressMode
	call	%t0				; %addr = AddressMode()
	xld.w	%t0, [%CPU+READ]		; %data = Read(addr)
	call	%t0
	ld.w	%t0, [%ptbl]			; %t0 = Operation
	call	%t0				; %data = Operation(data)
	xld.w	%t0, [%CPU+WRITE]		; Write(addr, data)
	jp	%t0

m6502cpu_BRANCH_EQ:
	ld.w	%t0, [%ptbl]			; %t0 = Operation
	call	%t0				; Condition check
	ld.b	%t1, [%PC]+			; %t1 = rel
	jrne	3				; if(!ne) {
	add	%PC, %t1			;   PC += rel (skip?)
	sub	%CYCLE, 1			;   Cycle--   (skip?)
	ret					; }

m6502cpu_BRANCH_NE:
	ld.w	%t0, [%ptbl]			; %t0 = Operation
	call	%t0				; Condition check
	ld.b	%t1, [%PC]+			; %t1 = rel
	jreq	3				; if(!eq) {
	add	%PC, %t1			;   PC += rel (skip?)
	sub	%CYCLE, 1			;   Cycle--   (skip?)
	ret					; }

m6502cpu_JUMP:
	ld.w	%t0, [%ptbl]			; %t0 = AddressMode
	call	%t0				; %addr = AddressMode()
	ext	m6502mem@ah			; %PC = &mem[addr]
	ext	m6502mem@al
	add	%PC, %addr
	ret

m6502cpu_CALL:
	ld.w	%t0, [%ptbl]			; %t0 = AddressMode
	call	%t0				; %addr = AddressMode()
	;
	ext	m6502mem+1@ah			; %data = PC-1 (仕様)
	ext	m6502mem+1@al
	sub	%data, %PC
	xcall.d	m6502cpu_push			; Push HI(PC-1)
	rr	%data, 8			; *delay*
	xcall.d	m6502cpu_push			; Push LO(PC-1)
	rl	%data, 8			; *delay*
	;
	ext	m6502mem@ah			; %PC = &mem[addr]
	ext	m6502mem@al
	add	%PC, %addr
	ret

;****************************************************************************
;	AddressMode
;****************************************************************************

; * アドレッシングのアクセスはすべてメインメモリと仮定して、高速化してあります。
;   アドレッシングでI/Oアクセスを行うようなプログラムは、正しく動作しません。
;
; * ZeroPage内のWraparoundに依存するプログラムは無いと仮定して、高速化してあります。
;   もしもZeroPage内のWraparoundに依存するプログラムがあったならば、変更が必要です。
;   たとえばZeropage,XのWraparoundにきちんと対応するには、次のような変更が必要です。
;
;	m6502cpu_ZEROPAGE_X:
;		ld.ub	%addr, [%PC]+		; %addr = ZeroPage
;		add	%addr, %X		; %addr = ZeroPage+X
;		ld.ub	%addr, %addr		; Wraparound
;		ret
;
;   ↓(2005/03/18 追記)
;   ATARI VCS用Space InvadersがZeroPage内のWraparoundを使っているため、対応しました。
;   上述の変更例は"ld.ub"が遅延可能であることを発見する前に書いたものであり、
;   実際には、"ld.ub"を遅延スロットに入れる形で変更しました。
;   なお、本エミュレーションモジュールを使っていた既存のプログラムも、少し遅くなります。
;
; * 64KB内のWraparoundに依存するプログラムは無いと仮定して、高速化してあります。
;   もしも64KB内のWraparoundに依存するプログラムがあったならば、変更が必要です。
;   たとえばAbsolute,XのWraparoundにきちんと対応するには、次のような変更が必要です。
;
;	m6502cpu_ABSOLUTE_X:
;		ld.ub	%addr, [%PC]+		; %addr = LO(Absolute)
;		ld.ub	%t0, [%PC]+		; %t0   = HI(Absolute)
;		xsll	%t0, 8			; %addr = Absolute
;		or	%addr, %t0
;		add	%addr, %X		; %addr = Absolute+X
;		ld.uh	%addr, %addr		; Wraparound
;		ret
;
;   ↓(2005/03/18 追記)
;   ZeroPage内のWraparoundに対応したこと併せて、64KB内のWraparoundにも対応しました。
;   64KB内のWraparoundを使っているプログラムはまだ見つけていませんが、念のため、です。
;   上述の変更例は"ld.uh"が遅延可能であることを発見する前に書いたものであり、
;   実際には、"ld.uh"を遅延スロットに入れる形で変更しました。
;   なお、本エミュレーションモジュールを使っていた既存のプログラムも、少し遅くなります。
;

m6502cpu_ZEROPAGE:
	ld.ub	%addr, [%PC]+			; %addr = ZeroPage
	ret

m6502cpu_ZEROPAGE_X:
	ld.ub	%addr, [%PC]+			; %addr = ZeroPage
	add	%addr, %X			; %addr = ZeroPage+X
	ret.d
	ld.ub	%addr, %addr			; Wraparound *delay*

m6502cpu_ZEROPAGE_Y:
	ld.ub	%addr, [%PC]+			; %addr = ZeroPage
	add	%addr, %Y			; %addr = ZeroPage+Y
	ret.d
	ld.ub	%addr, %addr			; Wraparound *delay*

m6502cpu_ABSOLUTE:
	ld.ub	%addr, [%PC]+			; %addr = LO(Absolute)
	ld.ub	%t0,   [%PC]+			; %t0   = HI(Absolute)
	xsll	%t0, 8				; %addr = Absolute
	ret.d
	or	%addr, %t0			; *delay*

m6502cpu_ABSOLUTE_X:
	ld.ub	%addr, [%PC]+			; %addr = LO(Absolute)
	ld.ub	%t0, [%PC]+			; %t0   = HI(Absolute)
	xsll	%t0, 8				; %addr = Absolute
	or	%addr, %t0
	add	%addr, %X			; %addr = Absolute+X
	ret.d
	ld.uh	%addr, %addr			; Wraparound *delay*

m6502cpu_ABSOLUTE_Y:
	ld.ub	%addr, [%PC]+			; %addr = LO(Absolute)
	ld.ub	%t0, [%PC]+			; %t0   = HI(Absolute)
	xsll	%t0, 8				; %addr = Absolute
	or	%addr, %t0
	add	%addr, %Y			; %addr = Absolute+Y
	ret.d
	ld.uh	%addr, %addr			; Wraparound *delay*

m6502cpu_INDIRECT:
	ld.ub	%addr, [%PC]+			; %addr = LO(Absolute)
	ld.ub	%t0,   [%PC]+			; %t0   = HI(Absolute)
	xsll	%t0, 8				; %addr = Absolute
	or	%addr, %t0
	ext	m6502mem@ah			; %t1   = &mem[addr]
	ext	m6502mem@al
	add	%t1, %addr
	ld.ub	%addr, [%t1]+			; %addr = LO(Indirect)
	ld.ub	%t0,   [%t1]			; %t0   = HI(Indirect)
	xsll	%t0, 8				; %addr = Indirect
	ret.d
	or	%addr, %t0			; *delay*

m6502cpu_INDIRECT_X:
	ld.ub	%addr, [%PC]+			; %addr = ZeroPage
	add	%addr, %X			; %addr = ZeroPage+X
	ld.ub	%addr, %addr			; Wraparound
	ext	m6502mem@ah			; %t1   = &mem[addr]
	ext	m6502mem@al
	add	%t1, %addr
	ld.ub	%addr, [%t1]+			; %addr = LO(Indirect)
	ld.ub	%t0,   [%t1]			; %t0   = HI(Indirect)
	xsll	%t0, 8				; %addr = Indirect
	ret.d
	or	%addr, %t0			; *delay*

m6502cpu_INDIRECT_Y:
	ld.ub	%addr, [%PC]+			; %addr = ZeroPage
	ext	m6502mem@ah			; %t1   = &mem[addr]
	ext	m6502mem@al
	add	%t1, %addr
	ld.ub	%addr, [%t1]+			; %addr = LO(Indirect)
	ld.ub	%t0,   [%t1]			; %t0   = HI(Indirect)
	xsll	%t0, 8				; %addr = Indirect
	or	%addr, %t0
	add	%addr, %Y			; %addr = Indirect+Y
	ret.d
	ld.uh	%addr, %addr			; Wraparound *delay*

;****************************************************************************
;	Operation
;****************************************************************************

m6502cpu_LDA:
	ld.w	%A, %data
	ret.d
	ld.w	%NZ, %A				; *delay*

m6502cpu_LDX:
	ld.w	%X, %data
	ret.d
	ld.w	%NZ, %X				; *delay*

m6502cpu_LDY:
	ld.w	%Y, %data
	ret.d
	ld.w	%NZ, %Y				; *delay*

;----------------------------------------------------------------------------

m6502cpu_STA:
	ret.d
	ld.w	%data, %A			; *delay*

m6502cpu_STX:
	ret.d
	ld.w	%data, %X			; *delay*

m6502cpu_STY:
	ret.d
	ld.w	%data, %Y			; *delay*

;----------------------------------------------------------------------------

m6502cpu_TXA:
	ld.w	%A, %X
	ret.d
	ld.w	%NZ, %A				; *delay*

m6502cpu_TYA:
	ld.w	%A, %Y
	ret.d
	ld.w	%NZ, %A				; *delay*

m6502cpu_TAX:
	ld.w	%X, %A
	ret.d
	ld.w	%NZ, %X				; *delay*

m6502cpu_TAY:
	ld.w	%Y, %A
	ret.d
	ld.w	%NZ, %Y				; *delay*

m6502cpu_TSX:
	ld.w	%X, %SP
	ret.d
	ld.w	%NZ, %X				; *delay*

m6502cpu_TXS:
	ret.d
	ld.w	%SP, %X				; *delay*
	; no PSR affected

;----------------------------------------------------------------------------

m6502cpu_PHA:
	xjp.d	m6502cpu_push			; Push A
	ld.w	%data, %A			; *delay*

m6502cpu_PHP:
	xcall	m6502cpu_pack			; Push PSR
	xjp	m6502cpu_push

m6502cpu_PLA:
	xcall	m6502cpu_pull			; Pull A
	ld.w	%A, %data
	ret.d
	ld.w	%NZ, %A				; *delay*

m6502cpu_PLP:
	xcall	m6502cpu_pull			; Pull PSR
	xcall	m6502cpu_unpack
	xjp	m6502cpu_check_pending		; 保留IRQ要求を調べます。

;****************************************************************************
;	Operation
;****************************************************************************

m6502cpu_ADC:
	xbtst	[%CPU+BDI], 3
	xjrne	m6502cpu_ADCD
	;
	ld.w	%t0, %A				; %t0 = A+data+C
	xbtst	[%CPU+CA+1], 0
	jreq.d	3
	add	%t0, %data			; *delay*
	add	%t0, 1				; (skip?)
	;
	xld.h	[%CPU+CA], %t0			; C = (A+data+C)[8]
	;
	xor	%data, %A			; %data =  (A^data)
	not	%data, %data			; %data = ~(A^data)
	xor	%A, %t0				; %A    =           (A^(A+data+C))
	and	%data, %A			; %data = ~(A^data)&(A^(A+data+C))
	xld.b	[%CPU+V], %data			; V     = ~(A^data)&(A^(A+data+C))[7]
	;
	ld.ub	%A, %t0				; %A = A+data+C (unsigned)
	ret.d
	ld.w	%NZ, %A				; *delay*

m6502cpu_ADCD:
	xcall	m6502cpu_leave
	xcall.d	m6502cpu_adcd
	ld.w	%r12, %data			; *delay*
	xjp	m6502cpu_enter

m6502cpu_SBC:
	xbtst	[%CPU+BDI], 3
	xjrne	m6502cpu_SBCD
	;
	ld.w	%t0, %A				; %t0 = A-data-~C
	xbtst	[%CPU+CA+1], 0
	jrne.d	3
	sub	%t0, %data			; *delay*
	sub	%t0, 1				; (skip?)
	;
	not	%t1, %t0			; C = ~(A-data-~C)[8]
	xld.h	[%CPU+CA], %t1
	;
	xor	%data, %A			; %data = (A^data)
	xor	%A, %t0				; %A    =          (A^(A-data-~C))
	and	%data, %A			; %data = (A^data)&(A^(A-data-~C))
	xld.b	[%CPU+V], %data			; V     = (A^data)&(A^(A-data-~C))[7]
	;
	ld.ub	%A, %t0				; %A = A-data-~C (unsigned)
	ret.d
	ld.w	%NZ, %A				; *delay*

m6502cpu_SBCD:
	xcall	m6502cpu_leave
	xcall.d	m6502cpu_sbcd
	ld.w	%r12, %data			; *delay*
	xjp	m6502cpu_enter

m6502cpu_CMP:
	ld.w	%NZ, %A				; %NZ = A-data
	sub	%NZ, %data
	not	%t0, %NZ			; C = ~(A-data)[8]
	xld.h	[%CPU+CA], %t0
	ret.d
	ld.ub	%NZ, %NZ			; 必要!! *delay*

m6502cpu_CPX:
	ld.w	%NZ, %X				; %NZ = X-data
	sub	%NZ, %data
	not	%t0, %NZ			; C = ~(X-data)[8]
	xld.h	[%CPU+CA], %t0
	ret.d
	ld.ub	%NZ, %NZ			; 必要!! *delay*

m6502cpu_CPY:
	ld.w	%NZ, %Y				; %NZ = Y-data
	sub	%NZ, %data
	not	%t0, %NZ			; C = ~(Y-data)[8]
	xld.h	[%CPU+CA], %t0
	ret.d
	ld.ub	%NZ, %NZ			; 必要!! *delay*

;----------------------------------------------------------------------------

m6502cpu_INC:
	xadd	%data, %data, 1
	ld.ub	%data, %data			; 必要!!
	ret.d
	ld.w	%NZ, %data			; *delay*

m6502cpu_INX:
	xadd	%X, %X, 1
	ld.ub	%X, %X				; 必要!!
	ret.d
	ld.w	%NZ, %X				; *delay*

m6502cpu_INY:
	xadd	%Y, %Y, 1
	ld.ub	%Y, %Y				; 必要!!
	ret.d
	ld.w	%NZ, %Y				; *delay*

m6502cpu_DEC:
	xsub	%data, %data, 1
	ld.ub	%data, %data			; 必要!!
	ret.d
	ld.w	%NZ, %data			; *delay*

m6502cpu_DEX:
	xsub	%X, %X, 1
	ld.ub	%X, %X				; 必要!!
	ret.d
	ld.w	%NZ, %X				; *delay*

m6502cpu_DEY:
	xsub	%Y, %Y, 1
	ld.ub	%Y, %Y				; 必要!!
	ret.d
	ld.w	%NZ, %Y				; *delay*

;****************************************************************************
;	Operation
;****************************************************************************

m6502cpu_AND:
	and	%A, %data
	ret.d
	ld.w	%NZ, %A				; *delay*

m6502cpu_ORA:
	or	%A, %data
	ret.d
	ld.w	%NZ, %A				; *delay*

m6502cpu_EOR:
	xor	%A, %data
	ret.d
	ld.w	%NZ, %A				; *delay*

m6502cpu_ASL:
	xsll	%data, 1			; %data = -------7 6543210-
	xld.h	[%CPU+CA], %data		;                +------------> C
	ld.ub	%data, %data			; %data = -------- 6543210-
	ret.d
	ld.w	%NZ, %data			; *delay*

m6502cpu_LSR:
	xld.b	[%CPU+CA+1], %data		; %data = -------- 76543210 +-> C
	xsrl	%data, 1			; %data = -------- -7654321
	ret.d
	ld.w	%NZ, %data			; *delay *

m6502cpu_ROL:
	xld.ub	%t0, [%CPU+CA+1]		; %t0   = -------- -------C
	xand	%t0, %t0, 1
	xsll	%data, 1			; %data = -------7 6543210-
	xld.h	[%CPU+CA], %data		;                +------------> C
	ld.ub	%data, %data			; %data = -------- 6543210-
	or	%data, %t0			; %data = -------- 6543210C
	ret.d
	ld.w	%NZ, %data			; *delay*

m6502cpu_ROR:
	xld.ub	%t0, [%CPU+CA+1]		; %t0   = -------- -------C
	xand	%t0, %t0, 1
	xsll	%t0, 7				; %t0   = -------- C-------
	xld.b	[%CPU+CA+1], %data		; %data = -------- 76543210 +-> C
	xsrl	%data, 1			; %data = -------- -7654321
	or	%data, %t0			; %data = -------- C7654321
	ret.d
	ld.w	%NZ, %data

m6502cpu_BIT:
	ld.w	%NZ, %data			; V   =          V-------
	xsll	%NZ, 1				;                +-------- (  data)[6]
	xld.b	[%CPU+V], %NZ			; %NZ = N------- NZZZZZZZ
	xsll	%NZ, 7				;       |        ++++++++- (A&data)
	and	%data, %A			;       |        +-------- (A&data)[7]
	ret.d					;       +----------------- (  data)[7]
	or	%NZ, %data			; *delay*

;****************************************************************************
;	Operation
;****************************************************************************

m6502cpu_BCC:
m6502cpu_BCS:
	xbtst	[%CPU+CA+1], 0
	ret

m6502cpu_BNE:
m6502cpu_BEQ:
	xand	%r9, %NZ, 0xff
	ret

m6502cpu_BVC:
m6502cpu_BVS:
	xbtst	[%CPU+V], 7
	ret

m6502cpu_BPL:
m6502cpu_BMI:
	xand	%r9, %NZ, 0x8080
	ret

;----------------------------------------------------------------------------

m6502cpu_BRK:
	xld.w	%addr, 0xfffe			; BRKを実行します。
	xjp.d	m6502cpu_interrupt
	ld.w	%data, 1			; *delay*

m6502cpu_RTS:
	xcall	m6502cpu_pull			; Pull LO(PC-1)
	xcall.d	m6502cpu_pull			; Pull HI(PC-1)
	ld.w	%PC, %data			; *delay*
	xsll	%data, 8			; %PC = PC-1 (仕様)
	or	%PC, %data
	;
	ext	m6502mem+1@ah			; %PC = &mem[PC]
	ext	m6502mem+1@al
	add	%PC, %PC
	ret

m6502cpu_RTI:
	xcall	m6502cpu_pull			; Pull PSR
	xcall	m6502cpu_unpack
	;
	xcall	m6502cpu_pull			; Pull LO(PC)
	xcall.d	m6502cpu_pull			; Pull HI(PC)
	ld.w	%PC, %data			; *delay*
	xsll	%data, 8			; %PC = PC
	or	%PC, %data
	;
	ext	m6502mem@ah			; %PC = &mem[PC]
	ext	m6502mem@al
	add	%PC, %PC
	;
	xjp	m6502cpu_check_pending		; 保留IRQ要求を調べます。

;****************************************************************************
;	Operation
;****************************************************************************

m6502cpu_SEC:
	xbset	[%CPU+CA+1], 0
	ret

m6502cpu_CLC:
	xbclr	[%CPU+CA+1], 0
	ret

m6502cpu_SEI:
	xbset	[%CPU+BDI], 2
	ret

m6502cpu_CLI:
	xbclr	[%CPU+BDI], 2
	xjp	m6502cpu_check_pending		; 保留IRQ要求を調べます。

m6502cpu_SED:
	xbset	[%CPU+BDI], 3
	ret

m6502cpu_CLD:
	xbclr	[%CPU+BDI], 3
	ret

m6502cpu_CLV:
	xbclr	[%CPU+V], 7
	ret

;----------------------------------------------------------------------------

m6502cpu_NOP:
	ret

m6502cpu_WAI:
	xbset	[%CPU+FLAGS], 0
	ret.d
	ld.w	%CYCLE, 0

;****************************************************************************
;	
;****************************************************************************

; 高速化のため、M6502CPU構造体を高速RAMに配置します。
; 高速RAMへ配置するために、.codeセクションとします。
	.code
	.align	2
	.global	m6502cpu
m6502cpu:
	.space	SIZEOF_M6502CPU

;****************************************************************************
;	
;****************************************************************************

; 制御テーブルは、高速RAMではなくSRAMに配置します。
; SRAMへ配置するために、.dataセクションとします。
	.data
m6502tbl:
	; [00] BRK Implied
	.word 7<<24
	.word m6502cpu_BRK
	.word -1
	.word -1
	; [01] ORA Indirect,X
	.word 6<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_X
	.word m6502cpu_ORA
	; [02] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [03] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [04] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [05] ORA ZeroPage
	.word 3<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_ORA
	; [06] ASL ZeroPage
	.word 5<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_ASL
	; [07] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [08] PHP Implied
	.word 3<<24
	.word m6502cpu_PHP
	.word -1
	.word -1
	; [09] ORA Immediate
	.word 2<<24
	.word m6502cpu_IMMEDIATE
	.word m6502cpu_ORA
	.word -1
	; [0A] ASL Accumulator
	.word 2<<24
	.word m6502cpu_ACCUMULATOR
	.word m6502cpu_ASL
	.word -1
	; [0B] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [0C] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [0D] ORA Absolute
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_ORA
	; [0E] ASL Absolute
	.word 6<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_ASL
	; [0F] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [10] BPL Relative
	.word 2<<24
	.word m6502cpu_BRANCH_EQ
	.word m6502cpu_BPL
	.word -1
	; [11] ORA Indirect,Y
	.word 5<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_Y
	.word m6502cpu_ORA
	; [12] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [13] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [14] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [15] ORA ZeroPage,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_ORA
	; [16] ASL ZeroPage,X
	.word 6<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_ASL
	; [17] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [18] CLC Implied
	.word 2<<24
	.word m6502cpu_CLC
	.word -1
	.word -1
	; [19] ORA Absolute,Y
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_Y
	.word m6502cpu_ORA
	; [1A] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [1B] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [1C] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [1D] ORA Absolute,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_ORA
	; [1E] ASL Absolute,X
	.word 7<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_ASL
	; [1F] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [20] JSR Absolute
	.word 6<<24
	.word m6502cpu_CALL
	.word m6502cpu_ABSOLUTE
	.word -1
	; [21] AND Indirect,X
	.word 6<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_X
	.word m6502cpu_AND
	; [22] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [23] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [24] BIT ZeroPage
	.word 3<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_BIT
	; [25] AND ZeroPage
	.word 3<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_AND
	; [26] ROL ZeroPage
	.word 5<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_ROL
	; [27] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [28] PLP Implied
	.word 4<<24
	.word m6502cpu_PLP
	.word -1
	.word -1
	; [29] AND Immediate
	.word 2<<24
	.word m6502cpu_IMMEDIATE
	.word m6502cpu_AND
	.word -1
	; [2A] ROL Accumulator
	.word 2<<24
	.word m6502cpu_ACCUMULATOR
	.word m6502cpu_ROL
	.word -1
	; [2B] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [2C] BIT Absolute
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_BIT
	; [2D] AND Absolute
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_AND
	; [2E] ROL Absolute
	.word 6<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_ROL
	; [2F] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [30] BMI Relative
	.word 2<<24
	.word m6502cpu_BRANCH_NE
	.word m6502cpu_BMI
	.word -1
	; [31] AND Indirect,Y
	.word 5<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_Y
	.word m6502cpu_AND
	; [32] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [33] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [34] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [35] AND ZeroPage,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_AND
	; [36] ROL ZeroPage,X
	.word 6<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_ROL
	; [37] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [38] SEC Implied
	.word 2<<24
	.word m6502cpu_SEC
	.word -1
	.word -1
	; [39] AND Absolute,Y
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_Y
	.word m6502cpu_AND
	; [3A] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [3B] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [3C] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [3D] AND Absolute,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_AND
	; [3E] ROL Absolute,X
	.word 7<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_ROL
	; [3F] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [40] RTI Implied
	.word 6<<24
	.word m6502cpu_RTI
	.word -1
	.word -1
	; [41] EOR Indirect,X
	.word 6<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_X
	.word m6502cpu_EOR
	; [42] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [43] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [44] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [45] EOR ZeroPage
	.word 3<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_EOR
	; [46] LSR ZeroPage
	.word 5<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_LSR
	; [47] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [48] PHA Implied
	.word 3<<24
	.word m6502cpu_PHA
	.word -1
	.word -1
	; [49] EOR Immediate
	.word 2<<24
	.word m6502cpu_IMMEDIATE
	.word m6502cpu_EOR
	.word -1
	; [4A] LSR Accumulator
	.word 2<<24
	.word m6502cpu_ACCUMULATOR
	.word m6502cpu_LSR
	.word -1
	; [4B] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [4C] JMP Absolute
	.word 3<<24
	.word m6502cpu_JUMP
	.word m6502cpu_ABSOLUTE
	.word -1
	; [4D] EOR Absolute
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_EOR
	; [4E] LSR Absolute
	.word 6<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_LSR
	; [4F] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [50] BVC Relative
	.word 2<<24
	.word m6502cpu_BRANCH_EQ
	.word m6502cpu_BVC
	.word -1
	; [51] EOR Indirect,Y
	.word 5<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_Y
	.word m6502cpu_EOR
	; [52] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [53] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [54] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [55] EOR ZeroPage,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_EOR
	; [56] LSR ZeroPage,X
	.word 6<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_LSR
	; [57] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [58] CLI Implied
	.word 2<<24
	.word m6502cpu_CLI
	.word -1
	.word -1
	; [59] EOR Absolute,Y
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_Y
	.word m6502cpu_EOR
	; [5A] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [5B] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [5C] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [5D] EOR Absolute,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_EOR
	; [5E] LSR Absolute,X
	.word 7<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_LSR
	; [5F] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [60] RTS Implied
	.word 6<<24
	.word m6502cpu_RTS
	.word -1
	.word -1
	; [61] ADC Indirect,X
	.word 6<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_X
	.word m6502cpu_ADC
	; [62] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [63] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [64] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [65] ADC ZeroPage
	.word 3<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_ADC
	; [66] ROR ZeroPage
	.word 5<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_ROR
	; [67] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [68] PLA Implied
	.word 4<<24
	.word m6502cpu_PLA
	.word -1
	.word -1
	; [69] ADC Immediate
	.word 2<<24
	.word m6502cpu_IMMEDIATE
	.word m6502cpu_ADC
	.word -1
	; [6A] ROR Accumulator
	.word 2<<24
	.word m6502cpu_ACCUMULATOR
	.word m6502cpu_ROR
	.word -1
	; [6B] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [6C] JMP Indirect
	.word 5<<24
	.word m6502cpu_JUMP
	.word m6502cpu_INDIRECT
	.word -1
	; [6D] ADC Absolute
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_ADC
	; [6E] ROR Absolute
	.word 6<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_ROR
	; [6F] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [70] BVS Relative
	.word 2<<24
	.word m6502cpu_BRANCH_NE
	.word m6502cpu_BVS
	.word -1
	; [71] ADC Indirect,Y
	.word 5<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_Y
	.word m6502cpu_ADC
	; [72] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [73] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [74] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [75] ADC ZeroPage,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_ADC
	; [76] ROR ZeroPage,X
	.word 6<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_ROR
	; [77] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [78] SEI Implied
	.word 2<<24
	.word m6502cpu_SEI
	.word -1
	.word -1
	; [79] ADC Absolute,Y
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_Y
	.word m6502cpu_ADC
	; [7A] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [7B] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [7C] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [7D] ADC Absolute,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_ADC
	; [7E] ROR Absolute,X
	.word 7<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_ROR
	; [7F] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [80] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [81] STA Indirect,X
	.word 6<<24
	.word m6502cpu_WRITE
	.word m6502cpu_INDIRECT_X
	.word m6502cpu_STA
	; [82] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [83] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [84] STY ZeroPage
	.word 3<<24
	.word m6502cpu_WRITE
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_STY
	; [85] STA ZeroPage
	.word 3<<24
	.word m6502cpu_WRITE
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_STA
	; [86] STX ZeroPage
	.word 3<<24
	.word m6502cpu_WRITE
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_STX
	; [87] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [88] DEY Implied
	.word 2<<24
	.word m6502cpu_DEY
	.word -1
	.word -1
	; [89] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [8A] TXA Implied
	.word 2<<24
	.word m6502cpu_TXA
	.word -1
	.word -1
	; [8B] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [8C] STY Absolute
	.word 4<<24
	.word m6502cpu_WRITE
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_STY
	; [8D] STA Absolute
	.word 4<<24
	.word m6502cpu_WRITE
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_STA
	; [8E] STX Absolute
	.word 4<<24
	.word m6502cpu_WRITE
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_STX
	; [8F] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [90] BCC Relative
	.word 2<<24
	.word m6502cpu_BRANCH_EQ
	.word m6502cpu_BCC
	.word -1
	; [91] STA Indirect,Y
	.word 6<<24
	.word m6502cpu_WRITE
	.word m6502cpu_INDIRECT_Y
	.word m6502cpu_STA
	; [92] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [93] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [94] STY ZeroPage,X
	.word 4<<24
	.word m6502cpu_WRITE
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_STY
	; [95] STA ZeroPage,X
	.word 4<<24
	.word m6502cpu_WRITE
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_STA
	; [96] STX ZeroPage,Y
	.word 4<<24
	.word m6502cpu_WRITE
	.word m6502cpu_ZEROPAGE_Y
	.word m6502cpu_STX
	; [97] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [98] TYA Implied
	.word 2<<24
	.word m6502cpu_TYA
	.word -1
	.word -1
	; [99] STA Absolute,Y
	.word 5<<24
	.word m6502cpu_WRITE
	.word m6502cpu_ABSOLUTE_Y
	.word m6502cpu_STA
	; [9A] TXS Implied
	.word 2<<24
	.word m6502cpu_TXS
	.word -1
	.word -1
	; [9B] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [9C] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [9D] STA Absolute,X
	.word 5<<24
	.word m6502cpu_WRITE
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_STA
	; [9E] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [9F] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [A0] LDY Immediate
	.word 2<<24
	.word m6502cpu_IMMEDIATE
	.word m6502cpu_LDY
	.word -1
	; [A1] LDA Indirect,X
	.word 6<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_X
	.word m6502cpu_LDA
	; [A2] LDX Immediate
	.word 2<<24
	.word m6502cpu_IMMEDIATE
	.word m6502cpu_LDX
	.word -1
	; [A3] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [A4] LDY ZeroPage
	.word 3<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_LDY
	; [A5] LDA ZeroPage
	.word 3<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_LDA
	; [A6] LDX ZeroPage
	.word 3<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_LDX
	; [A7] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [A8] TAY Implied
	.word 2<<24
	.word m6502cpu_TAY
	.word -1
	.word -1
	; [A9] LDA Immediate
	.word 2<<24
	.word m6502cpu_IMMEDIATE
	.word m6502cpu_LDA
	.word -1
	; [AA] TAX Implied
	.word 2<<24
	.word m6502cpu_TAX
	.word -1
	.word -1
	; [AB] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [AC] LDY Absolute
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_LDY
	; [AD] LDA Absolute
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_LDA
	; [AE] LDX Absolute
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_LDX
	; [AF] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [B0] BCS Relative
	.word 2<<24
	.word m6502cpu_BRANCH_NE
	.word m6502cpu_BCS
	.word -1
	; [B1] LDA Indirect,Y
	.word 5<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_Y
	.word m6502cpu_LDA
	; [B2] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [B3] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [B4] LDY ZeroPage,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_LDY
	; [B5] LDA ZeroPage,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_LDA
	; [B6] LDX ZeroPage,Y
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE_Y
	.word m6502cpu_LDX
	; [B7] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [B8] CLV Implied
	.word 2<<24
	.word m6502cpu_CLV
	.word -1
	.word -1
	; [B9] LDA Absolute,Y
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_Y
	.word m6502cpu_LDA
	; [BA] TSX Implied
	.word 2<<24
	.word m6502cpu_TSX
	.word -1
	.word -1
	; [BB] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [BC] LDY Absolute,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_LDY
	; [BD] LDA Absolute,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_LDA
	; [BE] LDX Absolute,Y
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_Y
	.word m6502cpu_LDX
	; [BF] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [C0] CPY Immediate
	.word 2<<24
	.word m6502cpu_IMMEDIATE
	.word m6502cpu_CPY
	.word -1
	; [C1] CMP Indirect,X
	.word 6<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_X
	.word m6502cpu_CMP
	; [C2] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [C3] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [C4] CPY ZeroPage
	.word 3<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_CPY
	; [C5] CMP ZeroPage
	.word 3<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_CMP
	; [C6] DEC ZeroPage
	.word 5<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_DEC
	; [C7] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [C8] INY Implied
	.word 2<<24
	.word m6502cpu_INY
	.word -1
	.word -1
	; [C9] CMP Immediate
	.word 2<<24
	.word m6502cpu_IMMEDIATE
	.word m6502cpu_CMP
	.word -1
	; [CA] DEX Implied
	.word 2<<24
	.word m6502cpu_DEX
	.word -1
	.word -1
	; [CB] WAI Implied
	.word 3<<24
	.word m6502cpu_WAI
	.word -1
	.word -1
	; [CC] CPY Absolute
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_CPY
	; [CD] CMP Absolute
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_CMP
	; [CE] DEC Absolute
	.word 6<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_DEC
	; [CF] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [D0] BNE Relative
	.word 2<<24
	.word m6502cpu_BRANCH_NE
	.word m6502cpu_BNE
	.word -1
	; [D1] CMP Indirect,Y
	.word 5<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_Y
	.word m6502cpu_CMP
	; [D2] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [D3] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [D4] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [D5] CMP ZeroPage,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_CMP
	; [D6] DEC ZeroPage,X
	.word 6<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_DEC
	; [D7] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [D8] CLD Implied
	.word 2<<24
	.word m6502cpu_CLD
	.word -1
	.word -1
	; [D9] CMP Absolute,Y
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_Y
	.word m6502cpu_CMP
	; [DA] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [DB] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [DC] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [DD] CMP Absolute,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_CMP
	; [DE] DEC Absolute,X
	.word 7<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_DEC
	; [DF] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [E0] CPX Immediate
	.word 2<<24
	.word m6502cpu_IMMEDIATE
	.word m6502cpu_CPX
	.word -1
	; [E1] SBC Indirect,X
	.word 6<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_X
	.word m6502cpu_SBC
	; [E2] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [E3] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [E4] CPX ZeroPage
	.word 3<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_CPX
	; [E5] SBC ZeroPage
	.word 3<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_SBC
	; [E6] INC ZeroPage
	.word 5<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ZEROPAGE
	.word m6502cpu_INC
	; [E7] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [E8] INX Implied
	.word 2<<24
	.word m6502cpu_INX
	.word -1
	.word -1
	; [E9] SBC Immediate
	.word 2<<24
	.word m6502cpu_IMMEDIATE
	.word m6502cpu_SBC
	.word -1
	; [EA] NOP Implied
	.word 2<<24
	.word m6502cpu_NOP
	.word -1
	.word -1
	; [EB] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [EC] CPX Absolute
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_CPX
	; [ED] SBC Absolute
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_SBC
	; [EE] INC Absolute
	.word 6<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ABSOLUTE
	.word m6502cpu_INC
	; [EF] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [F0] BEQ Relative
	.word 2<<24
	.word m6502cpu_BRANCH_EQ
	.word m6502cpu_BEQ
	.word -1
	; [F1] SBC Indirect,Y
	.word 5<<24
	.word m6502cpu_READ
	.word m6502cpu_INDIRECT_Y
	.word m6502cpu_SBC
	; [F2] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [F3] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [F4] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [F5] SBC ZeroPage,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_SBC
	; [F6] INC ZeroPage,X
	.word 6<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ZEROPAGE_X
	.word m6502cpu_INC
	; [F7] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [F8] SED Implied
	.word 2<<24
	.word m6502cpu_SED
	.word -1
	.word -1
	; [F9] SBC Absolute,Y
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_Y
	.word m6502cpu_SBC
	; [FA] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [FB] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [FC] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
	; [FD] SBC Absolute,X
	.word 4<<24
	.word m6502cpu_READ
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_SBC
	; [FE] INC Absolute,X
	.word 7<<24
	.word m6502cpu_READ_WRITE
	.word m6502cpu_ABSOLUTE_X
	.word m6502cpu_INC
	; [FF] ERR
	.word 0<<24
	.word m6502cpu_ERR
	.word -1
	.word -1
