/*	
 *	framdraw.c
 *
 *	16階調描画
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2005 Naoyuki Sawa
 *
 *	* Tue Jun 4 21:28:00 JST 2005 Naoyuki Sawa
 *	- 4bit描画ルーチン(PDW_Draw_4BN)を、framldir.cからframdraw.cへ移動しました。
 *	  4bit描画ルーチンを使わない16諧調表示アプリケーション(エミュレータなど)で、
 *	  4bit描画ルーチンが高速RAMを圧迫するのを避けるためです。
 *	- 4bit描画ルーチンを使わない16諧調表示アプリケーションは、
 *	  framldir.oを高速RAMに配置し、framdraw.cはSRAMに配置してください。
 *	* Tue Oct 23 12:54:59 JST 2007 Naoyuki Sawa
 *	- PDW_Draw_4BN()をASM化しました。
 *	- これまで本モジュールに対して適用していた、sedによるmlt.w→mlt.h変換が不要になりました。
 *	  従って、Makefileのframdraw.o生成規則を修正しました。
 */
#include "clip.h"

/****************************************************************************
 *	pceLCDDrawObject() 4bit描画サポート
 ****************************************************************************/

/* clipldir.c内のnew_pceLCDDrawObject()から呼び出されます。
 * * クリッピング処理は、呼び出される前にnew_pceLCDDrawObject()にて完了しています。
 * * DRAW_OBJECT.destは、new_LCDDrawObject()にて確実に有効値に設定されています。
 *   PDW_Draw_4BN()では、DRAW_OBJECT.destの規定値を取得する処理を行う必要はありません。
 */

