;
;	framz8ca.s
;
;	P/ECE Z80 Emulator (高速版)
;
;	CLiP - Common Library for P/ECE
;	Copyright (C) 2001-2005 Naoyuki Sawa
;
;	* Mon Jan 10 19:00:00 JST 2005 Naoyuki Sawa
;	- 作成開始。
;	* Mon Mar 07 02:08:00 JST 2005 Naoyuki Sawa
;	- HALT=1の状態でm6502cpu_runが呼ばれたときに、m6502cpu.cycle=0で終了するよう修正。
;	  これまでは、m6502cpu.cycleを変化せずに終了してしまっていたために、
;	  Cycleの端数を次回のm6502cpu_runへ繰り延べるような処理に不具合が生じていました。
;
#include "clipz8ca.h"

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

	.code
	.align 2

	; 高速化のため、Z80CPU構造体を高速RAMに配置します。
	.global z80cpu
z80cpu:
	.space SIZEOF_Z80CPU

	.code
	.align 1

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

	.global z80cpu_run
z80cpu_run:
	pushn  %r3
	;
	xld.w [z80cpu+_CYCLE_], %r12	; 実行コンテキストを取り出します。
	xcall  z80cpu_enter
	;
	xbtst [%CPU+HALT], 0		; 既にHALT中ならば、残り実行サイクル数を0にして、
	jreq   2			;  すぐにループを抜けます。(z80cpu.cycle=0で終了。)
	ld.w   %CYCLE, 0		; (skip?)
	;
	xjp    z80cpu_run_LOOP		; Cycle=0が指定された場合のために、まず条件判定から。
z80cpu_run_DO:
;----------------------------------------------------------------------------
//#define Z80CPU_RUN_TRACE
#ifdef Z80CPU_RUN_TRACE
	; トレースデバッグを行う場合は、このブロックを有効にしてください。
	; その際、z80cpu_trace()は、アプリケーションにて定義してください。
	; z80cpu_trace()は、ライブラリ内では定義していません。
	xcall  z80cpu_leave
	xcall  z80cpu_trace
	xcall  z80cpu_enter
#endif /*Z80CPU_RUN_TRACE*/
;----------------------------------------------------------------------------
	ld.ub  %t0, [%PC]+		; OpCodeを取得し、PCを進めます。
	xsll   %t0, 2			; OpCodeに対応する命令ルーチンを呼び出します。
	ext    z80cpu_XXops@ah
	ext    z80cpu_XXops@al
	ld.w   %t0, [%t0]
	call   %t0
z80cpu_run_LOOP:
	xcmp   %CYCLE, 0		; Cycleが0以下になるまで繰り返します。
	xjrgt  z80cpu_run_DO
	;
	xcall  z80cpu_leave		; 実行コンテキストを書き戻します。
	;
	popn   %r3
	ret

;
;	CB xx
;	   ++- OpCode
;
	.global z80cpu_CB
z80cpu_CB:
	ld.ub %t0, [%PC]+		; OpCode
	xsll  %t0, 2
	ext z80cpu_CBops@ah
	ext z80cpu_CBops@al
	ld.w  %t0, [%t0]
	jp    %t0

;
;	ED xx
;	   ++- OpCode
;
	.global z80cpu_ED
z80cpu_ED:
	ld.ub %t0, [%PC]+		; OpCode
	xsll  %t0, 2
	ext z80cpu_EDops@ah
	ext z80cpu_EDops@al
	ld.w  %t0, [%t0]
	jp %t0

;
;	DD xx
;	   ++- OpCode
;
	.global z80cpu_DD
z80cpu_DD:
	ld.ub %t0, [%PC]+		; OpCode
	xsll  %t0, 2
	ext z80cpu_DDops@ah
	ext z80cpu_DDops@al
	ld.w  %t0, [%t0]
	jp %t0

;
;	FD xx
;	   ++- OpCode
;
	.global z80cpu_FD
z80cpu_FD:
	ld.ub %t0, [%PC]+		; OpCode
	xsll  %t0, 2
	ext z80cpu_FDops@ah
	ext z80cpu_FDops@al
	ld.w  %t0, [%t0]
	jp %t0

;
;	DD CB d xx
;	      | ++- OpCode
;	      +---- IX+"d"
;
; [note]
;	* DD CB d xx 系列の命令は全て同じバイト構成で、[IX+d]を引数に取ります。
;	  あらかじめここで、&z80ram[IX+d]のメモリアドレスを求めておきます。
;	  これ以降は、FD CB d xx 系列と同じなので、命令ルーチンを共有できます。
;	* DD CB d xx 系列の命令ルーチンは %s0 = mem+IX+d の引数で呼び出されます。
;	  命令ルーチンの中で、メモリアドレスを計算する必要はありません。
;	* DD CB d xx 系列の命令ルーチンには xxx_IaddrI という名前を付けました。
;	  (z80cpu_RLC_IaddrI、z80cpu_BIT_0_IaddrI など)
;
	.global z80cpu_DDCB
z80cpu_DDCB:
	xld.uh %s0, [%CPU+IX]		; %s0 = &z80mem[IX+d(signed)]
	ld.b   %t0, [%PC]+
	add    %s0, %t0
	add    %s0, %MEM
	ld.ub  %t0, [%PC]+		; OpCode
	xsll   %t0, 2
	ext z80cpu_XXCBops@ah		; 
	ext z80cpu_XXCBops@al
	ld.w   %t0, [%t0]
	jp     %t0

