;
;	framc16a.s
;
;	P/ECE CP1610 Emulator
;
;	CLiP - Common Library for P/ECE
;	Copyright (C) 2001-2005 Naoyuki Sawa
;
;	* Sun May 15 21:34:00 JST 2005 Naoyuki Sawa
;	- 作成開始。
;
#include "clipc16a.h"

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

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

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

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

	.code
	.align 1

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

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

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

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

	.global	cp1610_run
cp1610_run:
	pushn	%r3
	xld.w	[cp1610+_CYCLE_], %r12		; 残りサイクル数を格納します。必要!!
	xcall	cp1610_enter			; 実行コンテキストへ入ります。
	;
	xbtst	[%CPU+FLAGS], HLT_BIT		; 既にHALT中ならば、残り実行サイクル数を0にして、すぐにループを抜けます。
	jreq	2				; (cp1610.cycle=0で関数を抜けること。必須!!)
	ld.w	%CYCLE, 0			; (skip?)
	;
	xjp	cp1610_run_LOOP			; 実行サイクル数≦0が指定された場合のために、まず条件判定から。
cp1610_run_DO:
;----------------------------------------------------------------------------
#ifdef CP1610_TRACE
	; トレースデバッグを行う場合は、このブロックを有効にしてください。
	; その際、cp1610_trace()は、アプリケーションにて定義してください。
	; cp1610_trace()は、ライブラリ内では定義していません。
	xcall	cp1610_leave
	xcall	cp1610_trace
	xcall	cp1610_enter
#endif /*CP1610_TRACE*/
;----------------------------------------------------------------------------
	xld.uh	%r12, [%CPU+R7]			; %r12 =  R7
	xadd	%r9, %r12, 1			; %r9  =  R7+1
	xld.h	[%CPU+R7], %r9			; R7   =  R7+1
	xcall	cp1610_read			; %r10 = [R7]
	xand	%r10, %r10, 0x3ff		; %r10 = [R7]&0x3ff = OpCode
	xsll	%r10, 3				; %r10 = OpCode*8
	ext	cp1610op@ah
	ext	cp1610op@al
	add	%op, %r10			; %op  = &cp1610op[OpCode*8]	(op = &op->fn   )
	ld.w	%r9, [%op]+			; %r9  = op->fn			(op = &op->cycle)
	ld.ub	%r10, [%op]+			; %r10 = op->cycle		(op = &op->dst  )
	call.d	%r9				; op->fn()
	sub	%CYCLE, %r10			; cycle -= op->cycle		*delay*
	;
	xbtst	[%CPU+FLAGS], IRQ_BIT		; if(IRQ) {
	xjreq	cp1610_run_LOOP
	xbtst	[%CPU+FLAGS], IFF_BIT		;   if(IFF) {
	xjreq	cp1610_run_LOOP
	xbtst	[%op+NI], 0			;     if(!(op->ni&1)) {
	xjrne	cp1610_run_LOOP
	xbclr	[%CPU+FLAGS], IRQ_BIT		;       IRQ=0
	sub	%CYCLE, 9			;       cycle -= 9
	xld.uh	%r12, [%CPU+R6]			;       %r12 = R6
	xadd	%r9, %r12, 1			;       %r9  = R6+1
	xld.h	[%CPU+R6], %r9			;       R6   = R6+1
	xld.uh	%r13, [%CPU+R7]			;       %r13 = R7
	xcall	cp1610_write			;       [R6] = R7
	xld.uh	%r9, [%CPU+IAB]			;       %r9  = IAB
	xld.h	[%CPU+R7], %r9			;       R7   = IAB
	;
cp1610_run_LOOP:				; } } }
	xcmp	%CYCLE, 0			; 残り実行サイクル数が0以下になるまで繰り返します。
	xjrgt	cp1610_run_DO
	;
	xcall	cp1610_leave			; 実行コンテキストを抜けます。
	popn	%r3
	ret

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

