;
;	frams26a.s
;
;	P/ECE Signetics 2650 Emulator
;
;	CLiP - Common Library for P/ECE
;	Copyright (C) 2001-2005 Naoyuki Sawa
;
;	* Mon Apr 25 20:42:00 JST 2005 Naoyuki Sawa
;	- 作成開始。
;
#include "clips26a.h"

/* S2650_TRACEシンボルを定義すると、トレース出力を行います。 */
//#define S2650_TRACE

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

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

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

	.code
	.align 1

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

; 実行コンテキストへ入ります。
; [in]
;	ありません。
; [out]
;	規定のレジスタを設定します。
; [use]
;	規定のレジスタを設定すること以外は、全レジスタを保存します。
; [note]
;	* 実行コンテキスト外からのみ呼び出し可能です。
;	  このルーチンを呼び出すと、実行コンテキストへ入ります。
;
	.global	s2650_enter
s2650_enter:
	xld.w	%CPU  , s2650
	xld.uh	%CC   , [%CPU+_CC_   ]
	xld.uh	%IAR  , [%CPU+_IAR_  ]
	xld.w	%CYCLE, [%CPU+_CYCLE_]
	ret

; 実行コンテキストを抜けます。
; [in]
;	規定のレジスタが設定されていること。
; [out]
;	ありません。
; [use]
;	全レジスタを保存します。
; [note]
;	* 実行コンテキスト内からのみ呼び出し可能です。
;	  このルーチンを呼び出すと、実行コンテキストを抜けます。
;
	.global	s2650_leave
s2650_leave:
	xld.h	[%CPU+_CC_   ], %CC
	xld.h	[%CPU+_IAR_  ], %IAR
	xld.w	[%CPU+_CYCLE_], %CYCLE
	ret

;****************************************************************************
;	実行コンテキスト外から利用する関数
;****************************************************************************

	.global	s2650_run
s2650_run:
	pushn	%r3
	xld.w	[s2650+_CYCLE_], %r12		; 残りサイクル数を格納します。必要!!
	xcall	s2650_enter			; 実行コンテキストへ入ります。
	;
	xbtst	[%CPU+FLAGS], FLAGS_HALT	; 既にHALT中ならば、残り実行サイクル数を0にして、すぐにループを抜けます。
	jreq	2				; (s2650.cycle=0で関数を抜けること。必須!!)
	ld.w	%CYCLE, 0			; (skip?)
	;
	xjp	s2650_run_LOOP			; 実行サイクル数≦0が指定された場合のために、まず条件判定から。
s2650_run_DO:
;----------------------------------------------------------------------------
#ifdef S2650_TRACE
	; トレースデバッグを行う場合は、このブロックを有効にしてください。
	; その際、s2650_trace()は、アプリケーションにて定義してください。
	; s2650_trace()は、ライブラリ内では定義していません。
	xcall  s2650_leave
	xcall  s2650_trace
	xcall  s2650_enter
#endif /*S2650_TRACE*/
;----------------------------------------------------------------------------
	xcall.d	s2650_read			; %r10 = OpCode = [IAR++]
	ld.w	%r12, %IAR			; *delay*
	add	%IAR, 1
	xsll	%r10, 4				; %seq = &s2650seq[OpCode].cycle
	ext	s2650seq+3@ah
	ext	s2650seq+3@al
	add	%seq, %r10
	ld.ub	%r9, [%seq]+			; %r9  = 消費サイクル数
	ld.w	%r10, [%seq]+			; %r10 = 最初の関数
	call.d	%r10				; シーケンスの、最初の関数を呼びます。
	sub	%CYCLE, %r9			; 残り実行サイクル数を減らします。(命令実行前に減らす!!)
s2650_run_LOOP:
	xcmp	%CYCLE, 0			; 残り実行サイクル数が0以下になるまで繰り返します。
	xjrgt	s2650_run_DO
	;
	xcall	s2650_leave			; 実行コンテキストを抜けます。
	popn	%r3
	ret

;****************************************************************************
;	実行コンテキスト内から利用する関数
;****************************************************************************

	.global	s2650_get_psu
s2650_get_psu:
	xld.ub	%data, [%CPU+PSU]		; %data = S|F|II|-|-|  -|  -|  -
	xld.ub	%r9, [%CPU+SP]			; %r9   = 0|0| 0|0|0| SP| SP| SP
	xand	%data, %data, 0xe0		; %data = S|F|II|0|0|  0|  0|  0
	ret.d
	or	%data, %r9			; %data = S|F|II|0|0| SP| SP| SP	*delay*

	.global	s2650_set_psu
