;	
;	framt18a.s
;
;	P/ECE TMS9918(A) Emulator
;
;	CLiP - Common Library for P/ECE
;	Copyright (C) 2001-2005 Naoyuki Sawa
;
;	* Mon Jan 4 21:50:00 JST 2005 Naoyuki Sawa
;	- 作成開始。
;
;#include "clipt18a.h"
;/	
;/	framt18a.h
;/
;/	P/ECE TMS9918(A) Emulator
;/
;/	CLiP - Common Library for P/ECE
;/	Copyright (C) 2001-2005 Naoyuki Sawa
;/
;/	* Mon Jan 4 21:50:00 JST 2005 Naoyuki Sawa
;/	- 作成開始。
;/

;/ このファイルはC/アセンブラソース両方から参照します。
;/ C言語特有の定義を含めてはいけません。

;/ このシンボルを定義すると、アセンブラコードを使用します。
;/ このシンボルを定義しなければ、Ｃ言語コードを使用します。
;#define TMS9918_ASM
;#ifdef TMS9918_ASM

	.code
	.align 1

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

;
;	TMS9918構造体
;
			;typedef struct _TMS9918 {
;#define ADDR	 0	;	unsigned short addr;		/* + 0,  2: Address (0x0000-0x3fff) ★使用頻度が高いので1命令でアクセスできるよう先頭に配置★ */
;#define LATCH	 2	;	         short latch;		/* + 2,  2: Port#1への書き込み値を保持 (-1:初期状態) */
;#define REG	 4	;	unsigned char  reg[8];		/* + 4,  8: Register */
;#define STATUS	12	;	unsigned char  status;		/* +12,  1: Status */
;#define RESV	13	;	unsigned char  resv[3];		/* +13,  3: (予約) */
;#define VRAM	16	;	unsigned char  vram[0x4000];	/* +16,16K: VRAM (16KB) */
			;} TMS9918;

;****************************************************************************
;	tms9918_reduce
;****************************************************************************

	.global tms9918_reduce
tms9918_reduce:
	ext	0x4		; 	xld.w %r14, 0x100
	ld.w	%r14,0x0
	ext	0x8		; 	xld.w %r15, 0x200
	ld.w	%r15,0x0
	;
	ld.w	%r10,0x8	; 	xld.w %r10, 0x8			; z = 192 / 24