; int cp1610_get_status()
; [in]
;	ありません。
; [out]
;	%r10		status (00000000 00000000 00000000 SZVC0000)
; [use]
;	使用方法が規定されていないレジスタ(%r*)は、全て破壊と考えてください。
;
	.global	cp1610_get_status
cp1610_get_status:
	xcall	cp1610_leave
	xcall	cp1610_get_status_C
	xjp	cp1610_enter

; void cp1610_set_status(int status)
; [in]
;	%r12		status (???????? ???????? ???????? SZVC????)
; [out]
;	ありません。
; [use]
;	使用方法が規定されていないレジスタ(%r*)は、全て破壊と考えてください。
;
	.global	cp1610_set_status
cp1610_set_status:
	xcall	cp1610_leave
	xcall	cp1610_set_status_C
	xjp	cp1610_enter

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

; int cp1610_data()
; [in]
;	ありません。
; [out]
;	%r10		data
; [use]
;	%src,%dst,%tmp
;	使用方法が規定されていないレジスタ(%r*)は、全て破壊と考えてください。
;
cp1610_data:
	xld.ub	%src, [%op+SRC]			; %src   =       RS   *2
	ext	cp1610_data_TBL@ah		; %r9    = &TBL[ RS   *2]
	ext	cp1610_data_TBL@al
	add	%r9, %src
	xbtst	[%CPU+FLAGS], DBD_BIT		; if(DBD) {
	xjreq.d	cp1610_data_NO_DBD
	add	%r9, %src			;   %r9  = &TBL[ RS   *4]				*delay*
	add	%r9, 8*4			;   %r9  = &TBL[(RS+8)*4]
	xbclr	[%CPU+FLAGS], DBD_BIT		;   DBD  = 0
	sub	%CYCLE, 2			;   cycle -= 2
cp1610_data_NO_DBD:				; }
	ld.w	%r9, [%r9]			; %r9    =  TBL[ RS   *4] or TBL[(RS+8)*4]
	add	%src, %CPU			; %src   = &RS						*anti-interlock*
	jp	%r9
	;---------------------------------------;
cp1610_data_SBD_0:
	xld.uh	%r12, [%CPU+R7]			; %r12 =               R7
	xadd	%r9, %r12, 1			; %r9  =               R7+1
	xld.h	[%CPU+R7], %r9			; R7   =               R7+1
	xcall	cp1610_read			; %r10 =       [       R7   ]
	xjp.d	cp1610_read			; %r10 =      [[       R7   ]]
	ld.w	%r12, %r10			; %r12 =       [       R7   ]				*delay*
	;---------------------------------------;
cp1610_data_SBD_1:
cp1610_data_SBD_2:
cp1610_data_SBD_3:
	ld.uh	%r12, [%src]			; %r12 =               RS
	xjp	cp1610_read			; %r10 =       [       RS   ]
	;---------------------------------------;
cp1610_data_SBD_4:
cp1610_data_SBD_5:
cp1610_data_SBD_7:
	ld.uh	%r12, [%src]			; %r12 =               RS
	xadd	%r9, %r12, 1			; %r9  =               RS+1
	ld.h	[%src], %r9			; RS   =               RS+1
	xjp	cp1610_read			; %r10 =       [       RS  )]
	;---------------------------------------;
cp1610_data_SBD_6:
	ld.uh	%r12, [%src]			; %r12 =               RS
	sub	%r12, 1				; %r12 =               RS-1
	ld.h	[%src], %r12			; RS   =               RS-1
	xjp.d	cp1610_read			; %r10 =       [(half)(RS-1)]
	ld.uh	%r12, %r12			; %r12 =        (half)(RS-1)				*delay*
	;---------------------------------------;