s2650_set_psu:
	xld.ub	%r9, [%CPU+PSU]			; %r9   = S|-|--|-|-|---|---|---
	xand	%r9, %r9, 0x80			; %r9   = S|0| 0|0|0|  0|  0|  0
	xand	%data, %data, ~0x80		; %data = 0|F|II|-|-|SP2|SP1|SP0
	or	%data, %r9			; %data = S|F|II|-|-|SP2|SP1|SP0
	xld.b	[%CPU+PSU], %data
	xand	%data, %data, 7			; %data = 0|0| 0|0|0|SP2|SP1|SP0
	xld.b	[%CPU+SP], %data
	ret

	.global	s2650_get_psl
s2650_get_psl:
	xld.ub	%data, [%CPU+PSL]		; %data = ---|---|---|RS|WC|---|COM|-
	xand	%data, %data, 0x1a		; %data =   0|  0|  0|RS|WC|  0|COM|0
	xbtst	[%CPU+C+1], 0
	jreq	2
	add	%data, 0x01			; %data =   0|  0|  0|RS|WC|  0|COM|C	(skip?)
	xbtst	[%CPU+OVF], 7
	jreq	2
	add	%data, 0x04			; %data =   0|  0|  0|RS|WC|OVF|COM|C	(skip?)
	xbtst	[%CPU+IDC], 4
	jreq	2
	add	%data, 0x20			; %data =   0|  0|IDC|RS|WC|OVF|COM|C	(skip?)
	xcmp	%CC, 0x00
	xjreq	s2650_get_psl_EXIT
	xadd	%data, %data, 0x40		; %data =   0|CC0|IDC|RS|WC|OVF|COM|C
	xcmp	%CC, 0x80
	xjrlt	s2650_get_psl_EXIT
	xadd	%data, %data, 0x40		; %data = CC1|  0|IDC|RS|WC|OVF|COM|C
	xcmp	%CC, 0x100
	xjrlt	s2650_get_psl_EXIT
	xadd	%data, %data, 0x40		; %data = CC1|CC0|IDC|RS|WC|OVF|COM|C
s2650_get_psl_EXIT:
	ret

	.global	s2650_set_psl
s2650_set_psl:
	xld.b	[%CPU+PSL], %data		; PSL   =   ---|---|---|RS|WC|---|COM|-
	xld.b	[%CPU+C+1], %data		; C     =   ---|---|---|--|--|---|---|C|-|-|-|-|-|-|-|-
	xsll	%data, 5			; %data =   CC1|CC0|IDC|RS|WC|OVF|COM|C|0|0|0|0|0
	xld.b	[%CPU+OVF], %data		; OVF   =                     OVF|---|-|-|-|-|-|-
	xsrl	%data, 6			; %data = 0|CC1|CC0|IDC|RS|WC|OVF|COM
	xld.b	[%CPU+IDC], %data		; IDC   = -|---|---|IDC|--|--|---|---
	xsrl	%data, 5			; %data = 0_00000000 or 0_00000001 or 0_00000010 or 0_00000011
	sll	%data, %data			; %data = 0_00000000 or 0_00000010 or 0_00001000 or 0_00011000
	sll	%data, 4			; %data = 0_00000000 or 0_00100000 or 0_10000000 or 1_10000000
	ret.d
	ld.w	%CC, %data			;					*delay*

;****************************************************************************
;	Register
;****************************************************************************

	.global	s2650_R0
s2650_R0:
	ld.w	%reg, %CPU
	ret.d
	add	%reg, REG+0			; *delay*

	.global	s2650_R1
s2650_R1:
	xbtst	[%CPU+PSL], PSL_RS
	jreq.d	3
	ld.w	%reg, %CPU			; *delay*
	add	%reg, 3				; (skip?)
	ret.d
	add	%reg, REG+1			; *delay*

	.global	s2650_R2
s2650_R2:
	xbtst	[%CPU+PSL], PSL_RS
	jreq.d	3
	ld.w	%reg, %CPU			; *delay*
	add	%reg, 3				; (skip?)
	ret.d
	add	%reg, REG+2			; *delay*

	.global	s2650_R3
s2650_R3:
	xbtst	[%CPU+PSL], PSL_RS
	jreq.d	3
	ld.w	%reg, %CPU			; *delay*
	add	%reg, 3				; (skip?)
	ret.d
	add	%reg, REG+3			; *delay*

;****************************************************************************
;	Condition
;****************************************************************************

	.global	s2650_EQ
s2650_EQ:
	ret.d
	cmp	%CC, 0x00			; %psr(Z) = 0 or 1		*delay*

	.global	s2650_GT
s2650_GT:
	xcmp	%CC, 0x01
	xjrlt	s2650_GT_EXIT			; %psr(Z) = 0
	xcmp	%CC, 0x7f
	xjrgt	s2650_GT_EXIT			; %psr(Z) = 0
	cmp	%CC, %CC			; %psr(Z) = 1