tms9918_reduce_do_z:				; do {
	;
	ld.w	%r11,0xb	; 	xld.w %r11, 0xb			;   y = 24 / 2 - 1
tms9918_reduce_do_y:				;   do {
	;
	ext	0x2		; 	xld.w %r4, 0x80			;     x = 256 / 2
	ld.w	%r4,0x0
	cmp	%r11,0x4	; 	xcmp %r11, 4				;     switch(y) {
	jreq	tms9918_reduce_case4_8_do_x	; 	xjreq tms9918_reduce_case4_8_do_x	;     
	cmp	%r11,0x8	; 	xcmp %r11, 8				;     
	jreq	tms9918_reduce_case4_8_do_x	; 	xjreq tms9918_reduce_case4_8_do_x	;     
	;
tms9918_reduce_default_do_x:			;     default: do {
	ext	0x100		; 	xld.uh %r5, [%r13+0x100]			;         c = tmp[0] + tmp[256 / 2]
	ld.uh	%r5,[%r13]
	 ld.uh %r6, [%r13]+			;         tmp++
	add %r5, %r6
	ld.ub %r6, %r5				;         c = (c & 0xff) + (c >> 8)
	srl	%r5,0x8		; 	xsrl %r5, 8				;         
	add %r5, %r6				;         
	srl	%r5,0x2		; 	xsrl %r5, 2				;         *dst++ = c / 4
	sub	%r4,0x1		; 	xsub %r4, %r4, 1			;         x--
	ld.b [%r12]+, %r5			;         
	jrne	tms9918_reduce_default_do_x	; 	xjrne tms9918_reduce_default_do_x	;       } while(x)
	jp.d	tms9918_reduce_while_y	; 	xjp.d tms9918_reduce_while_y		;       break;
	add %r13, %r14		  		;       tmp += (256 * (2 - 1)) / 2 *delay*
	;
tms9918_reduce_case4_8_do_x:			;     case 4: case 8: do {
	ext	0x200		; 	xld.uh %r5, [%r13+0x200]			;         c = tmp[0] + tmp[256 / 2] + tmp[512 / 2]
	ld.uh	%r5,[%r13]
	ext	0x100		; 	xld.uh %r6, [%r13+0x100]			;         
	ld.uh	%r6,[%r13]
	 ld.uh %r7, [%r13]+			;         tmp++
	add %r5, %r6				;         
	add %r5, %r7				;         
	ld.ub %r6, %r5				;         c = (c & 0xff) + (c >> 8)
	srl	%r5,0x8		; 	xsrl %r5, 8				;         
	add %r5, %r6				;         
	ext tms9918_div6_table@ah		;         *dst++ = tms9918_div6_table[c]
	ext tms9918_div6_table@al		;         
	ld.ub %r5, [%r5]			;         
	sub	%r4,0x1		; 	xsub %r4, %r4, 1			;         x-- *anti-interlock*
	ld.b [%r12]+, %r5			;         
	jrne	tms9918_reduce_case4_8_do_x	; 	xjrne tms9918_reduce_case4_8_do_x	;       } while(x)
	add %r13, %r15				;       tmp += (256 * (3 - 1)) / 2
	;					;     }
	;
tms9918_reduce_while_y:				;   } while(--y)
	sub	%r11,0x1	; 	xsub %r11, %r11, 1
	jrne	tms9918_reduce_do_y	; 	xjrne tms9918_reduce_do_y
	;
	sub	%r10,0x1	; 	xsub %r10, %r10, 1			; } while(--z)
	jrne	tms9918_reduce_do_z	; 	xjrne tms9918_reduce_do_z
	ret

;****************************************************************************
;	tms9918_update_graphics2
;****************************************************************************

	.global tms9918_update_graphics2
tms9918_update_graphics2:
	pushn %r3
	;
	ext	0x6		; 	xld.ub %r0, [%r12+0x6]		; name_table        = &vram[(reg[2] & 0x0f) << 10]
	ld.ub	%r0,[%r12]
	ext	0x7		; 	xld.ub %r1, [%r12+0x7]		; color_table       = &vram[(reg[3] & 0x80) <<  6]
	ld.ub	%r1,[%r12]
	ext	0x8		; 	xld.ub %r2, [%r12+0x8]		; pattern_generator = &vram[(reg[4] & 0x04) << 11]
	ld.ub	%r2,[%r12]
	ext	0xb		; 	xld.ub %r3, [%r12+0xb]		; backdrop          =        reg[7] & 0x0f
	ld.ub	%r3,[%r12]
	and	%r0,0xf		; 	xand %r0, %r0, 0x0f
	ext	0x2		; 	xand %r1, %r1, 0x80
	and	%r1,0x0
	and	%r2,0x4		; 	xand %r2, %r2, 0x04
	and	%r3,0xf		; 	xand %r3, %r3, 0x0f
	sll	%r0,0x8		; 	xsll %r0, 10
	sll	%r0,0x2
	sll	%r1,0x6		; 	xsll %r1, 6
	sll	%r2,0x8		; 	xsll %r2, 11
	sll	%r2,0x3
	add	%r12,0x10	; 	xadd %r12, %r12, 16
	add %r0, %r12
	add %r1, %r12
	add %r2, %r12
	;
	ld.w	%r4,0x3		; 	xld.w %r4, 3				; block = 3