;
;	FD CB d xx
;	      | ++- OpCode
;	      +---- IY+"d"
;
; [note]
;	* FD CB d xx 系列の命令は全て同じバイト構成で、[IY+d]を引数に取ります。
;	  あらかじめここで、&z80ram[IY+d]のメモリアドレスを求めておきます。
;	  これ以降は、DD CB d xx 系列と同じなので、命令ルーチンを共有できます。
;	* FD CB d xx 系列の命令ルーチンは %s0 = mem+IX+d の引数で呼び出されます。
;	  命令ルーチンの中で、メモリアドレスを計算する必要はありません。
;	* FD CB d xx 系列の命令ルーチンには xxx_IaddrI という名前を付けました。
;	  (z80cpu_RLC_IaddrI、z80cpu_BIT_0_IaddrI など)
;
	.global z80cpu_FDCB
z80cpu_FDCB:
	xld.uh %s0, [%CPU+IY]		; %s0 = &z80mem[IY+d(signed)]
	ld.b   %t0, [%PC]+
	add    %s0, %t0
	add    %s0, %MEM
	ld.ub  %t0, [%PC]+		; OpCode
	xsll   %t0, 2
	ext z80cpu_XXCBops@ah
	ext z80cpu_XXCBops@al
	ld.w   %t0, [%t0]
	jp     %t0

;****************************************************************************
;	16-Bit Load Group
;****************************************************************************

;
;	PUSH rr
;
; [in]
;	%a0		rr
;
	.global z80cpu_push
z80cpu_push:
	xld.uh %t0, [%CPU+SP]		; %t0 = SP
	add    %t0, %MEM		; %t0 = mem+SP
	xrr    %a0, 8			; %a0[7:0] = hi(rr)
	xsub   %t0, %t0, 1		; %t0 = mem+SP-1
	ld.b  [%t0], %a0		; [mem+SP-1] = hi(rr)
	xrl    %a0, 8			; %a0[7:0] = lo(rr)
	xsub   %t0, %t0, 1		; %t0 = mem+SP-2
	ld.b  [%t0], %a0		; [mem+SP-2] = lo(rr)
	sub    %t0, %MEM		; %s0 = SP-2
	xld.h [%CPU+SP], %t0		; SP = SP-2
	ret

;
;	POP rr
;
; [out]
;	%a0		rr
;
	.global z80cpu_pop
z80cpu_pop:
	xld.uh %t0, [%CPU+SP]		; %t0 = SP
	add    %t0, %MEM		; %t0 = mem+SP
	ld.ub  %a0, [%t0]+		; %a0 = [mem+SP+0], %t0 = mem+SP+1
	ld.ub  %a1, [%t0]+		; %a1 = [mem+SP+1], %t0 = mem+SP+2
	sub    %t0, %MEM		; %t0 = SP+2
	xld.h [%CPU+SP], %t0		; SP  = SP+2
	xsll   %a1, 8			; %a0 = lo(rr)|hi(rr)<<8
	ret.d
	or     %a0, %a1			; *delay*

;****************************************************************************
;	8-Bit Arithmetic Group
;****************************************************************************

;
;	ADD A, r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is set if carry from bit 3, reset otherwise
;	P/V	is set if overflow, reset otherwise
;	N	is reset
;	C	is set if carry from bit 7, reset otherwise
;
; [in]
;	%a0	r
;
	.global z80cpu_add8
z80cpu_add8:
	swap %t0, %A			; %t0[31:24] = A
	swap %t1, %a0			; %t1[31:24] = r
	add  %t0, %t1			; %t0[31:24] = A+r
	;
	ld.w %F, %psr			; %F = F(00CPZS)
	xand %F, %F, CF|PF|ZF|SF
	xand %A, %A, 0xf		; %F = F(0HCPZS)
	xand %a0, %a0, 0xf
	add  %A, %a0
	xand %A, %A, HF
	or   %F, %A
	;
	ret.d
	swap %A, %t0			; %A = A+r *delay*

;
;	ADC A, r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is set if carry from bit 3, reset otherwise
;	P/V	is set if overflow, reset otherwise
;	N	is reset
;	C	is set if carry from bit 7: reset otherwise
;
; [in]
;	%a0	r
;
	.global z80cpu_adc8
z80cpu_adc8:
	ld.w  %t2, %psr			; %t2 = F(C)
	xand  %t2, %t2, ~CF
	xand  %F, %F, CF
	or    %t2, %F
	;
	swap  %t0, %A			; %t0[31:24] = A
	swap  %t1, %a0			; %t1[31:24] = r
	xoor  %t1, %t1, (1<<24)-1	; %t1[23: 0] = 0xffffff
	ld.w  %psr, %t2			; %t0[31:24] = A+r+F(C)
	adc   %t0, %t1
	;
	ld.w  %F, %psr			; %F = F(00CP0S)
	xand  %F, %F, CF|PF|SF		; (%t0[23:0]不定のため、%psr(Z)は未確定です)
	xand  %A, %A, 0xf		; %F = F(0HCP0S)
	xand  %a0, %a0, 0xf
	ld.w  %psr, %t2
	adc   %A, %a0
	xand  %A, %A, HF
	or    %F, %A
	;
	swap  %A, %t0			; %A[7:0] = A+r+F(C)
	ld.ub %A, %A			; %A = A+r+F(C)
	or    %A, %A			; %F = F(0HCPZS)
	jrne  2
	add   %F, ZF			; (skip?)
	ret