/*{{2007/10/23:ASM化に伴い削除。これまで安定動作していたので、参考に残しておきます。*/
//void
//PDW_Draw_4BN(DRAW_OBJECT obj)
//{
//	int n, x, y, step, dest_stride, src_stride;
//	unsigned char *dest_buf, *src_mask, mask;
//	unsigned int *src_buf, pixel;
//
//	/* 転送元原点が、転送元画像の水平8ピクセル単位のうち何ピクセル目から開始するか？ */
//	step = obj.sx & 7;
//
//	/* 転送元ピクセルアドレスを求めます。 */
//	n = (obj.src->header.w * obj.sy + obj.sx) / 8;
//	src_buf = (unsigned int*)obj.src->buf + n;
//	src_mask = obj.src->mask + n;
//	src_stride = obj.src->header.w / 8 - (step + obj.dw - 1) / 8;
//	/*                                                  ~~~         */
//	/* 8ステップ完了時に進むのではなく、9ステップ目の先頭で進むから */
//
//	/* 残り転送ライン数を用意しておきます。 */
//	y = obj.dh;
//
//	/* 反転方向によって、処理を分けます。(※DRW_NOMAL=0と仮定)
//	 * 反転方向以外のフラグが指定されていたら、本物に任せます。
//	 */
//	switch(obj.param) {
//	case 0/*反転なし*/:
//		/* 転送先ピクセルアドレスを求めます。 */
//		dest_buf = obj.dest->buf + obj.dest->w * obj.dy + obj.dx;
//		dest_stride = obj.dest->w - obj.dw;
//
//		if(obj.src->header.mask) {
//			do {
//				/* 開始点から始まるか途中から始まるかわからないので、
//				 * 初回はたとえstep=0でも、ここで最初のデータを取得することにします。
//				 */
//				pixel = *src_buf;	/* ピクセル並びは MSB:67452301:LSB の順です */
//				mask = *src_mask;	/* ピクセル並びは MSB:01234567:LSB の順です */
//
//				/* 残り水平ピクセル数を取得します。 */
//				x = obj.dw;
//
//				/* 何ピクセル目から開始するかによって、適切な位置へ飛び込みます。 */
//				switch(step) {
//LOOP_00: /* 初回はここは飛び越します */
//					/* 8ピクセル単位の開始点で、次のデータを取得します。 */
//					pixel = *++src_buf;
//					mask = *++src_mask;
//#define PIXEL(p, m) \
//					/* 不透明ピクセルなら、描きます。 */ \
//					if(mask & (1 << (m))) *dest_buf = pixel >> (p) * 4 & 15; \
//					dest_buf++; \
//					/* 1ライン転送完了したら、抜けます。 */ \
//					if(--x == 0) break;
//				case 0:       PIXEL(1, 7);
//				case 1:       PIXEL(0, 6);
//				case 2:       PIXEL(3, 5);
//				case 3:       PIXEL(2, 4);
//				case 4:       PIXEL(5, 3);
//				case 5:       PIXEL(4, 2);
//				case 6:       PIXEL(7, 1);
//				default/*7*/: PIXEL(6, 0); goto LOOP_00;
//#undef PIXEL
//				}
//
//				/* 転送先・転送元ピクセルアドレスを次のラインへ進めます。 */
//				dest_buf += dest_stride;
//				src_buf += src_stride;
//				src_mask += src_stride;
//			} while(--y != 0);
//		} else {
//			do {
//				/* 開始点から始まるか途中から始まるかわからないので、
//				 * 初回はたとえstep=0でも、ここで最初のデータを取得することにします。
//				 */
//				pixel = *src_buf;	/* ピクセル並びは MSB:67452301:LSB の順です */
//
//				/* 残り水平ピクセル数を取得します。 */
//				x = obj.dw;
//
//				/* 何ピクセル目から開始するかによって、適切な位置へ飛び込みます。 */
//				switch(step) {
//LOOP_01: /* 初回はここは飛び越します */
//					/* 8ピクセル単位の開始点で、次のデータを取得します。 */
//					pixel = *++src_buf;
//#define PIXEL(p) \
//					/* ピクセルを、描きます。 */ \
//					*dest_buf++ = pixel >> (p) * 4 & 15; \
//					/* 1ライン転送完了したら、抜けます。 */ \
//					if(--x == 0) break;
//				case 0:       PIXEL(1);
//				case 1:       PIXEL(0);
//				case 2:       PIXEL(3);
//				case 3:       PIXEL(2);
//				case 4:       PIXEL(5);
//				case 5:       PIXEL(4);
//				case 6:       PIXEL(7);
//				default/*7*/: PIXEL(6); goto LOOP_01;
//#undef PIXEL
//				}
//
//				/* 転送先・転送元ピクセルアドレスを次のラインへ進めます。 */
//				dest_buf += dest_stride;
//				src_buf += src_stride;
//			} while(--y != 0);
//		}
//		break;
//
//	case DRW_REVX:
//		/* 転送先ピクセルアドレスを求めます。 */
//		dest_buf = obj.dest->buf + obj.dest->w * obj.dy + obj.dx + obj.dw - 1;
//		dest_stride = obj.dest->w + obj.dw;
//
//		if(obj.src->header.mask) {
//			do {
//				/* 開始点から始まるか途中から始まるかわからないので、
//				 * 初回はたとえstep=0でも、ここで最初のデータを取得することにします。
//				 */
//				pixel = *src_buf;	/* ピクセル並びは MSB:67452301:LSB の順です */
//				mask = *src_mask;	/* ピクセル並びは MSB:01234567:LSB の順です */
//
//				/* 残り水平ピクセル数を取得します。 */
//				x = obj.dw;
//
//				/* 何ピクセル目から開始するかによって、適切な位置へ飛び込みます。 */
//				switch(step) {
//LOOP_10: /* 初回はここは飛び越します */
//					/* 8ピクセル単位の開始点で、次のデータを取得します。 */
//					pixel = *++src_buf;
//					mask = *++src_mask;
//#define PIXEL(p, m) \
//					/* 不透明ピクセルなら、描きます。 */ \
//					if(mask & (1 << (m))) *dest_buf = pixel >> (p) * 4 & 15; \
//					dest_buf--; \
//					/* 1ライン転送完了したら、抜けます。 */ \
//					if(--x == 0) break;
//				case 0:       PIXEL(1, 7);
//				case 1:       PIXEL(0, 6);
//				case 2:       PIXEL(3, 5);
//				case 3:       PIXEL(2, 4);
//				case 4:       PIXEL(5, 3);
//				case 5:       PIXEL(4, 2);
//				case 6:       PIXEL(7, 1);
//				default/*7*/: PIXEL(6, 0); goto LOOP_10;
//#undef PIXEL
//				}
//
//				/* 転送先・転送元ピクセルアドレスを次のラインへ進めます。 */
//				dest_buf += dest_stride;
//				src_buf += src_stride;
//				src_mask += src_stride;
//			} while(--y != 0);
//		} else {
//			do {
//				/* 開始点から始まるか途中から始まるかわからないので、
//				 * 初回はたとえstep=0でも、ここで最初のデータを取得することにします。
//				 */
//				pixel = *src_buf;	/* ピクセル並びは MSB:67452301:LSB の順です */
//
//				/* 残り水平ピクセル数を取得します。 */
//				x = obj.dw;
//
//				/* 何ピクセル目から開始するかによって、適切な位置へ飛び込みます。 */
//				switch(step) {
//LOOP_11: /* 初回はここは飛び越します */
//					/* 8ピクセル単位の開始点で、次のデータを取得します。 */
//					pixel = *++src_buf;
//#define PIXEL(p) \
//					/* ピクセルを、描きます。 */ \
//					*dest_buf-- = pixel >> (p) * 4 & 15; \
//					/* 1ライン転送完了したら、抜けます。 */ \
//					if(--x == 0) break;
//				case 0:       PIXEL(1);
//				case 1:       PIXEL(0);
//				case 2:       PIXEL(3);
//				case 3:       PIXEL(2);
//				case 4:       PIXEL(5);
//				case 5:       PIXEL(4);
//				case 6:       PIXEL(7);
//				default/*7*/: PIXEL(6); goto LOOP_11;
//#undef PIXEL
//				}
//
//				/* 転送先・転送元ピクセルアドレスを次のラインへ進めます。 */
//				dest_buf += dest_stride;
//				src_buf += src_stride;
//			} while(--y != 0);
//		}
//		break;
//
//	case DRW_REVY:
//		/* 転送先ピクセルアドレスを求めます。 */
//		dest_buf = obj.dest->buf + obj.dest->w * (obj.dy + obj.dh - 1) + obj.dx;
//		dest_stride = -obj.dest->w - obj.dw;
//
//		if(obj.src->header.mask) {
//			do {
//				/* 開始点から始まるか途中から始まるかわからないので、
//				 * 初回はたとえstep=0でも、ここで最初のデータを取得することにします。
//				 */
//				pixel = *src_buf;	/* ピクセル並びは MSB:67452301:LSB の順です */
//				mask = *src_mask;	/* ピクセル並びは MSB:01234567:LSB の順です */
//
//				/* 残り水平ピクセル数を取得します。 */
//				x = obj.dw;
//
//				/* 何ピクセル目から開始するかによって、適切な位置へ飛び込みます。 */
//				switch(step) {
//LOOP_20: /* 初回はここは飛び越します */
//					/* 8ピクセル単位の開始点で、次のデータを取得します。 */
//					pixel = *++src_buf;
//					mask = *++src_mask;
//#define PIXEL(p, m) \
//					/* 不透明ピクセルなら、描きます。 */ \
//					if(mask & (1 << (m))) *dest_buf = pixel >> (p) * 4 & 15; \
//					dest_buf++; \
//					/* 1ライン転送完了したら、抜けます。 */ \
//					if(--x == 0) break;
//				case 0:       PIXEL(1, 7);
//				case 1:       PIXEL(0, 6);
//				case 2:       PIXEL(3, 5);
//				case 3:       PIXEL(2, 4);
//				case 4:       PIXEL(5, 3);
//				case 5:       PIXEL(4, 2);
//				case 6:       PIXEL(7, 1);
//				default/*7*/: PIXEL(6, 0); goto LOOP_20;
//#undef PIXEL
//				}
//
//				/* 転送先・転送元ピクセルアドレスを次のラインへ進めます。 */
//				dest_buf += dest_stride;
//				src_buf += src_stride;
//				src_mask += src_stride;
//			} while(--y != 0);
//		} else {
//			do {
//				/* 開始点から始まるか途中から始まるかわからないので、
//				 * 初回はたとえstep=0でも、ここで最初のデータを取得することにします。
//				 */
//				pixel = *src_buf;	/* ピクセル並びは MSB:67452301:LSB の順です */
//
//				/* 残り水平ピクセル数を取得します。 */
//				x = obj.dw;
//
//				/* 何ピクセル目から開始するかによって、適切な位置へ飛び込みます。 */
//				switch(step) {
//LOOP_21: /* 初回はここは飛び越します */
//					/* 8ピクセル単位の開始点で、次のデータを取得します。 */
//					pixel = *++src_buf;
//#define PIXEL(p) \
//					/* ピクセルを、描きます。 */ \
//					*dest_buf++ = pixel >> (p) * 4 & 15; \
//					/* 1ライン転送完了したら、抜けます。 */ \
//					if(--x == 0) break;
//				case 0:       PIXEL(1);
//				case 1:       PIXEL(0);
//				case 2:       PIXEL(3);
//				case 3:       PIXEL(2);
//				case 4:       PIXEL(5);
//				case 5:       PIXEL(4);
//				case 6:       PIXEL(7);
//				default/*7*/: PIXEL(6); goto LOOP_21;
//#undef PIXEL
//				}
//
//				/* 転送先・転送元ピクセルアドレスを次のラインへ進めます。 */
//				dest_buf += dest_stride;
//				src_buf += src_stride;
//			} while(--y != 0);
//		}
//		break;
//
//	case DRW_REVX | DRW_REVY:
//		/* 転送先ピクセルアドレスを求めます。 */
//		dest_buf = obj.dest->buf + obj.dest->w * (obj.dy + obj.dh - 1) + obj.dx + obj.dw - 1;
//		dest_stride = -obj.dest->w + obj.dw;
//
//		if(obj.src->header.mask) {
//			do {
//				/* 開始点から始まるか途中から始まるかわからないので、
//				 * 初回はたとえstep=0でも、ここで最初のデータを取得することにします。
//				 */
//				pixel = *src_buf;	/* ピクセル並びは MSB:67452301:LSB の順です */
//				mask = *src_mask;	/* ピクセル並びは MSB:01234567:LSB の順です */
//
//				/* 残り水平ピクセル数を取得します。 */
//				x = obj.dw;
//
//				/* 何ピクセル目から開始するかによって、適切な位置へ飛び込みます。 */
//				switch(step) {
//LOOP_30: /* 初回はここは飛び越します */
//					/* 8ピクセル単位の開始点で、次のデータを取得します。 */
//					pixel = *++src_buf;
//					mask = *++src_mask;
//#define PIXEL(p, m) \
//					/* 不透明ピクセルなら、描きます。 */ \
//					if(mask & (1 << (m))) *dest_buf = pixel >> (p) * 4 & 15; \
//					dest_buf--; \
//					/* 1ライン転送完了したら、抜けます。 */ \
//					if(--x == 0) break;
//				case 0:       PIXEL(1, 7);
//				case 1:       PIXEL(0, 6);
//				case 2:       PIXEL(3, 5);
//				case 3:       PIXEL(2, 4);
//				case 4:       PIXEL(5, 3);
//				case 5:       PIXEL(4, 2);
//				case 6:       PIXEL(7, 1);
//				default/*7*/: PIXEL(6, 0); goto LOOP_30;
//#undef PIXEL
//				}
//
//				/* 転送先・転送元ピクセルアドレスを次のラインへ進めます。 */
//				dest_buf += dest_stride;
//				src_buf += src_stride;
//				src_mask += src_stride;
//			} while(--y != 0);
//		} else {
//			do {
//				/* 開始点から始まるか途中から始まるかわからないので、
//				 * 初回はたとえstep=0でも、ここで最初のデータを取得することにします。
//				 */
//				pixel = *src_buf;	/* ピクセル並びは MSB:67452301:LSB の順です */
//
//				/* 残り水平ピクセル数を取得します。 */
//				x = obj.dw;
//
//				/* 何ピクセル目から開始するかによって、適切な位置へ飛び込みます。 */
//				switch(step) {
//LOOP_31: /* 初回はここは飛び越します */
//					/* 8ピクセル単位の開始点で、次のデータを取得します。 */
//					pixel = *++src_buf;
//#define PIXEL(p) \
//					/* ピクセルを、描きます。 */ \
//					*dest_buf-- = pixel >> (p) * 4 & 15; \
//					/* 1ライン転送完了したら、抜けます。 */ \
//					if(--x == 0) break;
//				case 0:       PIXEL(1);
//				case 1:       PIXEL(0);
//				case 2:       PIXEL(3);
//				case 3:       PIXEL(2);
//				case 4:       PIXEL(5);
//				case 5:       PIXEL(4);
//				case 6:       PIXEL(7);
//				default/*7*/: PIXEL(6); goto LOOP_31;
//#undef PIXEL
//				}
//
//				/* 転送先・転送元ピクセルアドレスを次のラインへ進めます。 */
//				dest_buf += dest_stride;
//				src_buf += src_stride;
//			} while(--y != 0);
//		}
//		break;
//	}
//}
/*}}2007/10/23:ASM化に伴い削除。これまで安定動作していたので、参考に残しておきます。*/