s2650_GT_EXIT:
	ret

	.global	s2650_LT
s2650_LT:
	xcmp	%CC, 0x80
	xjrlt	s2650_LT_EXIT			; %psr(Z) = 0
	xcmp	%CC, 0xff
	xjrgt	s2650_LT_EXIT			; %psr(Z) = 0
	cmp	%CC, %CC			; %psr(Z) = 1
s2650_LT_EXIT:
	ret

	.global	s2650_UN
s2650_UN:
	ret.d
	cmp	%CC, %CC			; %psr(Z) = 1			*delay*

	.global	s2650_IR
s2650_IR:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.ub	%r9, [%reg]			; r++
	xadd	%r9, %r9, 1
	ld.ub	%r9, %r9			; 必要!!
	ld.b	[%reg], %r9
	ret.d
	cmp	%r9, 0				; %psr(Z) = 0 or 1		*delay*

	.global	s2650_DR
s2650_DR:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.ub	%r9, [%reg]			; r--
	xsub	%r9, %r9, 1
	ld.ub	%r9, %r9			; 必要!!
	ld.b	[%reg], %r9
	ret.d
	cmp	%r9, 0				; %psr(Z) = 0 or 1		*delay*

	.global	s2650_NR
s2650_NR:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.ub	%r9, [%reg]
	ret.d
	cmp	%r9, 0				; %psr(Z) = 0 or 1		*delay*

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

	.global	s2650_IND
s2650_IND: /* INDirect addressing */
	/* 他のアドレスモード関数から呼ばれます。dataを破壊しないよう注意!! */
	xcall.d	s2650_read			; tmp  = [addr++]<<8
	ld.w	%r12, %addr			;						*delay*
	add	%addr, 1
	ld.w	%r12, %addr
	ld.w	%addr, %r10
	xcall.d	s2650_read			; tmp |= [addr  ]
	sll	%addr, 8			;						*delay*
	or	%addr, %r10
	xand	%addr, %addr, 0x7fff		; addr = tmp&0x7fff
	ret.d
	sub	%CYCLE, 6			;						*delay*

	.global	s2650_ABB
s2650_ABB: /* ABsolute addressing for Branch instructions */
	xcall.d	s2650_read			; data  = [IAR++]<<8
	ld.w	%r12, %IAR			;						*delay*
	add	%IAR, 1
	ld.w	%data, %r10
	xsll	%data, 8
	xcall.d	s2650_read			; data |= [IAR++]
	ld.w	%r12, %IAR			;						*delay*
	add	%IAR, 1
	or	%data, %r10
	xand	%addr, %data, 0x7fff		; addr  = data&7fff
	xand	%r9, %data, 0x8000		; if(data&0x8000) s2650_IND()
	xjrne	s2650_IND
	ret

	.global	s2650_AXB
s2650_AXB: /* Absolute indeXed addressing for Branch instructions */
	xcall	s2650_ABB			; AddressMode
	xcall	s2650_R3			; Register
	ld.ub	%r10, [%reg]			; %r10 =                      r
	xand	%r9, %addr, 0x6000		; %r9  =  addr&0x6000
	add	%addr, %r10			; addr =                 addr+r
	xand	%addr, %addr, 0x1fff		; addr =                (addr+r)&0x1fff
	ret.d
	or	%addr, %r9			; addr = (addr&0x6000)|((addr+r)&0x1fff)	*delay*

	.global	s2650_VEC
s2650_VEC: /* Relative addressing from Zero Page [in] data=vector */
	ld.w	%addr, %data			; addr =         data
	xsla	%addr, 1			; addr =         data<<1
	ld.b	%addr, %addr			; addr =  (char)(data<<1)
	xsra	%addr, 1			; addr =  (char)(data<<1)>>1
	xand	%addr, %addr, 0x1fff		; addr = ((char)(data<<1)>>1)&0x1fff
	xsrl	%data, 7			; if(data&0x80) s2650_IND()
	xjrne	s2650_IND
	ret

	.global	s2650_ZPR
s2650_ZPR: /* Relative addressing from Zero Page (vectorフェッチ) */
	xcall.d	s2650_read			; data = [IAR++]
	ld.w	%r12, %IAR			;						*delay*
	add	%IAR, 1
	xjp.d	s2650_VEC			; s2650_VEC()
	ld.w	%data, %r10			;						*delay*

	.global	s2650_IMM
s2650_IMM: /* IMMediate addressing */
	ld.w	%addr, %IAR			; addr = IAR++
	ret.d
	add	%IAR, 1				;						*delay*

	.global	s2650_REL