;
;	SUB r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is set if borrow from bit 4, reset otherwise
;	P/V	is set if overflow, reset otherwise
;	N	is set
;	C	is set if borrow, reset otherwise
;
; [in]
;	%a0	r
;
	.global z80cpu_sub8
z80cpu_sub8:
	swap %t0, %A			; %t0[31:24] = A
	swap %t1, %a0			; %t1[31:24] = r
	sub  %t0, %t1			; %t0[31:24] = A-r
	;
	ld.w %F, %psr			; %F = F(00CPZS)
	xand %F, %F, CF|PF|ZF|SF
	xadd %F, %F, NF			; %F = F(N0CPZS)
	xand %A, %A, 0xf		; %F = F(NHCPZS)
	xand %a0, %a0, 0xf
	sub  %A, %a0
	xand %A, %A, HF
	or   %F, %A
	;
	ret.d
	swap %A, %t0			; %A = A-r *delay*

;
;	SBC A, r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is set if borrow from bit 4, reset otherwise
;	P/V	is reset if overflow, reset otherwise
;	N	is set
;	C	is set if borrow, reset otherwise
;
; [in]
;	%a0	r
;
	.global z80cpu_sbc8
z80cpu_sbc8:
	ld.w  %t2, %psr			; %t2 = F(C)
	xand  %t2, %t2, ~CF
	xand  %F, %F, CF
	or    %t2, %F
	;
	swap  %t0, %A			; %t0[31:24] = A
	swap  %t1, %a0			; %t1[31:24] = r
	ld.w  %psr, %t2			; %t0[31:24] = A-r-F(C)
	sbc   %t0, %t1
	;
	ld.w  %F, %psr			; %F = F(00CP0S)
	xand  %F, %F, CF|PF|SF		; (%t0[23:0]不定のため、%psr(Z)は未確定です)
	xadd  %F, %F, NF		; %F = F(N0CP0S)
	xand  %A, %A, 0xf		; %F = F(NHCP0S)
	xand  %a0, %a0, 0xf
	ld.w  %psr, %t2
	sbc   %A, %a0
	xand  %A, %A, HF
	or    %F, %A
	;
	swap  %A, %t0			; %A[7:0] = A-r-F(C)
	ld.ub %A, %A			; %A = A-r-F(C)
	or    %A, %A			; %F = F(NHCPZS)
	jrne  2
	add   %F, ZF			; (skip?)
	ret

;
;	AND r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is set
;	P/V	is set if parity is even, reset otherwise
;	N	is reset
;	C	is reset
;
; [in]
;	%a0	r
;
	.global z80cpu_and
z80cpu_and:
	swap  %t0, %A			; %t0[31:24] = A
	swap  %t1, %a0			; %t1[31:24] = r
	and   %t0, %t1			; %t0[31:24] = A&r
	;
	ld.w  %F, %psr			; %F = F(0000ZS)
	xand  %F, %F, ZF|SF
	xadd  %F, %F, HF		; %F = F(0N00ZS)
	swap  %A, %t0			; %A = A&r
	ext z80cpu_parity@ah		; %F = F(0N0PZS)
	ext z80cpu_parity@al
	ld.ub %t0, [%A]
	ret.d
	or    %F, %t0			; *delay*

;
;	OR r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is reset
;	P/V	is set if parity is even, reset otherwise
;	N	is reset
;	C	is reset
;
; [in]
;	%a0	r
;
	.global z80cpu_or
z80cpu_or:
	swap  %t0, %A			; %t0[31:24] = A
	swap  %t1, %a0			; %t1[31:24] = r
	or    %t0, %t1			; %t0[31:24] = A|r
	;
	ld.w  %F, %psr			; %F = F(0000ZS)
	xand  %F, %F, ZF|SF
	swap  %A, %t0			; %A = A|r
	ext z80cpu_parity@ah		; %F = F(000PZS)
	ext z80cpu_parity@al
	ld.ub %t0, [%A]
	ret.d
	or    %F, %t0			; *delay*

;
;	XOR r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is reset
;	P/V	is set if parity is even, reset otherwise
;	N	is reset
;	C	is reset
;
; [in]
;	%a0	r
;
	.global z80cpu_xor
z80cpu_xor:
	swap  %t0, %A			; %t0[31:24] = A
	swap  %t1, %a0			; %t1[31:24] = r
	xor   %t0, %t1			; %t0[31:24] = A^r
	;
	ld.w  %F, %psr			; %F = F(0000ZS)
	xand  %F, %F, ZF|SF
	swap  %A, %t0			; %A = A^r
	ext z80cpu_parity@ah		; %F = F(000PZS)
	ext z80cpu_parity@al
	ld.ub %t0, [%A]
	ret.d
	or    %F, %t0			; *delay*

;
;	CP r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is set if borrow from bit 4, reset otherwise
;	P/V	is set if overflow, reset otherwise
;	N	is set
;	C	is set if borrow, reset otherwise
;
; [in]
;	%a0	r
;
	.global z80cpu_cp
