;	
;	framline.s
;
;	高速Lineルーチン
;
;	CLiP - Common Library for P/ECE
;	Copyright (C) 2001-2004 Naoyuki Sawa
;
;	* Mon Dec 20 19:13:00 JST 2004 Naoyuki Sawa
;	- 1stリリース。
;

; cliprend.hでREND_NOASMの定義有りならば、ここでも定義有りにしてください。
; cliprend.hでREND_NOASMの定義無しならば、ここでも定義無しにしてください。
; cliprend.hでREND_NOASMが定義無しなのにここで定義有りだと、render_lineの二重定義エラーになります。
; cliprend.hでREND_NOASMが定義有りなのにここで定義無しだと、render_lineの定義無しエラーになります。
;#define REND_NOASM
;#ifndef REND_NOASM

;
;	SURFACE構造体
;
;#define W	 0	; (short)
;#define H	 2	; (short)
;#define VBUFF	 4	; (unsigned char*)
; これ以降のフィールドはここでは使いません

;
;	RENDER構造体
;
;#define SURFACE	 0	; (SURFACE*)
;#define LEFT	 4	; (short)
;#define TOP	 6	; (short)
;#define RIGHT	 8	; (short)
;#define BOTTOM	10	; (short)
; これ以降のフィールドはここでは使いません

	.code
	.align 1

