/*	
 *	framldir.c
 *
 *	高速切替・16階調表\示
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2004 Naoyuki Sawa
 *
 *	* Sun Jun 6 14:11:00 JST 2004 Naoyuki Sawa
 *	- 作成開始。
 *	* Tue Jun 8 19:00:00 JST 2004 Naoyuki Sawa
 *	- 4bit描画のためのカスタムpceLCDDrawObject()をこのモジュールに含めました。
 *	* Thu Jun 10 19:00:00 JST 2004 Naoyuki Sawa
 *	- new_pceLCDTrans()の処理本体を高速RAMへ移し、ldirect_mkbuf()としました。
 *	* 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に配置してください。
 */
#include "clip.h"

/****************************************************************************
 *	内部関数
 ****************************************************************************/

#if 0	/*==================================================================*/
void
ldirect_mkbuf(const unsigned char wbuff[/*DISP_X / 2 * DISP_Y*/], const unsigned char* lcdbuff)
{
	const unsigned int* src = (const unsigned int*)lcdbuff;
	      unsigned int* dst = (      unsigned int*)wbuff;
	//
	int i;
	unsigned int pixel0to3;
	unsigned int pixel4to7;

	/* 8ピクセル単位で、先行4ピクセルを上位4bit、後続4ピクセルを下位4bitに重ねて格納します。 */
	for(i = 0; i < DISP_X / 8 * DISP_Y; i++) {
		pixel0to3 = *src++;
		pixel4to7 = *src++;
		*dst++ = pixel0to3 << 4 | pixel4to7;
	}
}
#else	/*==================================================================*/
asm("
	.code
	.global ldirect_mkbuf
ldirect_mkbuf:
	xld.w %r15, 1408		; %r15 = DISP_X / 8 * DISP_Y
ldirect_mkbuf_LOOP:
	ld.w %r10, [%r13]+		; %r10 = pixel0to3
	ld.w %r11, [%r13]+		; %r11 = pixel4to7
	xsll %r10, 4			; %r10 = pixel0to3 << 4 | pixel4to7
	or %r10, %r11
	ld.w [%r12]+, %r10		; store (pixel0to3 << 4 | pixel4to7)
	xsub %r15, %r15, 1
	xjrne ldirect_mkbuf_LOOP
	ret
");
#endif	/*==================================================================*/

#if 0	/*==================================================================*/
void
ldirect_trans(const unsigned char wbuff[/*DISP_X / 2 * DISP_Y*/], const unsigned short cvttbl[/*256*/])
{
	/* コードサイズ節約&高速化のために、I/O領域のベースアドレスをローカル変数に用意します。 */
	#undef plc_IO /* c33209.hでのマクロ定義をキャンセル */
	volatile struct c_IOtag* plc_IO = (volatile struct c_IOtag*)0x40000;

	int v;
	int page;
	int column;

	/* 各ページ(横8×縦88(=DISP_Y)ピクセルの短冊矩形)を転送します。
	 * * P/ECE LCDのページ番号並びは、左から { 9,8,7,6,5,4,3,2,1,0,15,14,13,12,11,10 } です。
	 *   開発中に使われていた旧いLCDとの互換性のための歴史的理由(？)により、
	 *   LCDハードウェアから見ると、左右反転＋9ページス分クロールした状態となっています。
	 *   /usr/PIECE/sysdev/pcekn/lcd.cを参照してください。
	 */
	page = 9;
	do {

		/*** コマンド送信 ***/

		bP2_P2D_P21D = 0; /* RS <= 0:Command */

		v = 0xb0 | page; /* Set Page Address */
		asm volatile ("mirror %0,%0" : "=r"(v) : "0"(v));
		while(!bSIF3_STATUS_TDBE3) { /* 送信バッファ空き待ち */ }
		pSIF3_TXD = v;

		//v = 0x10; /* Set Column Address MSB */
		//asm volatile ("mirror %0,%0" : "=r"(v) : "0"(v));
		//↓0x10のmirrorはあらかじめ計算できるので、次のように変更。
		v = 0x08;
		while(!bSIF3_STATUS_TDBE3) { /* 送信バッファ空き待ち */ }
		pSIF3_TXD = v;

		//v = 0x00; /* Set Column Address LSB */
		//asm volatile ("mirror %0,%0" : "=r"(v) : "0"(v));
		//↓0x00のmirrorはあらかじめ計算できるので、次のように変更。
		v = 0x00;
		while(!bSIF3_STATUS_TDBE3) { /* 送信バッファ空き待ち */ }
		pSIF3_TXD = v;

		while(bSIF3_STATUS_TEND3) { /* 送信完了待ち */ } /* 必要!! */

		/*** データ送信 ***/

		bP2_P2D_P21D = 1; /* RS <= 1:Data */

		for(column = 0; column < DISP_Y; column++) {
			v =          cvttbl[*wbuff++]; /* [4],[0] */
			v = v >> 1 | cvttbl[*wbuff++]; /* [5],[1] */
			v = v >> 1 | cvttbl[*wbuff++]; /* [6],[2] */
			v = v >> 1 | cvttbl[*wbuff  ]; /* [7],[3] */
			wbuff += (DISP_X / 2) - (8 / 2 - 1);

			while(!bSIF3_STATUS_TDBE3) { /* 送信バッファ空き待ち */ }
			pSIF3_TXD = v;
			while(!bSIF3_STATUS_TDBE3) { /* 送信バッファ空き待ち */ }
			pSIF3_TXD = v >> 8;
		}

		/* 次のページへ。 */
		wbuff += (8 / 2) - (DISP_X / 2 * DISP_Y);
		page = (page - 1) & 15;

		while(bSIF3_STATUS_TEND3) { /* 送信完了待ち */ } /* 必要!! */

	} while(page != 9); /* ページ番号が一周したら終了 */
}
#else	/*==================================================================*/
asm("
	.code
	.global ldirect_trans
ldirect_trans:
	xld.w %r4, 0x401f5		; %r4 = pSIF3_TXD
	xld.w %r5, 0x401f7		; %r5 = pSIF3_STATUS
	xld.w %r6, 0x402d9		; %r6 = pP2_P2D
	;
	xld.w %r14, 9			; %r14 = page = { 9,8,7,6,5,4,3,2,1,0,15,14,13,12,10 }
ldirect_trans_LOOP_X:
	;
	;	コマンド送信
	;
	bclr [%r6], 1			; bP2_P2D_P21D = 0
	;
	mirror %r10, %r14		; %r10 = mirror(0xb0 | page)
	xoor %r10, %r10, 0x0d		;      = 0x0d | mirror(page)
ldirect_trans_L10:
	btst [%r5], 1			; while(!bSIF3_STATUS_TDBE3) { }
	xjreq ldirect_trans_L10
	ld.b [%r4], %r10		; pSIF3_TXD = %r10
	;
	xld.w %r10, 0x08		; %r10 = mirror(0x10) = 0x08
ldirect_trans_L20:
	btst [%r5], 1			; while(!bSIF3_STATUS_TDBE3) { }
	xjreq ldirect_trans_L20
	ld.b [%r4], %r10		; pSIF3_TXD = %r10
	;
	xld.w %r10, 0x00		; %r10 = mirror(0x00) = 0x00
ldirect_trans_L30:
	btst [%r5], 1			; while(!bSIF3_STATUS_TDBE3) { }
	xjreq ldirect_trans_L30
	ld.b [%r4], %r10		; pSIF3_TXD = %r10
	;
ldirect_trans_L40:
	btst [%r5], 5			; while(bSIF3_STATUS_TEND3) { }
	xjrne ldirect_trans_L40
	;
	;	データ送信
	;
	bset [%r6], 1			; bP2_P2D_P21D = 1
	;
	xld.w %r15, 88			; %r15 = DISP_Y
ldirect_trans_LOOP_Y:
	;
	; ※以下の命令列、インターロック回避しようとしてレジスタ割り当ての変更や命令の並び替えを行うと、
	;   なぜか余計に遅くなります。文書化されていない、外部メモリアクセスパターンの特性でしょうか？
	;   とりあえずこのままで・・・
	;
	ld.ub %r11, [%r12]+		; [4],[0]
	xsll %r11, 1			; !INTERLOCK!
	add %r11, %r13
	ld.uh %r10, [%r11]
	;
	ld.ub %r11, [%r12]+		; [5],[1]
	xsll %r11, 1			; !INTERLOCK!
	add %r11, %r13
	ld.uh %r11, [%r11]
	xsrl %r10, 1			; *anti-interlock*
	or %r10, %r11
	;
	ld.ub %r11, [%r12]+		; [6],[2]
	xsll %r11, 1			; !INTERLOCK!
	add %r11, %r13
	ld.uh %r11, [%r11]
	xsrl %r10, 1			; *anti-interlock*
	or %r10, %r11
	;
	ld.ub %r11, [%r12]		; [7],[3]
	xsll %r11, 1			; !INTERLOCK!
	add %r11, %r13
	ld.uh %r11, [%r11]
	xsrl %r10, 1			; *anti-interlock*
	or %r10, %r11
	;
ldirect_trans_L50:
	btst [%r5], 1			; while(!bSIF3_STATUS_TDBE3) { }
	xjreq ldirect_trans_L50
	ld.b [%r4], %r10		; pSIF3_TXD = %r10
	;
	xadd %r12, %r12, 61		; %r12 += (DISP_X / 2) - (8 / 2 - 1)
	xsrl %r10, 8			; %r10 >>= 8
	;
ldirect_trans_L60:
	btst [%r5], 1			; while(!bSIF3_STATUS_TDBE3) { }
	xjreq ldirect_trans_L60
	ld.b [%r4], %r10		; pSIF3_TXD = %r10
	;
	xsub %r15, %r15, 1
	xjrne ldirect_trans_LOOP_Y
	;
	xsub %r12, %r12, 5628		; wbuff += (8 / 2) - (DISP_X / 2 * DISP_Y)
	xsub %r14, %r14, 1		; page = (page - 1) & 15
	xand %r14, %r14, 15
	;
ldirect_trans_L70:
	btst [%r5], 5			; while(bSIF3_STATUS_TEND3) { }
	xjrne ldirect_trans_L70
	;
	xcmp %r14, 9
	xjrne ldirect_trans_LOOP_X
	;
	ret
");
#endif	/*==================================================================*/