z80cpu_cp:
	swap %t0, %A			; %t0[31:24] = A
	swap %t1, %a0			; %t1[31:24] = r
	cmp  %t0, %t1			; %t0[31:24] = A-r
	;
	ld.w %F, %psr			; %F = F(00CPZS)
	xand %F, %F, CF|PF|ZF|SF
	xadd %F, %F, NF			; %F = F(N0CPZS)
	xand %t0, %A, 0xf		; %F = F(NHCPZS)
	xand %a0, %a0, 0xf
	sub  %t0, %a0
	xand %t0, %t0, HF
	;
	ret.d
	or   %F, %t0			; *delay*

;
;	INC r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is set if carry from bit 3, reset otherwise
;	P/V	is set if r was 7FH before operation, reset otherwise
;	N	is reset
;	C	is not affected
;
; [in]
;	%a0	r
; [out]
;	%a0	r+1
;
	.global z80cpu_inc8
z80cpu_inc8:
	xand %t1, %F, CF		; %t1 = F(00C0000)
	swap %t0, %a0			; %t0[31:24] = r
	xadd %t0, %t0, 1<<24		; %t0[31:24] = r+1
	;
	ld.w %F, %psr			; %F = F(000PZS)
	xand %F, %F, PF|ZF|SF
	xand %a0, %a0, 0xf		; %F = F(0H0PZS)
	xadd %a0, %a0, 1
	xand %a0, %a0, HF
	or   %F, %a0
	or   %F, %t1			; %F = F(0HCPZS)
	;
	ret.d
	swap %a0, %t0			; %a0 = r+1 *delay*

;
;	DEC r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is set if borrow from bit 4, reset otherwise
;	P/V	is set if m was 80H before operation, reset otherwise
;	N	is set
;	C	is not affected
;
; [in]
;	%a0	r
; [out]
;	%a0	r-1
;
	.global z80cpu_dec8
z80cpu_dec8:
	xand %t1, %F, CF		; %t1 = F(00C0000)
	swap %t0, %a0			; %t0[31:24] = r
	xsub %t0, %t0, 1<<24		; %t0[31:24] = r-1
	;
	ld.w %F, %psr			; %F = F(000PZS)
	xand %F, %F, PF|ZF|SF
	xadd %F, %F, NF			; %F = F(N00PZS)
	xand %a0, %a0, 0xf		; %F = F(NH0PZS)
	xsub %a0, %a0, 1
	xand %a0, %a0, HF
	or   %F, %a0
	or   %F, %t1			; %F = F(NHCPZS)
	;
	ret.d
	swap %a0, %t0			; %a0 = r-1 *delay*

;****************************************************************************
;	16-Bit Arithmetic Group
;****************************************************************************

;
;	ADD rr, ss
;
;	S	is not affected
;	Z	is not affected
;	H	is set if carry out of bit 11, reset otherwise
;	P/V	is not affected
;	N	is reset
;	C	is set if carry from bit 15, reset otherwise
;
; [in]
;	%a0	rr
;	%a1	ss
; [out]
;	%a0	rr+ss
;
	.global z80cpu_add16
z80cpu_add16:
	xand %t2, %F, PF|ZF|SF		; %t2 = F(000PZS)
	ld.w %t0, %a0			; %t0[31:16] = rr
	xsll %t0, 16
	ld.w %t1, %a1			; %t1[31:16] = ss
	xsll %t1, 16
	add  %t0, %t1			; %t0[31:16] = rr+ss
	;
	ld.w %F, %psr			; %F = F(00C000)
	xand %F, %F, CF
	xand %a0, %a0, 0xfff		; %F = F(0HC000)
	xand %a1, %a1, 0xfff
	add  %a0, %a1
	xsrl %a0, 8
	xand %a0, %a0, HF
	or   %F, %a0
	or   %F, %t2			; %F = F(0HCPZS)
	;
	xsrl %t0, 16			; %t0 = rr+ss
	ret.d
	ld.w %a0, %t0			; %a0 = rr+ss *delay*

;
;	ADC rr, ss
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is set if carry out of bit 11, reset otherwise
;	P/V	is set if overflow, reset otherwise
;	N	is reset
;	C	is set if carry from bit 15, reset otherwise
;
; [in]
;	%a0	rr
;	%a1	ss
; [out]
;	%a0	rr+ss+F(C)
;
	.global z80cpu_adc16
z80cpu_adc16:
	ld.w %t2, %psr			; %t2 = F(C)
	xand %t2, %t2, ~CF
	xand %F, %F, CF
	or   %t2, %F
	;
	ld.w %t0, %a0			; %t0[31:16] = rr
	xsll %t0, 16
	ld.w %t1, %a1			; %t1[31:16] = ss
	xsll %t1, 16
	xoor %t1, %t1, (1<<16)-1	; %t1[15: 0] = 0xffff
	ld.w %psr, %t2			; %t0[31:16] = rr+ss+F(C)
	adc  %t0, %t1
	;
	ld.w %F, %psr			; %F = F(00CP0S)
	xand %F, %F, CF|PF|SF		; (%t0[15:0]不定のため、%psr(Z)は未確定です)
	xand %a0, %a0, 0xfff		; %F = F(0HCP0S)
	xand %a1, %a1, 0xfff
	ld.w %psr, %t2
	adc  %a0, %a1
	xsrl %a0, 8
	xand %a0, %a0, HF
	or   %F, %a0
	;
	xsrl %t0, 16			; %t0 = rr+ss+F(C)
	jrne 2				; %F = F(0HCPZS)
	add  %F, ZF			; (skip?)
	ret.d
	ld.w %a0, %t0			; %a0 = rr+ss+F(C) *delay*