cp1610_data_DBD_1:
cp1610_data_DBD_2:
cp1610_data_DBD_3:
	ld.uh	%r12, [%src]			; %r12 =               RS
	xcall	cp1610_read			; %r10 =       [       RS   ]
	ld.ub	%dst, %r10			; %dst = (byte)[       RS   ]
	ld.uh	%r12, [%src]			; %r12 =               RS
	xcall	cp1610_read			; %r10 =       [       RS   ]
	ld.ub	%r10, %r10			; %r10 = (byte)[       RS   ]
	xsll	%r10, 8				; %r10 = (byte)[       RS   ]<<8
	ret.d
	or	%r10, %dst			; %r10 = (byte)[       RS   ]<<8|(byte)[       RS   ]	*delay*
	;---------------------------------------;
cp1610_data_DBD_4:
cp1610_data_DBD_5:
cp1610_data_DBD_7:
	ld.uh	%tmp, [%src]			; %tmp =               RS
	xcall.d	cp1610_read			; %r10 =       [       RS   ]
	ld.w	%r12, %tmp			; %r12 =               RS				*delay*
	ld.ub	%dst, %r10			; %r10 = (byte)[       RS   ]
	add	%tmp, 1				; %tmp =               RS+1
	xcall.d	cp1610_read			; %r10 =       [(half)(RS+1)]
	ld.uh	%r12, %tmp			; %r12 =        (half)(RS+1)				*delay*
	add	%tmp, 1				; %tmp =               RS+2
	ld.h	[%src], %tmp			; RS   =               RS+2
	ld.ub	%r10, %r10			; %r10 = (byte)[(half)(RS+1)]
	xsll	%r10, 8				; %r10 = (byte)[(half)(RS+1)]<<8
	ret.d
	or	%r10, %dst			; %r10 = (byte)[(half)(RS+1)]<<8|(byte)[       RS   ]	*delay*
	;---------------------------------------;
cp1610_data_DBD_6:
	ld.uh	%tmp, [%src]			; %tmp =               RS
	sub	%tmp, 1				; %tmp =               RS-1
	xcall.d	cp1610_read			; %r10 =       [(half)(RS-1)]
	ld.uh	%r12, %tmp			; %r12 =        (half)(RS-1)				*delay*
	ld.ub	%dst, %r10			; %r10 = (byte)[(half)(RS-1)]
	sub	%tmp, 1				; %tmp =               RS-2
	xcall.d	cp1610_read			; %r10 =       [(half)(RS-2)]
	ld.uh	%r12, %tmp			; %r12 =        (half)(RS-2)				*delay*
	ld.h	[%src], %tmp			; RS   =               RS-2
	ld.ub	%r10, %r10			; %r10 = (byte)[(half)(RS-2)]
	xsll	%r10, 8				; %r10 = (byte)[(half)(RS-2)]<<8
	ret.d
	or	%r10, %dst			; %r10 = (byte)[(half)(RS-2)]<<8|(byte)[(half)(RS-1)]	*delay*
	;---------------------------------------;
	.data					; 高速RAM節約のため、分岐テーブルはSRAMに配置します。
	.align	2				; <-必要!!
cp1610_data_TBL:				;
	.word	cp1610_data_SBD_0		;
	.word	cp1610_data_SBD_1		;
	.word	cp1610_data_SBD_2		;
	.word	cp1610_data_SBD_3		;
	.word	cp1610_data_SBD_4		;
	.word	cp1610_data_SBD_5		;
	.word	cp1610_data_SBD_6		;
	.word	cp1610_data_SBD_7		;
	.word	cp1610_ERR			;
	.word	cp1610_data_DBD_1		;
	.word	cp1610_data_DBD_2		;
	.word	cp1610_data_DBD_3		;
	.word	cp1610_data_DBD_4		;
	.word	cp1610_data_DBD_5		;
	.word	cp1610_data_DBD_6		;
	.word	cp1610_data_DBD_7		;
	.code					; 以降の配置を高速RAMに戻します。
	.align	1				; <-この指定は無くてもいいです。
	;---------------------------------------;