tms9918_update_graphics2_do_block:		; do {
	;
	ld.w	%r5,0x8		; 	xld.w %r5, 8				; row = 8
tms9918_update_graphics2_do_row:		; do {
	;
	ext	0x0		; 	xld.w %r6, 32				; col = 32
	ld.w	%r6,0x20
tms9918_update_graphics2_do_col:		; do {
	;
	ld.ub %r7, [%r0]+			; code = *name_table++
	;
	ld.w %r10, %r1				; color   = color_table       + code * 8
	ld.w %r11, %r2				; pattern = pattern_generator + code * 8
	sll	%r7,0x3		; 	xsll %r7, 3
	add %r10, %r7
	add %r11, %r7
	;
	ld.w	%r7,0x8		; 	xld.w %r7, 8				; line = 8
tms9918_update_graphics2_do_line:		; do {
	;
	ld.ub %r15, [%r10]+			; c1 = *color++
	ext	0xf		; 	xand %r14, %r15, 0xf			; c0 = c1 & 0xf
	and	%r14,%r15
	jrne.d	tms9918_update_graphics2_c0	; 	xjrne.d tms9918_update_graphics2_c0	; if(!c0) c0 = backdrop
	srl %r15, 4				; c1 >>= 4 *delay*
	ld.w %r14, %r3
tms9918_update_graphics2_c0:
	jrne	tms9918_update_graphics2_c1	; 	xjrne tms9918_update_graphics2_c1	; if(!c1) c1 = backdrop
	ld.w %r15, %r3
tms9918_update_graphics2_c1:
	;
	ext tms9918_grayscale_table@ah		; c0 = tms9918_grayscale_table[c0]
	ext tms9918_grayscale_table@al
	ld.ub %r14, [%r14]
	ext tms9918_grayscale_table@ah		; c1 = tms9918_grayscale_table[c1]
	ext tms9918_grayscale_table@al
	ld.ub %r15, [%r15]
	;
	ld.ub %r12, [%r11]+			; v = *pattern++
	rr	%r12,0x8	; 	xrr %r12, 8				; (%r12[31:24] = v)
	;
	add %r12, %r12				; if(v & 0x80) { *vbuff++ = c1; } else { *vbuff++ = c0; }
	jruge.d 3
	ld.w %r9, %r14
	ld.w %r9, %r15
	ld.b [%r13]+, %r9
	add %r12, %r12				; if(v & 0x40) { *vbuff++ = c1; } else { *vbuff++ = c0; }
	jruge.d 3
	ld.w %r9, %r14
	ld.w %r9, %r15
	ld.b [%r13]+, %r9
	add %r12, %r12				; if(v & 0x20) { *vbuff++ = c1; } else { *vbuff++ = c0; }
	jruge.d 3
	ld.w %r9, %r14
	ld.w %r9, %r15
	ld.b [%r13]+, %r9
	add %r12, %r12				; if(v & 0x10) { *vbuff++ = c1; } else { *vbuff++ = c0; }
	jruge.d 3
	ld.w %r9, %r14
	ld.w %r9, %r15
	ld.b [%r13]+, %r9
	add %r12, %r12				; if(v & 0x08) { *vbuff++ = c1; } else { *vbuff++ = c0; }
	jruge.d 3
	ld.w %r9, %r14
	ld.w %r9, %r15
	ld.b [%r13]+, %r9
	add %r12, %r12				; if(v & 0x04) { *vbuff++ = c1; } else { *vbuff++ = c0; }
	jruge.d 3
	ld.w %r9, %r14
	ld.w %r9, %r15
	ld.b [%r13]+, %r9
	add %r12, %r12				; if(v & 0x02) { *vbuff++ = c1; } else { *vbuff++ = c0; }
	jruge.d 3
	ld.w %r9, %r14
	ld.w %r9, %r15
	ld.b [%r13]+, %r9
	add %r12, %r12				; if(v & 0x01) { *vbuff++ = c1; } else { *vbuff++ = c0; }
	jruge.d 3
	ld.w %r9, %r14
	ld.w %r9, %r15
	ld.b [%r13]+, %r9
	;
	ext	0x3		; 	xadd %r13, %r13, 0xf8			; vbuff += 256 - 8
	add	%r13,0x38
	;
	sub	%r7,0x1		; 	xsub %r7, %r7, 1			; } while(--line)
	jrne	tms9918_update_graphics2_do_line	; 	xjrne tms9918_update_graphics2_do_line
	;
	ext	0x1f		; 	xsub %r13, %r13, 0x7f8		; vbuff -= 256 * 8 - 8
	sub	%r13,0x38
	;
	sub	%r6,0x1		; 	xsub %r6, %r6, 1			; } while(--col)
	jrne	tms9918_update_graphics2_do_col	; 	xjrne tms9918_update_graphics2_do_col
	;
	ext	0x1c		; 	xadd %r13, %r13, 0x700		; vbuff += 256 * 8 - 256
	add	%r13,0x0
	;
	sub	%r5,0x1		; 	xsub %r5, %r5, 1			; } while(--row)
	jrne	tms9918_update_graphics2_do_row	; 	xjrne tms9918_update_graphics2_do_row
	;
	ext	0x20		; 	xadd %r1, %r1, 0x800			; color_table       += 0x800
	add	%r1,0x0
	ext	0x20		; 	xadd %r2, %r2, 0x800			; pattern_generator += 0x800
	add	%r2,0x0
	;
	sub	%r4,0x1		; 	xsub %r4, %r4, 1			; } while(--block)
	jrne	tms9918_update_graphics2_do_block	; 	xjrne tms9918_update_graphics2_do_block
	;
	popn %r3
	ret