;
;	SBC rr, ss
;
;	S is set if result is negative, reset otherwise
;	Z is set if result is zero, reset otherwise
;	H is set if a borrow from bit 12, reset otherwise
;	P/V is set if overflow, reset otherwise
;	N is set
;	C is set if borrow, reset otherwise
;
; [in]
;	%a0	rr
;	%a1	ss
; [out]
;	%a0	rr-ss-F(C)
;
	.global z80cpu_sbc16
z80cpu_sbc16:
	ld.w %t2, %psr			; %t2 = F(C)
	xand %t2, %t2, ~CF
	xand %F, %F, CF
	or   %t2, %F
	;
	ld.w %t0, %a0			; %t0[31:16] = rr
	xsll %t0, 16
	ld.w %t1, %a1			; %t1[31:16] = ss
	xsll %t1, 16
	ld.w %psr, %t2			; %t0[31:16] = rr-ss-F(C)
	sbc  %t0, %t1
	;
	ld.w %F, %psr			; %F = F(00CP0S)
	xand %F, %F, CF|PF|SF		; (%t0[15:0]不定のため、%psr(Z)は未確定です)
	xadd %F, %F, NF			; %F = F(N0CP0S)
	xand %a0, %a0, 0xfff		; %F = F(NHCP0S)
	xand %a1, %a1, 0xfff
	ld.w %psr, %t2
	sbc  %a0, %a1
	xsrl %a0, 8
	xand %a0, %a0, HF
	or   %F, %a0
	;
	xsrl %t0, 16			; %t0 = rr-ss-F(C)
	jrne 2				; %F = F(NHCPZS)
	add  %F, ZF			; (skip?)
	ret.d
	ld.w %a0, %t0			; %a0 = rr-ss-F(C) *delay*

;****************************************************************************
;	Rotate and Shift Group
;****************************************************************************

;
;	RL r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is reset
;	P/V	is set if parity is even, reset otherwise
;	N	is reset
;	C	is data from bit 7 of source register
;
; [in]
;	%a0	r
; [out]
;	%a0	RL r
;
	.global z80cpu_rl
z80cpu_rl:
;;	ld.w  %t0, %a0			; %t0 = 0:rrrrrrrr
;;	xsll  %a0, 1			; %a0 = r:rrrrrrr0
;;	xand  %F, %F, CF		; %F  = 0:0000C000
;;	xsrl  %F, 3-0			; %F  = 0:0000000C
;;	or    %a0, %F			; %a0 = r:rrrrrrrC
;;	ld.b  %a0, %a0			; %a0 = ?:rrrrrrrC (signed)
;;	or    %a0, %a0			; (%psrへ反映するために必要です)
;;	;
;;	ld.w  %F, %psr			; %F  = F(000000ZS)
;;	and   %F, ZF|SF
;;	xsrl  %t0, 7-3			; %t0 = 0:0000rrrr
;;	xand  %t0, %t0, CF		; %t0 = 0:0000r000
;;	or    %F, %t0			; %F  = F(0000C0ZS)
;;	ld.ub %a0, %a0			; %a0 = 0:rrrrrrrC (unsigned)
;;	ext z80cpu_parity@ah		; %t0 = F(00000P00)
;;	ext z80cpu_parity@al
;;	ld.ub %t0, [%a0]
;;	ret.d
;;	or    %F, %t0			; %F  = F(0000CPZS) *delay*
;;↓僅かに高速化しました。たぶん大丈夫だと思うけれど、しばらく様子見です。
	ld.w  %t0, %a0			; %t0 = 0:rrrrrrrr
	xsll  %a0, 1			; %a0 = r:rrrrrrr0          -+- この二行を逆にすると間違いです。
	ld.b  %a0, %a0			; %a0 = ?:rrrrrrr0 (signed) -+  逆にしないよう注意してください!!
	xand  %F, %F, CF		; %F  = 0:0000C000
	xsrl  %F, 3-0			; %F  = 0:0000000C
	or    %a0, %F			; %a0 = ?:rrrrrrrC (signed)
	;
	ld.w  %F, %psr			; %F  = F(000000ZS)
	and   %F, ZF|SF
	xsrl  %t0, 7-3			; %t0 = 0:0000rrrr
	xand  %t0, %t0, CF		; %t0 = 0:0000r000
	or    %F, %t0			; %F  = F(0000C0ZS)
	ld.ub %a0, %a0			; %a0 = 0:rrrrrrrC (unsigned)
	ext z80cpu_parity@ah		; %t0 = F(00000P00)
	ext z80cpu_parity@al
	ld.ub %t0, [%a0]
	ret.d
	or    %F, %t0			; %F  = F(0000CPZS) *delay*

;
;	RLC r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is reset
;	P/V	is set if parity is even, reset otherwise
;	N	is reset
;	C	is data from bit 7 of source register
;
; [in]
;	%a0	r
; [out]
;	%a0	RLC r
;
	.global z80cpu_rlc