; int cp1610_add(int a, int b)
; [in]
;	%r12		a
;	%r13		b
; [out]
;	%r10		a+b
; [use]
;	使用方法が規定されていないレジスタ(%r*)は、全て破壊と考えてください。
;
cp1610_add:
	ld.w	%SZ, %r12			; SZ   =    a
	add	%SZ, %r13			; SZ   =    a+b = t
	xld.w	[%CPU+C], %SZ			; C    =          t[16]
	xor	%r13, %r12			; %r13 =    a^b
	not	%r13, %r13			; %r13 =  ~(a^b)
	xor	%r12, %SZ			; %r12 =          a^t
	and	%r12, %r13			; %r13 =  ~(a^b)&(a^t)
	xld.h	[%CPU+OV], %r12			; OV   = (~(a^b)&(a^t))[15]
	ld.uh	%SZ, %SZ			; SZ   = (half)t
	ret.d
	ld.w	%r10, %SZ			; return SZ						*delay*

; int cp1610_sub(int a, int b)
; [in]
;	%r12		a
;	%r13		b
; [out]
;	%r10		a-b
; [use]
;	使用方法が規定されていないレジスタ(%r*)は、全て破壊と考えてください。
;
cp1610_sub:
	ld.w	%SZ, %r12			; SZ   =   a
	sub	%SZ, %r13			; SZ   =   a-b = t
	not	%r9, %SZ			; %r9  =        ~t
	xld.w	[%CPU+C], %r9			; C    =        ~t[16]
	xor	%r13, %r12			; %r13 =   a^b
	xor	%r12, %SZ			; %r12 =         a^t
	and	%r12, %r13			; %r13 =  (a^b)&(a^t)
	xld.h	[%CPU+OV], %r12			; OV   = ((a^b)&(a^t))[15]
	ld.uh	%SZ, %SZ			; SZ   = (half)t
	ret.d
	ld.w	%r10, %SZ			; return SZ						*delay*

; void cp1610_bcond(%psr)
; [in]
;	%psr(Z)		1:分岐有り or 0:分岐無し
; [out]
;	ありません。
; [use]
;	%dst,%tmp
;	使用方法が規定されていないレジスタ(%r*)は、全て破壊と考えてください。
;
	.global	cp1610_bcond
cp1610_bcond:
	xld.uh	%tmp, [%CPU+R7]			; %tmp   =  R7
	xjrne	cp1610_bcond_NO_BRANCH		; if(%psr(Z)) { /* branch taken */
	xcall.d	cp1610_read			;   %r10 = [R7] = rel
	ld.w	%r12, %tmp			;   %r12 =  R7						*delay*
	xld.b	%dst, [%op+DST]			;   %dst = 0:前方分岐 or -1:後方分岐
	sub	%CYCLE, 2			;   cycle -= 2						*anti-interlock*
	xor	%r10, %dst			;   %r10 =     (rel^(0 or -1))
	add	%tmp, %r10			;   %tmp =  R7+(rel^(0 or -1))
cp1610_bcond_NO_BRANCH:				; }
	add	%tmp, 1				; %tmp   =  R7+(rel^(0 or -1))+1 or R7+1
	xld.h	[%CPU+R7], %tmp			; R7     =  R7+(rel^(0 or -1))+1 or R7+1
	ret

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

	.global	cp1610_JSR