;****************************************************************************
;	tms9918_update_sprite10
;****************************************************************************

	.global tms9918_update_sprite10
tms9918_update_sprite10:
	pushn %r3
	;
	sub	%r13,0x1	; 	xsub %r13, %r13, 1			; ★描画ループ中のp++をPSET前の遅延スロットに入れるために、pre-incrementで処理します。★
	;					; ★初回のpre-increment後に描画先矩形の左上原点を指すよう、あらかじめ1引いておきます。★
	;
	ext	0x3		; 	xld.w %r14, 0xf8			; 頻繁に使う値をレジスタに保持
	ld.w	%r14,0x38
	ext	0x3f		; 	xld.w %r15, 0xff8			; 頻繁に使う値をレジスタに保持
	ld.w	%r15,0x38
	;
	ext	0x9		; 	xld.ub %r0, [%r12+0x9]		; attribute_table   = &vram[(reg[5] & 0x7f) <<  7]
	ld.ub	%r0,[%r12]
	ext	0xa		; 	xld.ub %r1, [%r12+0xa]		; pattern_generator = &vram[(reg[6] & 0x07) << 11]
	ld.ub	%r1,[%r12]
	ext	0x1		; 	xand %r0, %r0, 0x7f
	and	%r0,0x3f
	and	%r1,0x7		; 	xand %r1, %r1, 0x07
	sll	%r0,0x7		; 	xsll %r0, 7
	sll	%r1,0x8		; 	xsll %r1, 11
	sll	%r1,0x3
	add	%r12,0x10	; 	xadd %r12, %r12, 16
	add %r0, %r12
	add %r1, %r12
	;
	ext	0x0		; 	xld.w %r2, 32				; sprite = 32
	ld.w	%r2,0x20