z80cpu_rlc:
;;	ld.w  %t0, %a0			; %t0 = 0:rrrrrrrr
;;	ld.w  %t1, %a0			; %t1 = 0:rrrrrrrr
;;	xsll  %a0, 1			; %a0 = r:rrrrrrr0
;;	xsrl  %t1, 7			; %t1 = 0:0000000r
;;	or    %a0, %t1			; %a0 = r:rrrrrrrr
;;	ld.b  %a0, %a0			; %a0 = ?:rrrrrrrr (signed)
;;	or    %a0, %a0			; (%psrへ反映するために必要です)
;;	;
;;	ld.w  %F, %psr			; %F  = F(000000ZS)
;;	and   %F, ZF|SF
;;	xsrl  %t0, 7-3			; %t0 = 0:0000rrrr
;;	xand  %t0, %t0, CF		; %t0 = 0:0000r000
;;	or    %F, %t0			; %F  = F(0000C0ZS)
;;	ld.ub %a0, %a0			; %a0 = 0:rrrrrrrC (unsigned)
;;	ext z80cpu_parity@ah		; %t0 = F(00000P00)
;;	ext z80cpu_parity@al
;;	ld.ub %t0, [%a0]
;;	ret.d
;;	or    %F, %t0			; %F  = F(0000CPZS) *delay*
;;↓僅かに高速化しました。たぶん大丈夫だと思うけれど、しばらく様子見です。
	ld.w  %t0, %a0			; %t0 = 0:rrrrrrrr
	ld.w  %t1, %a0			; %t1 = 0:rrrrrrrr
	xsll  %a0, 1			; %a0 = r:rrrrrrr0          -+- この二行を逆にすると間違いです。
	ld.b  %a0, %a0			; %a0 = ?:rrrrrrr0 (signed) -+  逆にしないよう注意してください!!
	xsrl  %t1, 7			; %t1 = 0:0000000r
	or    %a0, %t1			; %a0 = ?:rrrrrrrr (signed)
	;
	ld.w  %F, %psr			; %F  = F(000000ZS)
	and   %F, ZF|SF
	xsrl  %t0, 7-3			; %t0 = 0:0000rrrr
	xand  %t0, %t0, CF		; %t0 = 0:0000r000
	or    %F, %t0			; %F  = F(0000C0ZS)
	ld.ub %a0, %a0			; %a0 = 0:rrrrrrrC (unsigned)
	ext z80cpu_parity@ah		; %t0 = F(00000P00)
	ext z80cpu_parity@al
	ld.ub %t0, [%a0]
	ret.d
	or    %F, %t0			; %F  = F(0000CPZS) *delay*

;
;	RR r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is reset
;	P/V	is set if parity is even, reset otherwise
;	N	is reset
;	C	is data from bit 0 of source register
;
; [in]
;	%a0	r
; [out]
;	%a0	RR r
;
	.global z80cpu_rr
z80cpu_rr:
;;	ld.w  %t0, %a0			; %t0 = 0:rrrrrrrr
;;	xsrl  %a0, 1			; %a0 = 0:0rrrrrrr
;;	xand  %F, %F, CF		; %F  = 0:0000C000
;;	xsll  %F, 7-3			; %F  = 0:C0000000
;;	or    %a0, %F			; %a0 = 0:Crrrrrrr
;;	ld.b  %a0, %a0			; %a0 = ?:Crrrrrrr (signed)
;;	or    %a0, %a0			; (%psrへ反映するために必要です)
;;	;
;;	ld.w  %F, %psr			; %F  = F(000000ZS)
;;	and   %F, ZF|SF
;;	xsll  %t0, 3-0			; %t0 = r:rrrrr000
;;	xand  %t0, %t0, CF		; %t0 = 0:0000r000
;;	or    %F, %t0			; %F  = F(0000C0ZS)
;;	ld.ub %a0, %a0			; %a0 = 0:Crrrrrrr (unsigned)
;;	ext z80cpu_parity@ah		; %t0 = F(00000P00)
;;	ext z80cpu_parity@al
;;	ld.ub %t0, [%a0]
;;	ret.d
;;	or    %F, %t0			; %F  = F(0000CPZS) *delay*
;;↓僅かに高速化しました。たぶん大丈夫だと思うけれど、しばらく様子見です。
	ld.w  %t0, %a0			; %t0 = 0:rrrrrrrr
	xsrl  %a0, 1			; %a0 = 0:0rrrrrrr
	xand  %F, %F, CF		; %F  = 0:0000C000
	xsll  %F, 7-3			; %F  = 0:C0000000          -+- この二行を逆にすると間違いです。
	ld.b  %F, %F			; %F  = ?:C0000000 (signed) -+  逆にしないよう注意してください!!
	or    %a0, %F			; %a0 = ?:Crrrrrrr (signed)
	;
	ld.w  %F, %psr			; %F  = F(000000ZS)
	and   %F, ZF|SF
	xsll  %t0, 3-0			; %t0 = r:rrrrr000
	xand  %t0, %t0, CF		; %t0 = 0:0000r000
	or    %F, %t0			; %F  = F(0000C0ZS)
	ld.ub %a0, %a0			; %a0 = 0:Crrrrrrr (unsigned)
	ext z80cpu_parity@ah		; %t0 = F(00000P00)
	ext z80cpu_parity@al
	ld.ub %t0, [%a0]
	ret.d
	or    %F, %t0			; %F  = F(0000CPZS) *delay*

;
;	RRC r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is reset
;	P/V	is set if parity is even, reset otherwise
;	N	is reset
;	C	is data from bit 0 of source register
;
; [in]
;	%a0	r
; [out]
;	%a0	RRC r
;
	.global z80cpu_rrc