cp1610_JSR:
	xld.uh	%tmp, [%CPU+R7]			; %tmp =         R7
	xcall.d	cp1610_read			; %r10 = [       R7   ]
	ld.w	%r12, %tmp			; %r12 =         R7			*delay*
	xand	%dst, %r10, 0x3ff		; %dst = bb ppppppii
	add	%tmp, 1				; %tmp =         R7+1
	xcall.d	cp1610_read			; %r10 = [(half)(R7+1)]
	ld.uh	%r12, %tmp			; %r12 =  (half)(R7+1)			*delay
	xand	%src, %r10, 0x3ff		; %src = pp pppppppp
	add	%tmp, 1				; %tmp =         R7+2
	xld.h	[%CPU+R7], %tmp			; R7   =         R7+2
	;
	xand	%r9, %dst, 3			; %r9  = ii = 0..3
	xcmp	%r9, 1
	jrne	3				; if(ii==1) {
	ext	FLAGS				;   IFF=1				(skip?)
	bset	[%CPU], IFF_BIT			; }					(skip?)
	xcmp	%r9, 2
	jrne	3				; if(ii==2) {
	ext	FLAGS				;   IFF=0				(skip?)
	bclr	[%CPU], IFF_BIT			; }					(skip?)
	;
	xand	%r9, %dst, (3<<8)		; %r9  = bb = (0..3)*2
	xsrl	%r9, (8-1)
	xld.uh	%r10, [%CPU+R7]			; %r10 = R7
	ext	cp1610+R4@ah			; [R4 or R5 or R6 or R7] = R7
	ext	cp1610+R4@al
	ld.h	[%r9], %r10
	;
	xand	%dst, %dst, ~3			; %dst = bb pppppp00
	xsll	%dst, 8				; %dst = bb pppppp00 00000000
	or	%dst, %src			; %dst = bb pppppppp pppppppp
	xld.h	[%CPU+R7], %dst			; R7   =    pppppppp pppppppp
	ret

	.global	cp1610_INCR
cp1610_INCR:
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%dst, %CPU			; %dst = &RD
	ld.uh	%SZ, [%dst]			; SZ   =  RD
	add	%SZ, 1				; SZ   =  RD+1
	ld.h	[%dst], %SZ			; RD   =  RD+1
	ret.d
	ld.uh	%SZ, %SZ			; SZ   = (half)SZ			*delay*

	.global	cp1610_DECR
cp1610_DECR:
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%dst, %CPU			; %dst = &RD
	ld.uh	%SZ, [%dst]			; SZ   =  RD
	sub	%SZ, 1				; SZ   =  RD-1
	ld.h	[%dst], %SZ			; RD   =  RD-1
	ret.d
	ld.uh	%SZ, %SZ			; SZ   = (half)SZ			*delay*

	.global	cp1610_COMR
cp1610_COMR:
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%dst, %CPU			; %dst = &RD
	ld.uh	%SZ, [%dst]			; SZ   =  RD
	not	%SZ, %SZ			; SZ   = ~RD
	ld.h	[%dst], %SZ			; RD   = ~RD
	ret.d
	ld.uh	%SZ, %SZ			; SZ   = (half)SZ			*delay*

	.global	cp1610_NEGR
cp1610_NEGR:
	xld.ub	%dst, [%op+DST]			; %dst =   RD
	add	%dst, %CPU			; %dst =  &RD
	ld.uh	%r13, [%dst]			; %r13 =   RD
	xcall.d	cp1610_sub			; %r10 = 0-RD
	ld.w	%r12, 0				; %r12 = 0				*delay*
	ld.h	[%dst], %r10			; RD   = 0-RD
	ret

	.global	cp1610_ADCR
cp1610_ADCR:
	xld.ub	%dst, [%op+DST]			; %dst =     RD
	add	%dst, %CPU			; %dst =    &RD
	ld.uh	%r12, [%dst]			; %r12 =     RD
	xld.ub	%r13, [%CPU+C+2]		; %r13 = ???????C
	xcall.d	cp1610_add			; %r10 =     RD+C
	and	%r13, 1				; %r13 = -------C			*delay*
	ld.h	[%dst], %r10			; RD   =     RD+C
	ret

	.global	cp1610_MOVR
cp1610_MOVR:
	xld.ub	%src, [%op+SRC]			; %src =  RS
	xld.ub	%dst, [%op+DST]			; %dst =  RD				*anti-interlock*
	add	%src, %CPU			; %src = &RS
	ld.uh	%SZ, [%src]			; SZ   =  RS
	add	%dst, %CPU			; %dst = &RD				*anti-interlock*
	ld.h	[%dst], %SZ			; RD   =  RS
	ret

	.global	cp1610_ADDR