s2650_REL: /* RELative addressing */
	xcall.d	s2650_read			; %r10 = [IAR++]
	ld.w	%r12, %IAR			;						*delay*
	add	%IAR, 1
	ld.w	%addr, %r10			; addr =        %r10
	xsla	%addr, 1			; addr =        %r10<<1
	ld.b	%addr, %addr			; addr = (char)(%r10<<1)
	xsra	%addr, 1			; addr = (char)(%r10<<1)>>1 = rel
	xand	%r9, %IAR, 0x6000		; %r9  =  IAR&0x6000
	add	%addr, %IAR			; addr =               IAR+rel
	xand	%addr, %addr, 0x1fff		; addr =              (IAR+rel)&0x1fff
	;or	%addr, %r9			; addr = (IAR&0x6000)|(IAR+rel)&0x1fff ------------+
	xsrl	%r10, 7				; if(%r10 & 0x80) s2650_IND()                      |
	xjrne.d	s2650_IND			;                                                  V
	 or	%addr, %r9			; addr = (IAR&0x6000)|(IAR+rel)&0x1fff		*delay*
	ret

	.global	s2650_ABS
s2650_ABS: /* ABSolute addressing for non-branch instructions */
	xcall.d	s2650_read			; data  = [IAR++]<<8
	ld.w	%r12, %IAR			;						*delay*
	add	%IAR, 1
	ld.w	%data, %r10
	xsll	%data, 8
	xcall.d	s2650_read			; data |= [IAR++]
	ld.w	%r12, %IAR			;						*delay*
	add	%IAR, 1
	or	%data, %r10
	xand	%r10, %IAR, 0x6000		; %r10 =  IAR&0x6000
	xand	%addr, %data, 0x1fff		; addr =               data&0x1fff
	;or	%addr, %r10			; addr = (IAR&0x6000)|(data&0x1fff) ---------------+
	xand	%r9, %data, 0x8000		; if(data&0x8000) s2650_IND()                      |
	xjreq.d	s2650_ABS_L10			;                                                  V
	 or	%addr, %r10			; addr = (IAR&0x6000)|(data&0x1fff)		*delay*
	xcall	s2650_IND
s2650_ABS_L10:
	xand	%r9, %data, 0x6000		; if(data&0x6000) {
	xjreq	s2650_ABS_L20
	ld.ub	%r10, [%reg]			;   %r10 = r
	xand	%r9, %data, 0x2000		;   if(data&0x2000) {
	jreq	2				;     r++
	add	%r10, 1				;   }						(skip?)
	xand	%r9, %data, 0x4000		;   if(data&0x4000) {
	jreq	2				;     r--
	sub	%r10, 1				;   }						(skip?)
	ld.ub	%r10, %r10			;   必要!!
	ld.b	[%reg], %r10			;   r = %r10
	xand	%r9, %addr, 0x6000		;   %r9  =  addr&0x6000
	add	%addr, %r10			;   addr =                 addr+r
	xand	%addr, %addr, 0x1fff		;   addr =                (addr+r)&0x1fff
	;or	%addr, %r9			;   addr = (addr&0x6000)|((addr+r)&0x1fff) --------+
	xcall.d	s2650_R0			;   Register                                       V
	 or	%addr, %r9			;   addr = (addr&0x6000)|((addr+r)&0x1fff)	*delay*
s2650_ABS_L20:					; }
	ret

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

	.global	s2650_LODr
s2650_LODr:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.ub	%CC, [%reg]			; CC = r
	xld.b	[%CPU+REG+0], %CC		; R0 = CC
	ret

	.global	s2650_LODm
s2650_LODm:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	xcall.d	s2650_read			; %r10 = [addr]
	ld.w	%r12, %addr			;				*delay*
	ld.b	[%reg], %r10			; r    = %r10
	ret.d
	ld.w	%CC, %r10			; CC   = %r10			*delay*

	.global	s2650_STRr
s2650_STRr:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	xld.ub	%CC, [%CPU+REG+0]		; CC = R0
	ld.b	[%reg], %CC			; r  = CC
	ret

	.global	s2650_STRm
s2650_STRm:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	ld.ub	%r13, [%reg]			; [addr] = r
	xjp.d	s2650_write
	ld.w	%r12, %addr			;				*delay*

/*--------------------------------------------------------------------------*/

	.global	s2650_ADD