z80cpu_rrc:
;;	ld.w  %t0, %a0			; %t0 = 0:rrrrrrrr
;;	ld.w  %t1, %a0			; %t1 = 0:rrrrrrrr
;;	xsrl  %a0, 1			; %a0 = 0:0rrrrrrr
;;	xsll  %t1, 7			; %t1 = r:r0000000
;;	or    %a0, %t1			; %a0 = r:rrrrrrrr
;;	ld.b  %a0, %a0			; %a0 = ?:rrrrrrrr (signed)
;;	or    %a0, %a0			; (%psrへ反映するために必要です)
;;	;
;;	ld.w  %F, %psr			; %F  = F(000000ZS)
;;	and   %F, ZF|SF
;;	xsll  %t0, 3-0			; %t0 = r:rrrrr000
;;	xand  %t0, %t0, CF		; %t0 = 0:0000r000
;;	or    %F, %t0			; %F  = F(0000C0ZS)
;;	ld.ub %a0, %a0			; %a0 = 0:Crrrrrrr (unsigned)
;;	ext z80cpu_parity@ah		; %t0 = F(00000P00)
;;	ext z80cpu_parity@al
;;	ld.ub %t0, [%a0]
;;	ret.d
;;	or    %F, %t0			; %F  = F(0000CPZS) *delay*
;;↓僅かに高速化しました。たぶん大丈夫だと思うけれど、しばらく様子見です。
	ld.w  %t0, %a0			; %t0 = 0:rrrrrrrr
	ld.w  %t1, %a0			; %t1 = 0:rrrrrrrr
	xsrl  %a0, 1			; %a0 = 0:0rrrrrrr
	xsll  %t1, 7			; %t1 = r:r0000000          -+- この二行を逆にすると間違いです。
	ld.b  %t1, %t1			; %t1 = ?:r0000000 (signed) -+  逆にしないよう注意してください!!
	or    %a0, %t1			; %a0 = ?:rrrrrrrr (signed)
	;
	ld.w  %F, %psr			; %F  = F(000000ZS)
	and   %F, ZF|SF
	xsll  %t0, 3-0			; %t0 = r:rrrrr000
	xand  %t0, %t0, CF		; %t0 = 0:0000r000
	or    %F, %t0			; %F  = F(0000C0ZS)
	ld.ub %a0, %a0			; %a0 = 0:Crrrrrrr (unsigned)
	ext z80cpu_parity@ah		; %t0 = F(00000P00)
	ext z80cpu_parity@al
	ld.ub %t0, [%a0]
	ret.d
	or    %F, %t0			; %F  = F(0000CPZS) *delay*

;
;	SLA r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is reset
;	P/V	is set if parity is even, reset otherwise
;	N	is reset
;	C	is data from bit 7
;
; [in]
;	%a0	r
; [out]
;	%a0	SLA r
;
	.global z80cpu_sla
z80cpu_sla:
	ld.w  %t0, %a0			; %t0 = 0:rrrrrrrr
	xsll  %a0, 1			; %a0 = r:rrrrrrr0
	ld.b  %a0, %a0			; %a0 = ?:rrrrrrr0 (signed)
	or    %a0, %a0			; (%psrへ反映するために必要です)
	;
	ld.w  %F, %psr			; %F  = F(000000ZS)
	and   %F, ZF|SF
	xsrl  %t0, 7-3			; %t0 = 0:0000rrrr
	xand  %t0, %t0, CF		; %t0 = 0:0000r000
	or    %F, %t0			; %F  = F(0000C0ZS)
	ld.ub %a0, %a0			; %a0 = 0:rrrrrrr0 (unsigned)
	ext z80cpu_parity@ah		; %t0 = F(00000P00)
	ext z80cpu_parity@al
	ld.ub %t0, [%a0]
	ret.d
	or    %F, %t0			; %F  = F(0000CPZS) *delay*

;
;	SRA r
;
;	S	is set if result is negative, reset otherwise
;	Z	is set if result is zero, reset otherwise
;	H	is reset
;	P/V	is set if parity is even, reset otherwise
;	N	is reset
;	C	is data from bit 0 of source register
;
; [in]
;	%a0	r
; [out]
;	%a0	SRA r
;
	.global z80cpu_sra
z80cpu_sra:
	ld.w  %t0, %a0			; %t0 = 0:rrrrrrrr
	ld.b  %a0, %a0			; %a0 = ?:rrrrrrrr (signed) -+- この二行を逆にすると間違いです。
	xsra  %a0, 1			; %a0 = ?:?rrrrrrr (signed) -+  逆にしないよう注意してください!!
	;
	ld.w  %F, %psr			; %F  = F(000000ZS)
	and   %F, ZF|SF
	xsll  %t0, 3-0			; %t0 = r:rrrrr000
	xand  %t0, %t0, CF		; %t0 = 0:0000r000
	or    %F, %t0			; %F  = F(0000C0ZS)
	ld.ub %a0, %a0			; %a0 = 0:?rrrrrrr (unsigned)
	ext z80cpu_parity@ah		; %t0 = F(00000P00)
	ext z80cpu_parity@al
	ld.ub %t0, [%a0]
	ret.d
	or    %F, %t0			; %F  = F(0000CPZS) *delay*