tms9918_update_sprite10_L10:			; do { /*sprite*/
	;
	ld.ub %r3, [%r0]+			;   y    = *attribute_table++
	ld.ub %r4, [%r0]+			;   x    = *attribute_table++
	ld.ub %r5, [%r0]+			;   code = *attribute_table++
	ld.ub %r6, [%r0]+			;   c    = *attribute_table++
	;
	ext	0x3		; 	xcmp %r3, 192				;   if(y >= 192) {
	cmp	%r3,0x0
	jrlt	tms9918_update_sprite10_L20	; 	xjrlt tms9918_update_sprite10_L20	;     
	ext	0x3		; 	xcmp %r3, 0xf0			;     if(y <= 256 - 16) {
	cmp	%r3,0x30
	jrgt	tms9918_update_sprite10_L21	; 	xjrgt tms9918_update_sprite10_L21	;       
	ext	0x3		; 	xcmp %r3, 208				;       if(y == 208) break
	cmp	%r3,0x10
	jreq	tms9918_update_sprite10_EXIT	; 	xjreq tms9918_update_sprite10_EXIT	;       
	jp	tms9918_update_sprite10_NEXT	; 	xjp   tms9918_update_sprite10_NEXT	;       continue
tms9918_update_sprite10_L21:			;     }
	ext	0x4		; 	xsub %r3, %r3, 256			;     y -= 256
	sub	%r3,0x0
tms9918_update_sprite10_L20:			;   }
	;
	ext	0x2		; 	xand %r6, %r6, 0x8f			;   c &= 0x8f
	and	%r6,0xf
	;
	cmp	%r6,0xf		; 	xcmp %r6, 15				;   if(c > 15) {
	jrle	tms9918_update_sprite10_L30	; 	xjrle tms9918_update_sprite10_L30	;     
	and	%r6,0xf		; 	xand %r6, %r6, 15			;     c &= 15
	sub	%r4,0x20	; 	xsub %r4, %r4, 32			;     x -= 32
	cmp	%r4,0x30	; 	xcmp %r4, -16				;     if(x <= 0 - 16) continue
	jrle	tms9918_update_sprite10_NEXT	; 	xjrle tms9918_update_sprite10_NEXT	;     
tms9918_update_sprite10_L30:			;   }
	;
	cmp	%r6,0x0		; 	xcmp %r6, 0				;   if(!c) continue
	jreq	tms9918_update_sprite10_NEXT	; 	xjreq tms9918_update_sprite10_NEXT
	;
	ext tms9918_grayscale_table@ah		;   c = tms9918_grayscale_table[c]
	ext tms9918_grayscale_table@al
	ld.ub %r6, [%r6]
	;
	and	%r5,0x3c	; 	xand %r5, %r5, -4			;   code &= ~3
	;
	sll	%r5,0x3		; 	xsll %r5, 3				;   pattern = pattern_generator + code * 8
	add %r5, %r1
	;
	ld.w %r7, %r3				;   p = (vbuff - 1) + y * 256 + x
	sll	%r7,0x8		; 	xsll %r7, 8
	add %r7, %r4
	add %r7, %r13
	;
	ext	0x2		; 	xcmp %r3, 0xb0			;   if((unsigned)y > 192 - 16) goto L50
	cmp	%r3,0x30
	jrugt.d	tms9918_update_sprite10_L50	; 	xjrugt.d tms9918_update_sprite10_L50	;   
	ld.w %r10, 2				;   side = 2 *delay*
	ext	0x3		; 	xcmp %r4, 0xf0			;   if((unsigned)x > 256 - 16) goto L50
	cmp	%r4,0x30
	jrugt	tms9918_update_sprite10_L50	; 	xjrugt   tms9918_update_sprite10_L50
	;
tms9918_update_sprite10_L40:			;   do { /*side*/
	ld.w	%r11,0x10	; 	xld.w %r11, 16				;     line = 16
tms9918_update_sprite10_L41:			;     do { /*line*/
	ld.ub %r9, [%r5]+			;       v = *pattern++
	rr	%r9,0x8		; 	xrr %r9, 8				;       (%r9[31:24] = v)
	add %r9, %r9				;       p++, if(v & 0x80) PSET
	jruge.d 3				;       
	add %r7, 1				;       *delay*
	ld.b [%r7], %r6				;       
	add %r9, %r9				;       p++, if(v & 0x40) PSET
	jruge.d 3				;       
	add %r7, 1				;       *delay*
	ld.b [%r7], %r6				;       
	add %r9, %r9				;       p++, if(v & 0x20) PSET
	jruge.d 3				;       
	add %r7, 1				;       *delay*
	ld.b [%r7], %r6				;       
	add %r9, %r9				;       p++, if(v & 0x10) PSET
	jruge.d 3				;       
	add %r7, 1				;       *delay*
	ld.b [%r7], %r6				;       
	add %r9, %r9				;       p++, if(v & 0x08) PSET
	jruge.d 3				;       
	add %r7, 1				;       *delay*
	ld.b [%r7], %r6				;       
	add %r9, %r9				;       p++, if(v & 0x04) PSET
	jruge.d 3				;       
	add %r7, 1				;       *delay*
	ld.b [%r7], %r6				;       
	add %r9, %r9				;       p++, if(v & 0x02) PSET
	jruge.d 3				;       
	add %r7, 1				;       *delay*
	ld.b [%r7], %r6				;       
	add %r9, %r9				;       p++, if(v & 0x01) PSET
	jruge.d 3				;       
	add %r7, 1				;       *delay*
	ld.b [%r7], %r6				;       
	sub	%r11,0x1	; 	xsub %r11, %r11, 1			;       line--
	jrne.d	tms9918_update_sprite10_L41	; 	xjrne.d tms9918_update_sprite10_L41	;     } while(line)
	add %r7, %r14				;       p += 256 - 8 *delay*
	sub	%r10,0x1	; 	xsub %r10, %r10, 1			;     side--
	jrne.d	tms9918_update_sprite10_L40	; 	xjrne.d tms9918_update_sprite10_L40	;   } while(side)
	sub %r7, %r15				;     p -= 256 * 16 - 8 *delay*
	jp	tms9918_update_sprite10_NEXT	; 	xjp   tms9918_update_sprite10_NEXT	;   goto NEXT
	;
tms9918_update_sprite10_L50:			;   do { /*side*/
	ld.w	%r11,0x10	; 	xld.w %r11, 16				;     line = 16
tms9918_update_sprite10_L51:			;     do { /*line*/
	ld.ub %r9, [%r5]+			;       v = *pattern++
	rr	%r9,0x8		; 	xrr %r9, 8				;       (%r9[31:24] = v)
	ld.w	%r12,0x8	; 	xld.w %r12, 8				;       i = 8
tms9918_update_sprite10_L52:			;       do { /*i*/
	add %r9, %r9				;         if(!(v & 0x80)) goto L43
	jruge.d	tms9918_update_sprite10_L53	; 	xjruge.d tms9918_update_sprite10_L53	;         
	add %r7, 1				;         p++ *delay*
	ext	0x2		; 	xcmp %r3, 191				;         if((unsigned)y > 191) goto L53
	cmp	%r3,0x3f
	jrugt	tms9918_update_sprite10_L53	; 	xjrugt   tms9918_update_sprite10_L53	;         
	ext	0x3		; 	xcmp %r4, 255				;         if((unsigned)x > 255) goto L53
	cmp	%r4,0x3f
	jrugt	tms9918_update_sprite10_L53	; 	xjrugt   tms9918_update_sprite10_L53	;         
	ld.b [%r7], %r6				;         PSET
tms9918_update_sprite10_L53:			;         
	sub	%r12,0x1	; 	xsub %r12, %r12, 1			;         i--
	jrne.d	tms9918_update_sprite10_L52	; 	xjrne.d tms9918_update_sprite10_L52	;       } while(i)
	add %r4, 1				;         x++ *delay*
	add	%r3,0x1		; 	xadd %r3, %r3, 1			;       y += 1
	sub	%r4,0x8		; 	xsub %r4, %r4, 8			;       x -= 8
	sub	%r11,0x1	; 	xsub %r11, %r11, 1			;       line--
	jrne.d	tms9918_update_sprite10_L51	; 	xjrne.d tms9918_update_sprite10_L51	;     } while(line)
	add %r7, %r14				;       p += 256 - 8 *delay*
	sub	%r3,0x10	; 	xsub %r3, %r3, 16			;     y -= 16
	add	%r4,0x8		; 	xadd %r4, %r4, 8			;     x +=  8
	sub	%r10,0x1	; 	xsub %r10, %r10, 1			;     side--
	jrne.d	tms9918_update_sprite10_L50	; 	xjrne.d tms9918_update_sprite10_L50	;   } while(side)
	sub %r7, %r15				;     p -= 256 * 16 - 8 *delay*
	;
tms9918_update_sprite10_NEXT:
	sub	%r2,0x1		; 	xsub %r2, %r2, 1			;   sprite--
	jrne	tms9918_update_sprite10_L10	; 	xjrne tms9918_update_sprite10_L10	; } while(sprite)
	;
tms9918_update_sprite10_EXIT:
	popn %r3
	ret

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

;#endif /*TMS9918_ASM*/