cp1610_ADDR:
	xld.ub	%src, [%op+SRC]			; %src =  RS
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%src, %CPU			; %src = &RS
	add	%dst, %CPU			; %dst = &RD
	ld.uh	%r13, [%src]			; %r13 =  RS
	ld.uh	%r12, [%dst]			; %r12 =  RD
	xcall	cp1610_add			; %r10 =  RD+RS
	ld.h	[%dst], %r10			; RD   =  RD+RS
	ret

	.global	cp1610_SUBR
cp1610_SUBR:
	xld.ub	%src, [%op+SRC]			; %src =  RS
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%src, %CPU			; %src = &RS
	add	%dst, %CPU			; %dst = &RD
	ld.uh	%r13, [%src]			; %r13 =  RS
	ld.uh	%r12, [%dst]			; %r12 =  RD
	xcall	cp1610_sub			; %r10 =  RD-RS
	ld.h	[%dst], %r10			; RD   =  RD-RS
	ret

	.global	cp1610_CMPR
cp1610_CMPR:
	xld.ub	%src, [%op+SRC]			; %src =  RS
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%src, %CPU			; %src = &RS
	add	%dst, %CPU			; %dst = &RD
	ld.uh	%r13, [%src]			; %r13 =  RS
	ld.uh	%r12, [%dst]			; %r12 =  RD
	xjp	cp1610_sub			;         RD-RS

	.global	cp1610_ANDR
cp1610_ANDR:
	xld.ub	%src, [%op+SRC]			; %src =  RS
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%src, %CPU			; %src = &RS
	add	%dst, %CPU			; %dst = &RD
	ld.uh	%r9, [%src]			; %r9  =  RS
	ld.uh	%SZ, [%dst]			; SZ   =  RD
	and	%SZ, %r9			; SZ   =  RD&RS
	ld.h	[%dst], %SZ			; RD   =  RD&RS
	ret

	.global	cp1610_XORR
cp1610_XORR:
	xld.ub	%src, [%op+SRC]			; %src =  RS
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%src, %CPU			; %src = &RS
	add	%dst, %CPU			; %dst = &RD
	ld.uh	%r9, [%src]			; %r9  =  RS
	ld.uh	%SZ, [%dst]			; SZ   =  RD
	xor	%SZ, %r9			; SZ   =  RD^RS
	ld.h	[%dst], %SZ			; RD   =  RD^RS
	ret

	.global	cp1610_B
cp1610_B:
	xcall	cp1610_get_status		; %r10    = SZVC0000
	xsrl	%r10, (4-1)			; %r10    = 000SZVC0
	ext	cp1610_cond@ah			; %r10    = cp1610_cond[(SZVC)*2]
	ext	cp1610_cond@al
	ld.uh	%r10, [%r10]
	xld.ub	%src, [%op+SRC]			; %src    = cond (0..15)
	xsrl	%r10, %src			; %r10    = cp1610_cond[(SZVC)*2]>>cond (%r9破壊!!)
	xjp.d	cp1610_bcond
	and	%r10, 1				; %psr(Z) = 1:分岐有り or 0:分岐無し	*delay*

	.global	cp1610_MVO
cp1610_MVO:
	xld.ub	%src, [%op+SRC]			; %src =  RS
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	ext	cp1610_MVO_TBL@ah		; %r9  = &TBL[RD*2]
	ext	cp1610_MVO_TBL@al
	add	%r9, %dst
	add	%r9, %dst			; %r9  = &TBL[RD*4]
	ld.w	%r9, [%r9]			; %r9  =  TBL[RD*4]
	add	%src, %CPU			; %src = &RS
	add	%dst, %CPU			; %dst = &RD
	jp	%r9