;
;	SRL r
;
;	S	is reset
;	Z	is set if result is zero, reset otherwise
;	H	is reset
;	P/V	is set if parity is even, reset otherwise
;	N	is reset
;	C	is data from bit 0 of source register
;
; [in]
;	%a0	r
; [out]
;	%a0	SRL r
;
	.global z80cpu_srl
z80cpu_srl:
	ld.w %t0, %a0			; %t0 = 0:rrrrrrrr
	xsrl %a0, 1			; %a0 = 0:0rrrrrrr
	;
	ld.w  %F, %psr			; %F  = F(000000ZS)
	and   %F, ZF|SF
	xsll  %t0, 3-0			; %t0 = r:rrrrr000
	xand  %t0, %t0, CF		; %t0 = 0:0000r000
	or    %F, %t0			; %F  = F(0000C0ZS)
	ext z80cpu_parity@ah		; %t0 = F(00000P00)
	ext z80cpu_parity@al
	ld.ub %t0, [%a0]
	ret.d
	or    %F, %t0			; %F  = F(0000CPZS) *delay*

;****************************************************************************
;	Bit Set, Reset, and Test Group
;****************************************************************************

;
;	BIT b, r
;
;	S	is unknown
;		  ↓Undoc'd
;		  (b=7)かつ(r[7]=1)の場合にset、さもなくばresetされます。
;		  SG-1000用チョップリフターは、この挙動に依存しています。
;	Z	is set if specified bit is 0, reset otherwise
;	H	is set
;	P/V	is unknown
;		  ↓Undoc'd
;		  Zフラグと同じ値になります。
;	N	is reset
;	C	is not affected
;
; [in]
;	%a0	b
;	%a1	r
;
	.global z80cpu_bit
z80cpu_bit:
	xand  %F, %F, CF		; %F = F(00C000)
	xadd  %F, %F, HF		; %F = F(0HC000)
	;
	xld.w %t0, 1<<24		; %t0[31:24] = 1<<b
	sll   %t0, %a0			; (0≦%a0≦7なので、xsllは必要ありません)
	swap  %a1, %a1			; %a1[31:24] = r
	and   %a1, %t0			; %a1[31:24] = r&(1<<b)
	;
	ld.w  %t0, %psr
	jrne.d 3
	and   %t0, ZF|SF		; %t0 = F(0000ZS) *delay*
	add   %t0, PF			; %t0 = F(000PZS) (skip?)
	;
	ret.d
	or    %F, %t0			; %F  = F(0HCPZS) *delay*

;****************************************************************************
;	Input and Output Group
;****************************************************************************

;
;	IN r, (C)
;
;	S	is set if input data is negative, reset otherwise
;	Z	is set if input data is zero, reset otherwise
;	H	is reset
;	P/V	is set if parity is even, reset otherwise
;	N	is reset
;	C	is not affected
;
; [out]
;	%a0	r
;
; [note]
;	* %a0 は %r10 の別名です。
;	  誤って破壊しないよう、注意してください。
;
	.global z80cpu_in
z80cpu_in:
	xsub   %sp, %sp, 8
	xld.w [%sp+0], %s0		; %r6退避
	xld.w [%sp+4], %s1		; %r7退避
	;
	xld.w  %r11, [%CPU+IN]		; %r11 = IN
	xld.uh %r12, [%CPU+BC]		; %r12 = BC (アドレスバスのbit15-8にはBレジスタの値が出力されます)
	call   %r11			; %r10 = IN (C)
	ld.ub  %a0, %r10		; (戻り値のbit31-8をClear。必要です!!)
	xld.w  %CPU, z80cpu		; %r4復元
	xld.w  %MEM, z80mem		; %r5復元
	;
	xand   %F, %F, CF		; %F  = F(00C000)
	ld.b   %t0, %a0			; %t0 = IN (C) (signed)
	or     %t0, %t0			; (%psrへ反映するために必要です)
	ld.w   %t0, %psr		; %t0 = F(0000ZS)
	xand   %t0, %t0, ZF|SF
	or     %F, %t0			; %F  = F(00C0ZS)
	ext z80cpu_parity@ah		; %t0 = F(000P00)
	ext z80cpu_parity@al
	ld.ub  %t0, [%a0]
	or     %F, %t0			; %F  = F(00CPZS)
	;
	xld.w  %s0, [%sp+0]		; %r6復元
	xld.w  %s1, [%sp+4]		; %r6復元
	xadd   %sp, %sp, 8
	ret

;
;	OUT (C), r
;
;	Condition Bits Affected: None
;
; [in]
;	%a0	r
;
; [note]
;	* %a0 は %r10 の別名です。
;	  誤って破壊しないよう、注意してください。
;
	.global z80cpu_out
z80cpu_out:
	xsub   %sp, %sp, 8
	xld.w [%sp+0], %s0		; %r6退避
	xld.w [%sp+4], %s1		; %r7退避
	;
	xld.w  %r11, [%CPU+OUT]		; %r11 = OUT
	xld.uh %r12, [%CPU+BC]		; %r12 = BC (アドレスバスのbit15-8にはBレジスタの値が出力されます)
	call.d %r11			; OUT (C), r
	ld.w   %r13, %a0		; %r13 = r *delay*
	xld.w  %CPU, z80cpu		; %r4復元
	xld.w  %MEM, z80mem		; %r5復元
	;
	xld.w  %s0, [%sp+0]		; %r6復元
	xld.w  %s1, [%sp+4]		; %r6復元
	xadd   %sp, %sp, 8
	ret

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