; %r10 /= %r11 を行います。
; CLIP0/1マクロから利用する、ローカルサブルーチンです。
div_r10_r11:
	ld.w %alr, %r10
	div0s %r11
	div1 %r11		;  1
	div1 %r11		;  2
	div1 %r11		;  3
	div1 %r11		;  4
	div1 %r11		;  5
	div1 %r11		;  6
	div1 %r11		;  7
	div1 %r11		;  8
	div1 %r11		;  9
	div1 %r11		; 10
	div1 %r11		; 11
	div1 %r11		; 12
	div1 %r11		; 13
	div1 %r11		; 14
	div1 %r11		; 15
	div1 %r11		; 16
	div1 %r11		; 17
	div1 %r11		; 18
	div1 %r11		; 19
	div1 %r11		; 20
	div1 %r11		; 21
	div1 %r11		; 22
	div1 %r11		; 23
	div1 %r11		; 24
	div1 %r11		; 25
	div1 %r11		; 26
	div1 %r11		; 27
	div1 %r11		; 28
	div1 %r11		; 29
	div1 %r11		; 30
	div1 %r11		; 31
	div1 %r11		; 32
	div2s %r11
	div3s
	ret.d
	ld.w %r10, %alr		; *delay* (undoc'd)

; 一軸、一方向のクリッピングを行います。
; [in/out]
;	$1	XA      (始点側の主軸座標)
;	$2	YA      (始点側の副軸座標)
;	$3	XB      (終点側の主軸座標)
;	$4	YB      (終点側の副軸座標)
;	$5	OP      (クリッピング領域の内側判定条件)
;	$6	!OP     (クリッピング領域の外側判定条件)
;	$7	LIM     (クリッピング判定エッジ主軸座標)
;	$8	CLIPPED ((x1,y1)側クリッピングフラグ)
;	$9	EXIT    (完全に領域外だった場合のJump先)
; [use]
;	%r10
;	%r11
;	%alr
;	%ahr
; (x0,y0)側のクリッピングを行います。
;#macro CLIP0 $1, $2, $3, $4, $5, $6, $7, $8, $9
;	cmp $1, $7			; if(!(XA OP LIM)) {
;	xjr$5 $$1			;
;	cmp $3, $7			;   if(!(XB OP LIM)) {
;	xjr$6 $9			;     return
					;   } else {
;	ld.w %r10, $4			;     (YB - YA)
;	sub %r10, $2			;
;	ld.w %r11, $7			;     (LIM - XA)
;	sub %r11, $1			;
	;mlt.w %r10, %r11		;     (YB - YA) * (LIM - XA)
	;↓実用上、(short)×(short)で充分です。
;	mlt.h %r10, %r11		;     (YB - YA) * (LIM - XA)
;	ld.w %r10, %alr			;
;	ld.w %r11, $3			;     (XB - XA)
;	xcall.d div_r10_r11		;     (YB - YA) * (LIM - XA) / (XB - XA)
;	sub %r11, $1			;     *delay*
;	add $2, %r10			;     YA += (YB - YA) * (LIM - XA) / (XB - XA)
;	ld.w $1, $7			;     XA = LIM
	;xoor $8, $8, 1			;     CLIPPED |= 1 ★CLIP0/1で異なるのはここだけ★
					;   }
;$$1:					; }
;#endm
; (x1,y1)側のクリッピングを行います。
;#macro CLIP1 $1, $2, $3, $4, $5, $6, $7, $8, $9
;	cmp $1, $7			; if(!(XA OP LIM)) {
;	xjr$5 $$1			;
;	cmp $3, $7			;   if(!(XB OP LIM)) {
;	xjr$6 $9			;     return
					;   } else {
;	ld.w %r10, $4			;     (YB - YA)
;	sub %r10, $2			;
;	ld.w %r11, $7			;     (LIM - XA)
;	sub %r11, $1			;
	;mlt.w %r10, %r11		;     (YB - YA) * (LIM - XA)
	;↓実用上、(short)×(short)で充分です。
;	mlt.h %r10, %r11		;     (YB - YA) * (LIM - XA)
;	ld.w %r10, %alr			;
;	ld.w %r11, $3			;     (XB - XA)
;	xcall.d div_r10_r11		;     (YB - YA) * (LIM - XA) / (XB - XA)
;	sub %r11, $1			;     *delay*
;	add $2, %r10			;     YA += (YB - YA) * (LIM - XA) / (XB - XA)
;	ld.w $1, $7			;     XA = LIM
;	xoor $8, $8, 1			;     CLIPPED |= 1 ★CLIP0/1で異なるのはここだけ★
					;   }
;$$1:					; }
;#endm

; void render_line(RENDER* render, int x0, int y0, int x1, int y1, int color);
; 手順はC言語版と同じです。clipren2.cのrender_line()の実装を参照してください。
	.global render_line
render_line:
	; %r12 = render
	; %r13 = x0
	; %r14 = y0
	; %r15 = x1
	; [%sp+0] = %pc
	; [%sp+1] = y1
	; [%sp+2] = color
	ld.w %r4, [%sp+0x1]		; y1
	ld.w %r5, [%sp+0x2]		; color
	; %r4  = y1
	; %r5  = color
	; %r12 = render
	; %r13 = x0
	; %r14 = y0
	; %r15 = x1
	ld.w	%r6,0x0		; 	xld.w %r6, 0							; clipped = 0
	ext	0x4		; 	xld.h %r7, [%r12+0x4]						; left
	ld.h	%r7,[%r12]
	cmp %r13, %r7			; if(!(XA OP LIM)) {	; 	CLIP0 %r13, %r14, %r15, %r4, ge, lt, %r7, %r6, render_line_EXIT	; CLIP(x, y, 0, 1, >=, render->left)
	jrge	__LX0001	; 	xjrge __L0001			;
	cmp %r15, %r7			;   if(!(XB OP LIM)) {
	ext	render_line_EXIT@rm	; 	xjrlt render_line_EXIT			;     return
	jrlt	render_line_EXIT@rl
					;   } else {
	ld.w %r10, %r4			;     (YB - YA)
	sub %r10, %r14			;
	ld.w %r11, %r7			;     (LIM - XA)
	sub %r11, %r13			;
	;mlt.w %r10, %r11		;     (YB - YA) * (LIM - XA)
	;↓実用上、(short)×(short)で充分です。
	mlt.h %r10, %r11		;     (YB - YA) * (LIM - XA)
	ld.w %r10, %alr			;
	ld.w %r11, %r15			;     (XB - XA)
	call.d	div_r10_r11	; 	xcall.d div_r10_r11		;     (YB - YA) * (LIM - XA) / (XB - XA)
	sub %r11, %r13			;     *delay*
	add %r14, %r10			;     YA += (YB - YA) * (LIM - XA) / (XB - XA)
	ld.w %r13, %r7			;     XA = LIM
	;xoor $8, $8, 1			;     CLIPPED |= 1 ★CLIP0/1で異なるのはここだけ★
					;   }
__LX0001:				; __L0001:					; }
	cmp %r15, %r7			; if(!(XA OP LIM)) {	; 	CLIP1 %r15, %r4, %r13, %r14, ge, lt, %r7, %r6, render_line_EXIT	; CLIP(x, y, 1, 0, >=, render->left)
	jrge	__LX0002	; 	xjrge __L0002			;
	cmp %r13, %r7			;   if(!(XB OP LIM)) {
	ext	render_line_EXIT@rm	; 	xjrlt render_line_EXIT			;     return
	jrlt	render_line_EXIT@rl
					;   } else {
	ld.w %r10, %r14			;     (YB - YA)
	sub %r10, %r4			;
	ld.w %r11, %r7			;     (LIM - XA)
	sub %r11, %r15			;
	;mlt.w %r10, %r11		;     (YB - YA) * (LIM - XA)
	;↓実用上、(short)×(short)で充分です。
	mlt.h %r10, %r11		;     (YB - YA) * (LIM - XA)
	ld.w %r10, %alr			;
	ld.w %r11, %r13			;     (XB - XA)
	call.d	div_r10_r11	; 	xcall.d div_r10_r11		;     (YB - YA) * (LIM - XA) / (XB - XA)
	sub %r11, %r15			;     *delay*
	add %r4, %r10			;     YA += (YB - YA) * (LIM - XA) / (XB - XA)
	ld.w %r15, %r7			;     XA = LIM
	or	%r6,0x1		; 	xoor %r6, %r6, 1			;     CLIPPED |= 1 ★CLIP0/1で異なるのはここだけ★
					;   }
__LX0002:				; __L0002:					; }
	ext	0x8		; 	xld.h %r7, [%r12+0x8]						; right-1
	ld.h	%r7,[%r12]
	sub	%r7,0x1		; 	xsub %r7, %r7, 1						;
	cmp %r15, %r7			; if(!(XA OP LIM)) {	; 	CLIP1 %r15, %r4, %r13, %r14, le, gt, %r7, %r6, render_line_EXIT	; CLIP(x, y, 1, 0, <=, render->right - 1)
	jrle	__LX0003	; 	xjrle __L0003			;
	cmp %r13, %r7			;   if(!(XB OP LIM)) {
	ext	render_line_EXIT@rm	; 	xjrgt render_line_EXIT			;     return
	jrgt	render_line_EXIT@rl
					;   } else {
	ld.w %r10, %r14			;     (YB - YA)
	sub %r10, %r4			;
	ld.w %r11, %r7			;     (LIM - XA)
	sub %r11, %r15			;
	;mlt.w %r10, %r11		;     (YB - YA) * (LIM - XA)
	;↓実用上、(short)×(short)で充分です。
	mlt.h %r10, %r11		;     (YB - YA) * (LIM - XA)
	ld.w %r10, %alr			;
	ld.w %r11, %r13			;     (XB - XA)
	call.d	div_r10_r11	; 	xcall.d div_r10_r11		;     (YB - YA) * (LIM - XA) / (XB - XA)
	sub %r11, %r15			;     *delay*
	add %r4, %r10			;     YA += (YB - YA) * (LIM - XA) / (XB - XA)
	ld.w %r15, %r7			;     XA = LIM
	or	%r6,0x1		; 	xoor %r6, %r6, 1			;     CLIPPED |= 1 ★CLIP0/1で異なるのはここだけ★
					;   }
__LX0003:				; __L0003:					; }
	cmp %r13, %r7			; if(!(XA OP LIM)) {	; 	CLIP0 %r13, %r14, %r15, %r4, le, gt, %r7, %r6, render_line_EXIT	; CLIP(x, y, 0, 1, <=, render->right - 1)
	jrle	__LX0004	; 	xjrle __L0004			;
	cmp %r15, %r7			;   if(!(XB OP LIM)) {
	ext	render_line_EXIT@rm	; 	xjrgt render_line_EXIT			;     return
	jrgt	render_line_EXIT@rl
					;   } else {
	ld.w %r10, %r4			;     (YB - YA)
	sub %r10, %r14			;
	ld.w %r11, %r7			;     (LIM - XA)
	sub %r11, %r13			;
	;mlt.w %r10, %r11		;     (YB - YA) * (LIM - XA)
	;↓実用上、(short)×(short)で充分です。
	mlt.h %r10, %r11		;     (YB - YA) * (LIM - XA)
	ld.w %r10, %alr			;
	ld.w %r11, %r15			;     (XB - XA)
	call.d	div_r10_r11	; 	xcall.d div_r10_r11		;     (YB - YA) * (LIM - XA) / (XB - XA)
	sub %r11, %r13			;     *delay*
	add %r14, %r10			;     YA += (YB - YA) * (LIM - XA) / (XB - XA)
	ld.w %r13, %r7			;     XA = LIM
	;xoor $8, $8, 1			;     CLIPPED |= 1 ★CLIP0/1で異なるのはここだけ★
					;   }
__LX0004:				; __L0004:					; }
	ext	0x6		; 	xld.h %r7, [%r12+0x6]						; top
	ld.h	%r7,[%r12]
	cmp %r14, %r7			; if(!(XA OP LIM)) {	; 	CLIP0 %r14, %r13, %r4, %r15, ge, lt, %r7, %r6, render_line_EXIT	; CLIP(y, x, 0, 1, >=, render->top)
	jrge	__LX0005	; 	xjrge __L0005			;
	cmp %r4, %r7			;   if(!(XB OP LIM)) {
	jrlt	render_line_EXIT	; 	xjrlt render_line_EXIT			;     return
					;   } else {
	ld.w %r10, %r15			;     (YB - YA)
	sub %r10, %r13			;
	ld.w %r11, %r7			;     (LIM - XA)
	sub %r11, %r14			;
	;mlt.w %r10, %r11		;     (YB - YA) * (LIM - XA)
	;↓実用上、(short)×(short)で充分です。
	mlt.h %r10, %r11		;     (YB - YA) * (LIM - XA)
	ld.w %r10, %alr			;
	ld.w %r11, %r4			;     (XB - XA)
	call.d	div_r10_r11	; 	xcall.d div_r10_r11		;     (YB - YA) * (LIM - XA) / (XB - XA)
	sub %r11, %r14			;     *delay*
	add %r13, %r10			;     YA += (YB - YA) * (LIM - XA) / (XB - XA)
	ld.w %r14, %r7			;     XA = LIM
	;xoor $8, $8, 1			;     CLIPPED |= 1 ★CLIP0/1で異なるのはここだけ★
					;   }
__LX0005:				; __L0005:					; }
	cmp %r4, %r7			; if(!(XA OP LIM)) {	; 	CLIP1 %r4, %r15, %r14, %r13, ge, lt, %r7, %r6, render_line_EXIT	; CLIP(y, x, 1, 0, >=, render->top)
	jrge	__LX0006	; 	xjrge __L0006			;
	cmp %r14, %r7			;   if(!(XB OP LIM)) {
	jrlt	render_line_EXIT	; 	xjrlt render_line_EXIT			;     return
					;   } else {
	ld.w %r10, %r13			;     (YB - YA)
	sub %r10, %r15			;
	ld.w %r11, %r7			;     (LIM - XA)
	sub %r11, %r4			;
	;mlt.w %r10, %r11		;     (YB - YA) * (LIM - XA)
	;↓実用上、(short)×(short)で充分です。
	mlt.h %r10, %r11		;     (YB - YA) * (LIM - XA)
	ld.w %r10, %alr			;
	ld.w %r11, %r14			;     (XB - XA)
	ext	div_r10_r11@rm	; 	xcall.d div_r10_r11		;     (YB - YA) * (LIM - XA) / (XB - XA)
	call.d	div_r10_r11@rl
	sub %r11, %r4			;     *delay*
	add %r15, %r10			;     YA += (YB - YA) * (LIM - XA) / (XB - XA)
	ld.w %r4, %r7			;     XA = LIM
	or	%r6,0x1		; 	xoor %r6, %r6, 1			;     CLIPPED |= 1 ★CLIP0/1で異なるのはここだけ★
					;   }
__LX0006:				; __L0006:					; }
	ext	0xa		; 	xld.h %r7, [%r12+0xa]					; bottom-1
	ld.h	%r7,[%r12]
	sub	%r7,0x1		; 	xsub %r7, %r7, 1						;
	cmp %r14, %r7			; if(!(XA OP LIM)) {	; 	CLIP0 %r14, %r13, %r4, %r15, le, gt, %r7, %r6, render_line_EXIT	; CLIP(y, x, 0, 1, <=, render->bottom - 1)
	jrle	__LX0007	; 	xjrle __L0007			;
	cmp %r4, %r7			;   if(!(XB OP LIM)) {
	jrgt	render_line_EXIT	; 	xjrgt render_line_EXIT			;     return
					;   } else {
	ld.w %r10, %r15			;     (YB - YA)
	sub %r10, %r13			;
	ld.w %r11, %r7			;     (LIM - XA)
	sub %r11, %r14			;
	;mlt.w %r10, %r11		;     (YB - YA) * (LIM - XA)
	;↓実用上、(short)×(short)で充分です。
	mlt.h %r10, %r11		;     (YB - YA) * (LIM - XA)
	ld.w %r10, %alr			;
	ld.w %r11, %r4			;     (XB - XA)
	ext	div_r10_r11@rm	; 	xcall.d div_r10_r11		;     (YB - YA) * (LIM - XA) / (XB - XA)
	call.d	div_r10_r11@rl
	sub %r11, %r14			;     *delay*
	add %r13, %r10			;     YA += (YB - YA) * (LIM - XA) / (XB - XA)
	ld.w %r14, %r7			;     XA = LIM
	;xoor $8, $8, 1			;     CLIPPED |= 1 ★CLIP0/1で異なるのはここだけ★
					;   }
__LX0007:				; __L0007:					; }
	cmp %r4, %r7			; if(!(XA OP LIM)) {	; 	CLIP1 %r4, %r15, %r14, %r13, le, gt, %r7, %r6, render_line_EXIT	; CLIP(y, x, 1, 0, <=, render->bottom - 1)
	jrle	__LX0008	; 	xjrle __L0008			;
	cmp %r14, %r7			;   if(!(XB OP LIM)) {
	jrgt	render_line_EXIT	; 	xjrgt render_line_EXIT			;     return
					;   } else {
	ld.w %r10, %r13			;     (YB - YA)
	sub %r10, %r15			;
	ld.w %r11, %r7			;     (LIM - XA)
	sub %r11, %r4			;
	;mlt.w %r10, %r11		;     (YB - YA) * (LIM - XA)
	;↓実用上、(short)×(short)で充分です。
	mlt.h %r10, %r11		;     (YB - YA) * (LIM - XA)
	ld.w %r10, %alr			;
	ld.w %r11, %r14			;     (XB - XA)
	ext	div_r10_r11@rm	; 	xcall.d div_r10_r11		;     (YB - YA) * (LIM - XA) / (XB - XA)
	call.d	div_r10_r11@rl
	sub %r11, %r4			;     *delay*
	add %r15, %r10			;     YA += (YB - YA) * (LIM - XA) / (XB - XA)
	ld.w %r4, %r7			;     XA = LIM
	or	%r6,0x1		; 	xoor %r6, %r6, 1			;     CLIPPED |= 1 ★CLIP0/1で異なるのはここだけ★
					;   }
__LX0008:				; __L0008:					; }
	; %r4  = y1
	; %r5  = color
	; %r6  = clipped
	; %r12 = render
	; %r13 = x0
	; %r14 = y0
	; %r15 = x1
	ld.w	%r12,[%r12]	; 	xld.w %r12, [%r12+0x0]	; surface
	ld.h	%r11,[%r12]	; 	xld.h %r11, [%r12+0x0]		; w (あとでまた使います。破壊しないように!!)
	ext	0x4		; 	xld.w %r12, [%r12+0x4]	; vbuff *anti-interlock*
	ld.w	%r12,[%r12]
	;mlt.w %r11, %r14		; w * y0
	;↓実用上、(short)×(short)で充分です。
	mlt.h %r11, %r14		; w * y0
	ld.w %r10, %alr			;
	add %r12, %r10			; vptr = vbuff + w * y0 + x0
	add %r12, %r13
	; %r4  = y1
	; %r5  = color
	; %r6  = clipped
	; %r11 = w
	; %r12 = vptr
	; %r13 = x0
	; %r14 = y0
	; %r15 = x1
	sub %r15, %r13			; nx = x1 - x0, ux = 1
	jrge.d	render_line_L10	; 	xjrge.d render_line_L10		; if(x1 < x0) {
	ld.w %r10, 1			; *delay*
	not %r15, %r15			;   nx = x0 - x1
	add	%r15,0x1	; 	xadd %r15, %r15, 1		;
	ld.w	%r10,0x3f	; 	xld.w %r10, -1			;   ux = -1
render_line_L10:			; }
	sub %r4, %r14			; ny = y1 - y0, uy = w
	jrge	render_line_L20	; 	xjrge render_line_L20		; if(y1 < y0) {
	not %r4, %r4			;   ny = y0 - y1
	add	%r4,0x1		; 	xadd %r4, %r4, 1		;
	not %r11, %r11			;   uy = -w
	add	%r11,0x1	; 	xadd %r11, %r11, 1		;
render_line_L20:			; }
	; %r4  = ny
	; %r5  = color
	; %r6  = clipped
	; %r10 = ux
	; %r11 = uy
	; %r12 = vptr
	; %r13 = x0 -> もう不要
	; %r14 = y0 -> もう不要
	; %r15 = nx
	cmp %r15, %r4			; if(nx < ny) {
	jrge	render_line_L30	; 	xjrge render_line_L30		;
	xor %r15, %r4			;   nx <=> ny
	xor %r4, %r15			;
	xor %r15, %r4			;
	xor %r10, %r11			;   ux <=> uy
	xor %r11, %r10			;
	xor %r10, %r11			;
render_line_L30:			; }
	cmp	%r15,0x0	; 	xcmp %r15, 0			; if(nx == 0)
	jreq	render_line_EXIT	; 	xjreq render_line_EXIT		;   return
	; %r4  = ny
	; %r5  = color
	; %r6  = clipped
	; %r10 = ux
	; %r11 = uy
	; %r12 = vptr
	; %r15 = nx
	ld.w %r7, %r15			; d = nx
	add %r6, %r15			; n = nx + clipped
	add %r15, %r15			; nx * 2
	add %r4, %r4			; ny * 2
	; %r4  = ny * 2
	; %r5  = color
	; %r6  = n
	; %r7  = d
	; %r10 = ux
	; %r11 = uy
	; %r12 = vptr
	; %r15 = nx * 2
;{{DelaySlotを使わない素直なコード
;render_line_L40:			; do {
;	ld.b [%r12], %r5		;   *vptr = color
;	sub %r7, %r4			;   d -= ny * 2
;	xjrgt.d render_line_L50		;   if(d <= 0) {
;	add %r12, %r10			;   vptr += ux *delay*
;	add %r12, %r11			;     vptr += uy
;	add %r7, %r15			;     d += nx * 2
;render_line_L50:			;   }
;	xsub %r6, %r6, 1		; } while(--n)
;	xjrne render_line_L40
;}}DelaySlotを使わない素直なコード
;{{DelaySlotを使い高速化したコード
	sub %r7, %r4			;   d -= ny * 2 (初回分)
render_line_L40:			; do {
	ld.b [%r12], %r5		;   *vptr = color (sub %r7,%r4の結果フラグを壊さないように!!)
	;sub %r7, %r4			;   d -= ny * 2 (初回分は↑、二回目以降は↓のDelaySlotに分離)
	jrgt.d	render_line_L50	; 	xjrgt.d render_line_L50		;   if(d <= 0) {
	add %r12, %r10			;   vptr += ux *delay*
	add %r12, %r11			;     vptr += uy
	add %r7, %r15			;     d += nx * 2
render_line_L50:			;   }
	sub	%r6,0x1		; 	xsub %r6, %r6, 1		; } while(--n)
	jrne.d	render_line_L40	; 	xjrne.d render_line_L40		;
	sub %r7, %r4			;   d -= ny * 2 (二回目以降) *delay*
;}}DelaySlotを使い高速化したコード
render_line_EXIT:
	ret

;#endif REND_NOASM