/* * Tue Oct 23 12:54:59 JST 2007 Naoyuki Sawa
 * - PDW_Draw_4BN()をASM化しました。
 * - ASM版は、C版に較べて、5〜15%ぐらい低速です。
 *   低速になった理由は、C版ではループ展開を多用したところを、ASM版はループを回しているからです。
 * - その代わりに、ASM版は、C版に較べて、大幅にコードサイズが小さくなりました。
 *   本モジュールのサイズが、C版は2140バイトだったのに較べ、ASM版は300バイトになりました。
 * - 少しの速度低下よりも、大幅なコードサイズ低減の利点を優先して、ASM版を採用することにしました。
 *   本モジュールは通常、高速RAMに転送して使用するため、サイズ効率が重要と考えたからです。
 *   PDW_Draw_4BN()が少し低速になっても、高速RAMに空き領域が増える分、他のモジュールを転送したり、
 *   あるいはユーザースタックを高速RAMに設定することで、総合的には速度向上できると考えたからです。
 */
void PDW_Draw_4BN(DRAW_OBJECT obj);
asm("
	.code
	.align	1
	.global	PDW_Draw_4BN
PDW_Draw_4BN:
	;// [%sp+0] := ret addr
	;// [%sp+4] := obj.dest
	;// [%sp+8] := obj.dx
	;// [%sp+10] := obj.dy
	;// [%sp+12] := obj.dw
	;// [%sp+14] := obj.dh
	;// [%sp+16] := obj.src
	;// [%sp+20] := obj.sx
	;// [%sp+22] := obj.sy
	;// [%sp+24] := obj.clip.left
	;// [%sp+25] := obj.clip.top
	;// [%sp+26] := obj.clip.right
	;// [%sp+27] := obj.clip.bottom
	;// [%sp+28] := obj.disp
	;// [%sp+29] := obj.param
	;// [%sp+30] := obj.type
	;// [%sp+31] := obj.layer
	xld.h	%r4, [%sp+20]				; %r4  := obj.sx
	xld.h	%r5, [%sp+22]				; %r5  := obj.sy
	xld.w	%r6, [%sp+16]				; %r6  := obj.src
	xld.h	%r7, [%sp+12]				; %r7  := obj.dw
	xld.h	%r10, [%r6+10]				; %r10 := obj.src->header.w
	xld.w	%r11, [%r6+20]				; %r11 := obj.src->buf
	xld.w	%r12, [%r6+24]				; %r12 := obj.src->mask
	;// %r4  := obj.sx
	;// %r5  := obj.sy
	;// %r6  := obj.src
	;// %r7  := obj.dw
	;// %r10 := obj.src->header.w
	;// %r11 := obj.src->buf
	;// %r12 := obj.src->mask
	xand	%r13, %r4, 7				; %r13 := step = obj.sx & 7
	mlt.h	%r10, %r5				; %alr := obj.src->header.w * obj.sy
	ld.w	%r9, %alr				; %r9  := obj.src->header.w * obj.sy
	add	%r4, %r9				; %r4  := obj.src->header.w * obj.sy + obj.sx
	xsra	%r4, 3					; %r4  := n = (obj.src->header.w * obj.sy + obj.sx) / 8
	add	%r12, %r4				; %r12 := src_mask = obj.src->mask + n
	xsla	%r4, 2					; %r4  := n * 4
	add	%r11, %r4				; %r11 := src_buf = obj.src->buf + n * 4
	;// %r6  := obj.src
	;// %r7  := obj.dw
	;// %r10 := obj.src->header.w
	;// %r11 := src_buf
	;// %r12 := src_mask
	;// %r13 := step
	xsra	%r10, 3					; %r10 := obj.src->header.w / 8
	ld.w	%r9, %r13				; %r9  := step
	add	%r9, %r7				; %r9  := step + obj.dw
	xsub	%r9, %r9, 1				; %r9  := (step + obj.dw - 1)
	xsra	%r9, 3					; %r9  := (step + obj.dw - 1) / 8
	sub	%r10, %r9				; %r10 := src_stride = obj.src->header.w / 8 - (step + obj.dw - 1) / 8
	ld.w	%ahr, %r10				; %ahr := src_stride
	;// %r6  := obj.src
	;// %r7  := obj.dw
	;// %r11 := src_buf
	;// %r12 := src_mask
	;// %r13 := step
	;// %ahr := src_stride
	xld.w	%r4, [%sp+4]				; %r4  := obj.dest
	xld.w	%r5, [%r4+4]				; %r5  := obj.dest->buf
	xld.h	%r9, [%sp+8]				; %r9  := obj.dx
	ld.h	%r4, [%r4]				; %r4  := obj.dest->w			*anti-interlock*
	add	%r5, %r9				; %r5  := obj.dest->buf + obj.dx
	xld.h	%r10, [%sp+10]				; %r10 := obj.dy
	xld.h	%r14, [%sp+14]				; %r14 := y = obj.dh
	;// %r4  := obj.dest->w
	;// %r5  := obj.dest->buf + obj.dx
	;// %r6  := obj.src
	;// %r7  := obj.dw
	;// %r10 := obj.dy
	;// %r11 := src_buf
	;// %r12 := src_mask
	;// %r13 := step
	;// %r14 := y
	;// %ahr := src_stride
	xld.ub	%r9, [%sp+29]				; %r9  := obj.param
	xsra	%r9, 6					; %r9  := obj.param(7:6)		!INTERLOCK!
	xjrne	PDW_Draw_4BN_REV
	;===============================================;
	;	param=0					;
	;===============================================;
	mlt.h	%r4, %r10				; %alr := obj.dest->w * obj.dy
	ld.w	%r9, %alr				; %r9  := obj.dest->w * obj.dy
	add	%r5, %r9				; %r5  := dest_buf = obj.dest->buf + obj.dest->w * obj.dy + obj.dx
	sub	%r4, %r7				; %r4  := dest_stride = obj.dest->w - obj.dw
	xld.w	%r7, 1					; %r7  := dest_add
	;// %r4  := dest_stride
	;// %r5  := dest_buf
	;// %r6  := obj.src
	;// %r7  := dest_add
	;// %r11 := src_buf
	;// %r12 := src_mask
	;// %r13 := step
	;// %r14 := y
	;// %ahr := src_stride
	;===============================================;
PDW_Draw_4BN_LOOP:
	xbtst	[%r6+9], 0				; if(obj.src->header.mask)
	xjreq.d	PDW_Draw_4BN_NOMASK_Y
	 ld.w	%alr, %r4				; %alr := dest_stride			*delay*
	;// %r5  := dest_buf
	;// %r7  := dest_add
	;// %r11 := src_buf
	;// %r12 := src_mask
	;// %r13 := step
	;// %r14 := y
	;// %alr := dest_stride
	;// %ahr := src_stride
	;-----------------------------------------------;
PDW_Draw_4BN_MASK_Y:
	ld.ub	%r6, [%r12]				; %r6  := mask = *src_mask	(0000 0000 0000 0000 0000 0000 abcd efgh)
	ld.w	%r4, [%r11]				; %r4  := pixel = *src_buf	(gggg hhhh eeee ffff cccc dddd aaaa bbbb)
	xrr	%r6, 8					; %r6  := mask			(abcd efgh 0000 0000 0000 0000 0000 0000)
	swap	%r4, %r4				; %r4  := pixel			(aaaa bbbb cccc dddd eeee ffff gggg hhhh)
	rl	%r6, %r13				; %r6  := mask
	rl	%r4, %r13				; %r4  := pixel
	rl	%r4, %r13
	rl	%r4, %r13
	rl	%r4, %r13
	xld.h	%r10, [%sp+12]				; %r10 := x = obj.dw
	xld.w	%r15, 8					; %r15 := 8
	sub	%r15, %r13				; %r15 := i = 8 - step
	;// %r4  := pixel
	;// %r5  := dest_buf
	;// %r6  := mask
	;// %r7  := dest_add
	;// %r10 := x
	;// %r11 := src_buf
	;// %r12 := src_mask
	;// %r13 := step
	;// %r14 := y
	;// %r15 := i
	;// %alr := dest_stride
	;// %ahr := src_stride
PDW_Draw_4BN_MASK_X:
	add	%r6, %r6				; %r6  := mask <<= 1		(bcde fgh0 0000 0000 0000 0000 0000 0000)
	jruge.d	5
	 rl	%r4, 4					; %r4  := pixel <<= 4		(bbbb cccc dddd eeee ffff gggg hhhh aaaa)	*delay*
	 ext	15					;// xand %r9,%r4,15
	 and	%r9, %r4				; %r9  := pixel & 15
	 ld.b	[%r5], %r9				; *dest_buf = pixel & 15
	xsub	%r10, %r10, 1				; %r10 := --x
	xjreq.d	PDW_Draw_4BN_MASK_X_BREAK		; if(!--x) break
	 add	%r5, %r7				; %r5  := dest_buf += dest_add		*delay*
	xsub	%r15, %r15, 1				; %r15 := --i
	xjrne	PDW_Draw_4BN_MASK_X			; if(!--i)
	xld.w	%r15, 8					;   %r15 := i = 8
	xadd	%r12, %r12, 1				;   %r12 := ++src_mask
	xadd	%r11, %r11, 4				;   %r11 := ++src_buf
	ld.ub	%r6, [%r12]				;   %r6  := mask = *++src_mask
	ld.w	%r4, [%r11]				;   %r4  := pixel = *++src_buf
	xrr	%r6, 8					;   %r6  := mask
	xjp.d	PDW_Draw_4BN_MASK_X
	 swap	%r4, %r4				;   %r4  := pixel			*delay*
PDW_Draw_4BN_MASK_X_BREAK:
	ld.w	%r9, %ahr				; %r9  := src_stride
	add	%r12, %r9				; %r12 := src_mask += src_stride
	xsla	%r9, 2					; %r9  := src_stride * 4
	add	%r11, %r9				; %r11 := src_buf += src_stride * 4
	ld.w	%r9, %alr				; %r9  := dest_stride
	xsub	%r14, %r14, 1				; %r14 := --y
	xjrne.d	PDW_Draw_4BN_MASK_Y			; while(--y)
	 add	%r5, %r9				; %r5  := dest_buf += dest_stride	*delay*
	ret
	;-----------------------------------------------;
PDW_Draw_4BN_NOMASK_Y:
	ld.w	%r4, [%r11]				; %r4  := pixel = *src_buf	(gggg hhhh eeee ffff cccc dddd aaaa bbbb)
	xld.h	%r10, [%sp+12]				; <-------------------+			*anti-interlock*
	swap	%r4, %r4				; %r4  := pixel       |		(aaaa bbbb cccc dddd eeee ffff gggg hhhh)
	rl	%r4, %r13				; %r4  := pixel       |
	rl	%r4, %r13				;                     |
	rl	%r4, %r13				;                     |
	rl	%r4, %r13				;                     |
;//	xld.h	%r10, [%sp+12]				; %r10 := x = obj.dw -+
	xld.w	%r15, 8					; %r15 := 8
	sub	%r15, %r13				; %r15 := i = 8 - step
	;// %r4  := pixel
	;// %r5  := dest_buf
	;// %r7  := dest_add
	;// %r10 := x
	;// %r11 := src_buf
	;// %r13 := step
	;// %r14 := y
	;// %r15 := i
	;// %alr := dest_stride
	;// %ahr := src_stride
PDW_Draw_4BN_NOMASK_X:
	xrl	%r4, 4					; %r4  := pixel <<= 4		(bbbb cccc dddd eeee ffff gggg hhhh aaaa)
	xand	%r9, %r4, 15				; %r9  := pixel & 15
	ld.b	[%r5], %r9				; *dest_buf = pixel & 15
	xsub	%r10, %r10, 1				; %r10 := --x
	xjreq.d	PDW_Draw_4BN_NOMASK_X_BREAK		; if(!--x) break
	 add	%r5, %r7				; %r5  := dest_buf += dest_add		*delay*
	xsub	%r15, %r15, 1				; %r15 := --i
	xjrne	PDW_Draw_4BN_NOMASK_X			; if(!--i)
	xld.w	%r15, 8					;   %r15 := i = 8
	xadd	%r11, %r11, 4				;   %r11 := ++src_buf
	ld.w	%r4, [%r11]				;   %r4  := pixel = *++src_buf
	xjp.d	PDW_Draw_4BN_NOMASK_X
	 swap	%r4, %r4				;   %r4  := pixel			*delay*
PDW_Draw_4BN_NOMASK_X_BREAK:
	ld.w	%r9, %ahr				; %r9  := src_stride
	xsla	%r9, 2					; %r9  := src_stride * 4
	add	%r11, %r9				; %r11 := src_buf += src_stride * 4
	ld.w	%r9, %alr				; %r9  := dest_stride
	xsub	%r14, %r14, 1				; %r14 := --y
	xjrne.d	PDW_Draw_4BN_NOMASK_Y			; while(--y)
	 add	%r5, %r9				; %r5  := dest_buf += dest_stride	*delay*
	ret
	;===============================================;
PDW_Draw_4BN_REV:
	xcmp	%r9, 2
	xjrlt	PDW_Draw_4BN_REVY
	xjrgt	PDW_Draw_4BN_REVXY
	;===============================================;
	;	param=DRW_REVX				;
	;===============================================;
	mlt.h	%r4, %r10				; %alr := obj.dest->w * obj.dy
	ld.w	%r9, %alr				; %r9  := obj.dest->w * obj.dy
	add	%r5, %r9				; %r5  := obj.dest->buf + obj.dest->w * obj.dy + obj.dx
	add	%r5, %r7				; %r5  := obj.dest->buf + obj.dest->w * obj.dy + obj.dx + obj.dw
	xsub	%r5, %r5, 1				; %r5  := dest_buf = obj.dest->buf + obj.dest->w * obj.dy + obj.dx + obj.dw - 1
	add	%r4, %r7				; %r4  := dest_stride = obj.dest->w + obj.dw
	xjp.d	PDW_Draw_4BN_LOOP
	 ld.w	%r7, -1					; %r7  := dest_add			*delay*
	;// %r4  := dest_stride
	;// %r5  := dest_buf
	;// %r6  := obj.src
	;// %r7  := dest_add
	;// %r11 := src_buf
	;// %r12 := src_mask
	;// %r13 := step
	;// %r14 := y
	;// %ahr := src_stride
	;===============================================;
	;	param=DRW_REVY				;
	;===============================================;
PDW_Draw_4BN_REVY:
	add	%r10, %r14				; %r10 := obj.dy + obj.dh
	xsub	%r10, %r10, 1				; %r10 := obj.dy + obj.dh - 1
	mlt.h	%r4, %r10				; %alr := obj.dest->w * (obj.dy + obj.dh - 1)
	ld.w	%r9, %alr				; %r9  := obj.dest->w * (obj.dy + obj.dh - 1)
	add	%r5, %r9				; %r5  := dest_buf = obj.dest->buf + obj.dest->w * (obj.dy + obj.dh - 1) + obj.dx
	add	%r4, %r7				; %r4  := obj.dest->w + obj.dw
	not	%r4, %r4				; %r4  := -(obj.dest->w + obj.dw) - 1
	xadd	%r4, %r4, 1				; %r4  := dest_stride = -obj.dest->w - obj.dw
	xjp.d	PDW_Draw_4BN_LOOP
	 ld.w	%r7, 1					; %r7  := dest_add			*delay*
	;// %r4  := dest_stride
	;// %r5  := dest_buf
	;// %r6  := obj.src
	;// %r7  := dest_add
	;// %r11 := src_buf
	;// %r12 := src_mask
	;// %r13 := step
	;// %r14 := y
	;// %ahr := src_stride
	;===============================================;
	;	param=DRW_REVX|DRW_REVY			;
	;===============================================;
PDW_Draw_4BN_REVXY:
	add	%r10, %r14				; %r10 := obj.dy + obj.dh
	xsub	%r10, %r10, 1				; %r10 := obj.dy + obj.dh - 1
	mlt.h	%r4, %r10				; %alr := obj.dest->w * (obj.dy + obj.dh - 1)
	ld.w	%r9, %alr				; %r9  := obj.dest->w * (obj.dy + obj.dh - 1)
	add	%r5, %r9				; %r5  := obj.dest->buf + obj.dest->w * (obj.dy + obj.dh - 1) + obj.dx
	add	%r5, %r7				; %r5  := obj.dest->buf + obj.dest->w * (obj.dy + obj.dh - 1) + obj.dx + obj.dw
	xsub	%r5, %r5, 1				; %r5  := dest_buf = obj.dest->buf + obj.dest->w * (obj.dy + obj.dh - 1) + obj.dx + obj.dw - 1
	sub	%r4, %r7				; %r4  := obj.dest->w - obj.dw
	not	%r4, %r4				; %r4  := -(obj.dest->w - obj.dw) - 1
	xadd	%r4, %r4, 1				; %r4  := dest_stride = -obj.dest->w + obj.dw
	xjp.d	PDW_Draw_4BN_LOOP
	 ld.w	%r7, -1					; %r7  := dest_add			*delay*
	;// %r4  := dest_stride
	;// %r5  := dest_buf
	;// %r6  := obj.src
	;// %r7  := dest_add
	;// %r11 := src_buf
	;// %r12 := src_mask
	;// %r13 := step
	;// %r14 := y
	;// %ahr := src_stride
	;===============================================;
");