s2650_ADD:
	xbtst	[%CPU+PSL], PSL_WC		; if(WC) {
	xjreq.d	s2650_ADD_L10
	ld.w	%r14, 0				; %r14 = c = 0			*delay*
	xld.ub	%r14, [%CPU+C+1]		;        c = C[8]
	xand	%r14, %r14, 1
s2650_ADD_L10:					; }
	ld.w	%CC, %r12			; CC   = t = a+b+c
	add	%CC, %r13
	add	%CC, %r14
	xld.h	[%CPU+C], %CC			; C    = t
	ld.w	%r10, %r12			; %r10 =   a
	xor	%r10, %r13			; %r10 =   a^b
	not	%r10, %r10			; %r10 = ~(a^b)
	ld.w	%r11, %r12			; %r10 =         a
	xor	%r11, %CC			; %r11 =         a^t
	and	%r10, %r11			; %r10 = ~(a^b)&(a^t)
	xld.b	[%CPU+OVF], %r10		; OVF  = ~(a^b)&(a^t)
	xand	%r12, %r12, 0xf			; %r12 =  a&0xf
	xand	%r13, %r13, 0xf			; %r12 =          b&0xf
	add	%r12, %r13			; %r12 = (a&0xf)+(b&0xf)
	add	%r12, %r14			; %r12 = (a&0xf)+(b&0xf)+c
	xld.b	[%CPU+IDC], %r12		; IDC  = (a&0xf)+(b&0xf)+c
	ret.d
	ld.ub	%CC, %CC			; CC   = (unsigned char)t	*delay*

	.global	s2650_ADDr
s2650_ADDr:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	xld.ub	%r12, [%CPU+REG+0]		; ADD(R0, r)
	ld.ub	%r13, [%reg]
	xcall	s2650_ADD
	xld.b	[%CPU+REG+0], %CC		; R0 = CC
	ret

	.global	s2650_ADDm
s2650_ADDm:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	xcall.d	s2650_read			; %r10 = [addr]
	ld.w	%r12, %addr			;				*delay*
	ld.ub	%r12, [%reg]			; ADD(r, [addr])
	xcall.d	s2650_ADD
	ld.w	%r13, %r10			;				*delay*
	ld.b	[%reg], %CC			; r = CC
	ret

	.global	s2650_SUB
s2650_SUB:
	xbtst	[%CPU+PSL], PSL_WC		; if(WC) {
	xjreq.d	s2650_SUB_L10
	ld.w	%r14, 0				; %r14 = c = 0			*delay*
	xld.ub	%r14, [%CPU+C+1]		;        c = ~C[8]
	not	%r14, %r14
	xand	%r14, %r14, 1
s2650_SUB_L10:					; }
	ld.w	%CC, %r12			; CC   = t = a-b-c
	sub	%CC, %r13
	sub	%CC, %r14
	not	%r9, %CC			; C    = ~t
	xld.h	[%CPU+C], %r9
	ld.w	%r10, %r12			; %r10 =  a
	xor	%r10, %r13			; %r10 =  a^b
	ld.w	%r11, %r12			; %r10 =        a
	xor	%r11, %CC			; %r11 =        a^t
	and	%r10, %r11			; %r10 = (a^b)&(a^t)
	xld.b	[%CPU+OVF], %r10		; OVF  = (a^b)&(a^t)
	xand	%r12, %r12, 0xf			; %r12 =    a&0xf
	xand	%r13, %r13, 0xf			; %r12 =            b&0xf
	sub	%r12, %r13			; %r12 =   (a&0xf)-(b&0xf)
	sub	%r12, %r14			; %r12 =   (a&0xf)-(b&0xf)-c
	not	%r12, %r12			; %r12 = ~((a&0xf)-(b&0xf)-c)
	xld.b	[%CPU+IDC], %r12		; IDC  = ~((a&0xf)-(b&0xf)-c)
	ret.d
	ld.ub	%CC, %CC			; CC   = (unsigned char)t	*delay*

	.global	s2650_SUBr
s2650_SUBr:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	xld.ub	%r12, [%CPU+REG+0]		; SUB(R0, r)
	ld.ub	%r13, [%reg]
	xcall	s2650_SUB
	xld.b	[%CPU+REG+0], %CC		; R0 = CC
	ret

	.global	s2650_SUBm
s2650_SUBm:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	xcall.d	s2650_read			; %r10 = [addr]
	ld.w	%r12, %addr			;				*delay*
	ld.ub	%r12, [%reg]			; SUB(r, [addr])
	xcall.d	s2650_SUB
	ld.w	%r13, %r10			;				*delay*
	ld.b	[%reg], %CC			; r = CC
	ret

	.global	s2650_ANDr
s2650_ANDr:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	xld.ub	%CC, [%CPU+REG+0]		; CC = R0 & r
	ld.ub	%r9, [%reg]
	and	%CC, %r9
	xld.b	[%CPU+REG+0], %CC		; R0 = CC
	ret

	.global	s2650_ANDm
s2650_ANDm:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	ld.ub	%CC, [%reg]			; CC = r & [addr]
	xcall.d	s2650_read
	ld.w	%r12, %addr			;				*delay*
	and	%CC, %r10
	ld.b	[%reg], %CC			; r = CC
	ret

	.global	s2650_IORr