cp1610_MVO_0:
	xld.uh	%r12, [%CPU+R7]			; %r12   =  R7
	xadd	%r9, %r12, 1			; %r9    =  R7+1
	xld.h	[%CPU+R7], %r9			; R7     =  R7+1
	xcall	cp1610_read			; %r10   = [R7]
	ld.uh	%r13, [%src]			; %r13   =  RS
	xjp.d	cp1610_write			; [[R7]] =  RS
	ld.w	%r12, %r10			; %r12   = [R7]				*delay*
cp1610_MVO_1:
cp1610_MVO_2:
cp1610_MVO_3:
	ld.uh	%r12, [%dst]			; %r12   =  RD
	ld.uh	%r13, [%src]			; %r13   =  RS
	xjp	cp1610_write			; [RD]   =  RS
cp1610_MVO_4:
cp1610_MVO_5:
cp1610_MVO_6:
cp1610_MVO_7:
	ld.uh	%r12, [%dst]			; %r12   =  RD
	xadd	%r9, %r12, 1			; %r9    =  RD+1
	ld.h	[%dst], %r9			; RD     =  RD+1
	ld.uh	%r13, [%src]			; %r13   =  RS
	xjp	cp1610_write			; [RD]   =  RS
	;---------------------------------------;
	.data					; 高速RAM節約のため、分岐テーブルはSRAMに配置します。
	.align	2				; <-必要!!
cp1610_MVO_TBL:					;
	.word	cp1610_MVO_0			;
	.word	cp1610_MVO_1			;
	.word	cp1610_MVO_2			;
	.word	cp1610_MVO_3			;
	.word	cp1610_MVO_4			;
	.word	cp1610_MVO_5			;
	.word	cp1610_MVO_6			;
	.word	cp1610_MVO_7			;
	.code					; 以降の配置を高速RAMに戻します。
	.align	1				; <-この指定は無くてもいいです。
	;---------------------------------------;

	.global	cp1610_MVI
cp1610_MVI:
	xcall	cp1610_data			; %r10 =  data
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%dst, %CPU			; %dst = &RD
	ld.h	[%dst], %r10			; RD   =  data
	ret

	.global	cp1610_ADD
cp1610_ADD:
	xcall	cp1610_data			; %r10 =  data
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%dst, %CPU			; %dst = &RD
	ld.uh	%r12, [%dst]			; %r12 =  RD
	xcall.d	cp1610_add			; %r10 =  RD+data
	ld.w	%r13, %r10			; %r13 =  data				*delay*
	ld.h	[%dst], %r10			; RD   =  RD+data
	ret

	.global	cp1610_SUB
cp1610_SUB:
	xcall	cp1610_data			; %r10 =  data
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%dst, %CPU			; %dst = &RD
	ld.uh	%r12, [%dst]			; %r12 =  RD
	xcall.d	cp1610_sub			; %r10 =  RD-data
	ld.w	%r13, %r10			; %r13 =  data				*delay*
	ld.h	[%dst], %r10			; RD   =  RD-data
	ret

	.global	cp1610_CMP
cp1610_CMP:
	xcall	cp1610_data			; %r10 =  data
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%dst, %CPU			; %dst = &RD
	ld.uh	%r12, [%dst]			; %r12 =  RD
	xjp.d	cp1610_sub			; %r10 =  RD-data
	ld.w	%r13, %r10			; %r13 =  data				*delay*

	.global	cp1610_AND
cp1610_AND:
	xcall	cp1610_data			; %r10 =  data
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%dst, %CPU			; %dst = &RD
	ld.uh	%SZ, [%dst]			; SZ   =  RD
	and	%SZ, %r10			; SZ   =  RD&data
	ld.h	[%dst], %SZ			; RD   =  RD&data
	ret

	.global	cp1610_XOR
cp1610_XOR:
	xcall	cp1610_data			; %r10 =  data
	xld.ub	%dst, [%op+DST]			; %dst =  RD
	add	%dst, %CPU			; %dst = &RD
	ld.uh	%SZ, [%dst]			; SZ   =  RD
	xor	%SZ, %r10			; SZ   =  RD^data
	ld.h	[%dst], %SZ			; RD   =  RD^data
	ret

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