s2650_IORr:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	xld.ub	%CC, [%CPU+REG+0]		; CC = R0 | r
	ld.ub	%r9, [%reg]
	or	%CC, %r9
	xld.b	[%CPU+REG+0], %CC		; R0 = CC
	ret

	.global	s2650_IORm
s2650_IORm:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	ld.ub	%CC, [%reg]			; CC = r | [addr]
	xcall.d	s2650_read
	ld.w	%r12, %addr			;				*delay*
	or	%CC, %r10
	ld.b	[%reg], %CC			; r = CC
	ret

	.global	s2650_EORr
s2650_EORr:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	xld.ub	%CC, [%CPU+REG+0]		; CC = R0 ^ r
	ld.ub	%r9, [%reg]
	xor	%CC, %r9
	xld.b	[%CPU+REG+0], %CC		; R0 = CC
	ret

	.global	s2650_EORm
s2650_EORm:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	ld.ub	%CC, [%reg]			; CC = r ^ [addr]
	xcall.d	s2650_read
	ld.w	%r12, %addr			;				*delay*
	xor	%CC, %r10
	ld.b	[%reg], %CC			; r = CC
	ret

	.global	s2650_COM
s2650_COM:
	xbtst	[%CPU+PSL], PSL_COM		; if(!COM) {
	xjrne	s2650_COM_L10
	ld.b	%r12, %r12			;   a = (char)a
	ld.b	%r13, %r13			;   b = (char)b
s2650_COM_L10:					; }
	cmp	%r12, %r13
	xjreq.d	s2650_COM_EXIT			; if(a=b) CC=0x00
	ld.w	%CC, 0				; 				*delay*
	xjrgt.d	s2650_COM_EXIT			; if(a>b) CC=0x01
	ld.w	%CC, 1				;				*delay*
	xsll	%CC, 7				; if(a<b) CC=0x80
s2650_COM_EXIT:
	ret

	.global	s2650_COMr
s2650_COMr:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	xld.ub	%r12, [%CPU+REG+0]		; COM(R0, r)
	ld.ub	%r13, [%reg]
	xjp	s2650_COM

	.global	s2650_COMm
s2650_COMm:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	xcall.d	s2650_read			; %r10 = [addr]
	ld.w	%r12, %addr			;				*delay*
	ld.ub	%r12, [%reg]			; COM(r, [addr])
	xjp.d	s2650_COM
	ld.w	%r13, %r10			;				*delay*

	.global	s2650_RRL
s2650_RRL:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.b	%CC, [%reg]			; CC   = r = ssssssss_ssssssss_ssssssss_srrrrrrr
	xbtst	[%CPU+PSL], PSL_WC		; if(WC) {						*anti-interlock*
	ld.w	%r10, %CC			; %r10 = r
	xjreq.d	s2650_RRL_L10
	rl	%CC, 1				; CC   = r = ssssssss_ssssssss_ssssssss_rrrrrrrs	*delay*
	xld.ub	%r9, [%CPU+C+1]			;   %r9    = 00000000_00000000_00000000_???????c
	xand	%CC, %CC, ~1			;   CC     = ssssssss_ssssssss_ssssssss_rrrrrrr0
	xand	%r9, %r9, 1			;   %r9    = 00000000_00000000_00000000_0000000c
	or	%CC, %r9			;   CC     = ssssssss_ssssssss_ssssssss_rrrrrrrc
	xld.h	[%CPU+C], %CC			;   C <-------------------------------+   |
	ld.w	%r9, %CC			;                                         ++
	xsrl	%r9, 1				;                                          |
	xld.b	[%CPU+IDC], %r9			;   IDC <----------------------------------+
s2650_RRL_L10:					; } else {
	xor	%r10, %CC			; OVF  = (r^RRL(r))[7]
	xld.b	[%CPU+OVF], %r10
	ld.b	[%reg], %CC			; r    = CC
	ret.d
	ld.ub	%CC, %CC			; CC   = (unsigned char)r				*delay*

	.global	s2650_RRR
s2650_RRR:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.ub	%CC, [%reg]			; CC   = r = 00000000_00000000_00000000_rrrrrrrx
	xbtst	[%CPU+PSL], PSL_WC		; if(WC) {						*anti-interlock*
	xjreq.d	s2650_RRR_L10
	ld.w	%r10, %CC			; %r10 = r						*delay*
	xld.ub	%r9, [%CPU+C+1]			;   %r9    = 00000000_00000000_00000000_???????c
	xsll	%r9, 8				;   %r9    = 00000000_00000000_???????c_00000000
	or	%CC, %r9			;   CC     = 00000000_00000000_???????c_rrrrrrrx
	ld.w	%r9, %CC			;                                        |     |
	xsrl	%r9, 2				;                                        +-+   |
	xld.b	[%CPU+IDC], %r9			;   IDC <----------------------------------+   |
	xld.b	[%CPU+C+1], %CC			;   C <----------------------------------------+
	;xsrl	%CC, 1				;   CC     = 00000000_00000000_0???????_crrrrrrr --+
	xjp	s2650_RRR_L20			;                                                  |
s2650_RRR_L10:					; } else {                                         |共
	ld.w	%r9, %CC			;   %r9    = 00000000_00000000_00000000_rrrrrrrx   |通
	xsll	%r9, 8				;   %r9    = 00000000_00000000_rrrrrrrx_00000000   |処
	or	%CC, %r9			;   %CC    = 00000000_00000000_rrrrrrrx_rrrrrrrx   |理
s2650_RRR_L20:					; }                                                |
	xsrl	%CC, 1				; CC   =     00000000_00000000_0rrrrrrr_xrrrrrrr <-+
	xor	%r10, %CC			; OVF  = (r^RRR(r))[7]
	xld.b	[%CPU+OVF], %r10
	ld.b	[%reg], %CC			; r    = CC
	ret.d
	ld.ub	%CC, %CC			; CC   = (unsigned char)r				*delay*

/*--------------------------------------------------------------------------*/

	.global	s2650_LPSU
s2650_LPSU:
	xld.ub	%data, [%CPU+REG+0]
	xcall	s2650_set_psu
	xjp	s2650_check_pending

	.global	s2650_LPSL
s2650_LPSL:
	xld.ub	%data, [%CPU+REG+0]
	xjp	s2650_set_psl

	.global	s2650_SPSU
s2650_SPSU:
	xcall	s2650_get_psu
	xld.b	[%CPU+REG+0], %data
	ret.d
	ld.w	%CC, %data

	.global	s2650_SPSL
s2650_SPSL:
	xcall	s2650_get_psl
	xld.b	[%CPU+REG+0], %data
	ret.d
	ld.w	%CC, %data

	.global	s2650_PPSU
s2650_PPSU:
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	xcall	s2650_get_psu			; data  = PSU
	xcall.d	s2650_read			; %r10  = [addr]
	ld.w	%r12, %addr			;				*delay*
	xjp.d	s2650_set_psu			; PSU   = data
	or	%data, %r10			; data |= %r10			*delay*

	.global	s2650_PPSL
s2650_PPSL:
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	xcall	s2650_get_psl			; data  = PSL
	xcall.d	s2650_read			; %r10  = [addr]
	ld.w	%r12, %addr			;				*delay*
	xjp.d	s2650_set_psl			; PSL   = data
	or	%data, %r10			; data |= %r10			*delay*

	.global	s2650_CPSU
s2650_CPSU:
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	xcall	s2650_get_psu			; data  = PSU
	xcall.d	s2650_read			; %r10  = [addr]
	ld.w	%r12, %addr			;				*delay*
	not	%r10, %r10			; %r10  = ~%r10
	xcall.d	s2650_set_psu			; PSU   = data
	and	%data, %r10			; data &= %r10			*delay*
	xjp	s2650_check_pending

	.global	s2650_CPSL
s2650_CPSL:
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	xcall	s2650_get_psl			; data  = PSL
	xcall.d	s2650_read			; %r10  = [addr]
	ld.w	%r12, %addr			;				*delay*
	not	%r10, %r10			; %r10  = ~%r10
	xjp.d	s2650_set_psl			; PSL   = data
	and	%data, %r10			; data &= %r10			*delay*

	.global	s2650_TEST
s2650_TEST:
	/* C言語版s2650_TESTのコメントを参照してください */
	and	%r12, %r13			; CC = (unsigned char)(((a&b)-b)>>8)
	sub	%r12, %r13
	xsrl	%r12, 8
	ret.d
	ld.ub	%CC, %r12			;				*delay*

	.global	s2650_TPSU
s2650_TPSU:
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	xcall	s2650_get_psu			; data  = PSU
	xcall.d	s2650_read			; %r10  = [addr]
	ld.w	%r12, %addr			;				*delay*
	ld.w	%r12, %data			; TEST(PSU, [addr])
	xjp.d	s2650_TEST
	ld.w	%r13, %r10			;				*delay*

	.global	s2650_TPSL
s2650_TPSL:
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	xcall	s2650_get_psl			; data  = PSL
	xcall.d	s2650_read			; %r10  = [addr]
	ld.w	%r12, %addr			;				*delay*
	ld.w	%r12, %data			; TEST(PSL, [addr])
	xjp.d	s2650_TEST
	ld.w	%r13, %r10			;				*delay*

/*--------------------------------------------------------------------------*/

	.global	s2650_BRR
s2650_BRR:
	xcall	s2650_REL			; AddressMode
	ret.d
	ld.w	%IAR, %addr			;				*delay*

	.global	s2650_BRA
s2650_BRA:
	xcall	s2650_ABB			; AddressMode
	ret.d
	ld.w	%IAR, %addr			;				*delay*

	.global	s2650_BRReq
s2650_BRReq:
	ld.w	%r9, [%seq]+			; Condition
	call	%r9
	xjreq	s2650_BRR
	ret.d
	add	%IAR, 1				; IAR += 1			*delay*

	.global	s2650_BRAeq
s2650_BRAeq:
	ld.w	%r9, [%seq]+			; Condition
	call	%r9
	xjreq	s2650_BRA
	ret.d
	add	%IAR, 2				; IAR += 2			*delay*

	.global	s2650_BRRne
s2650_BRRne:
	ld.w	%r9, [%seq]+			; Condition
	call	%r9
	xjrne	s2650_BRR
	ret.d
	add	%IAR, 1				; IAR += 1			*delay*

	.global	s2650_BRAne
s2650_BRAne:
	ld.w	%r9, [%seq]+			; Condition
	call	%r9
	xjrne	s2650_BRA
	ret.d
	add	%IAR, 2				; IAR += 2			*delay*

	.global	s2650_ZBRR
s2650_ZBRR:
	xcall	s2650_ZPR			; AddressMode
	ret.d
	ld.w	%IAR, %addr

	.global	s2650_BXA
s2650_BXA:
	xcall	s2650_AXB			; AddressMode
	ret.d
	ld.w	%IAR, %addr

/*--------------------------------------------------------------------------*/

	.global	s2650_BS
s2650_BS:
	xld.ub	%r9, [%CPU+SP]			; SP = (SP+1)&7
	xadd	%r9, %r9, 1
	xand	%r9, %r9, 7
	xld.b	[%CPU+SP], %r9
	xsll	%r9, 1				; RAS[SP] = IAR
	ext	s2650+RAS@ah
	ext	s2650+RAS@al
	ld.h	[%r9], %IAR
	ret.d
	ld.w	%IAR, %addr			; IAR = addr			*delay*

	.global	s2650_BSR
s2650_BSR:
	xcall	s2650_REL			; AddressMode
	xjp	s2650_BS

	.global	s2650_BSA
s2650_BSA:
	xcall	s2650_ABB			; AddressMode
	xjp	s2650_BS

	.global	s2650_BSReq
s2650_BSReq:
	ld.w	%r9, [%seq]+			; Condition
	call	%r9
	xjreq	s2650_BSR
	ret.d
	add	%IAR, 1				; IAR += 1			*delay*

	.global	s2650_BSAeq
s2650_BSAeq:
	ld.w	%r9, [%seq]+			; Condition
	call	%r9
	xjreq	s2650_BSA
	ret.d
	add	%IAR, 2				; IAR += 2			*delay*

	.global	s2650_BSRne
s2650_BSRne:
	ld.w	%r9, [%seq]+			; Condition
	call	%r9
	xjrne	s2650_BSR
	ret.d
	add	%IAR, 1				; IAR += 1			*delay*

	.global	s2650_BSAne
s2650_BSAne:
	ld.w	%r9, [%seq]+			; Condition
	call	%r9
	xjrne	s2650_BSA
	ret.d
	add	%IAR, 2				; IAR += 2			*delay*

	.global	s2650_ZBSR
s2650_ZBSR:
	xcall	s2650_ZPR			; AddressMode
	xjp	s2650_BS

	.global	s2650_BSXA
s2650_BSXA:
	xcall	s2650_AXB			; AddressMode
	xjp	s2650_BS

/*--------------------------------------------------------------------------*/

	.global	s2650_RET
s2650_RET:
	xld.ub	%r9, [%CPU+SP]			; IAR = RAS[SP]
	xsll	%r9, 1
	ext	s2650+RAS@ah
	ext	s2650+RAS@al
	ld.uh	%IAR, [%r9]
	xsrl	%r9, 1
	xsub	%r9, %r9, 1			; SP = (SP-1)&7
	xand	%r9, %r9, 7
	xld.b	[%CPU+SP], %r9
	ret

	.global	s2650_RETC
s2650_RETC:
	ld.w	%r9, [%seq]+			; Condition
	call	%r9
	xjreq	s2650_RET
	ret

/*--------------------------------------------------------------------------*/

	.global	s2650_TMI
s2650_TMI:
	ld.w	%r9, [%seq]+			; Register
	call	%r9
	ld.w	%r9, [%seq]+			; AddressMode
	call	%r9
	xcall.d	s2650_read			; %r10 = [addr]
	ld.w	%r12, %addr			;				*delay*
	ld.ub	%r12, [%reg]			; TEST(r, [addr])
	xjp.d	s2650_TEST
	ld.w	%r13, %r10			;				*delay*

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