/*
 *	framhfm.c
 *
 *	Canonical Huffman Code
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2014 Naoyuki Sawa
 *
 *	* Fri Nov 21 20:05:45 JST 2014 Naoyuki Sawa
 *	- 1st リリース。
 *	- 下記の記事を参考にしました。
 *	  「高速に符号／復号を行える最小冗長符号「Canonical Huffman Code」」(http://codezine.jp/article/detail/376)
 *	  (ダウンロードして「keep/高速に符号／復号を行える最小冗長符号「Canonical Huffman Code」.7z」に保存しておきました。)
 *	  アルゴリズムは参考にしましたが、サンプルソースの実装はよく理解できなかったので、ほぼ新規に実装しました。
 *	  サンプルソースよりも、当モジュールの実装の方が、デコーダのフットプリントが小さくて、P/ECEに適していると思います。
 *	  また、圧縮時に格納する符号表が小さく済むよう工夫したので、サンプルソースよりも当モジュールの実装の方が、僅かに圧縮率が高いです。
 *	  さらに、サンプルソースは元データのサイズをヘッダに格納していますが、当モジュールは終端符号で判断する点が、優れていると思います。
 *	* Sat Nov 22 10:24:01 JST 2014 Naoyuki Sawa
 *	- 圧縮データの作成は、DOSコマンドラインツール「tool/dphfm」を利用してください。
 *	* Sat Nov 22 14:56:38 JST 2014 Naoyuki Sawa
 *	- HuffmanDecoder_Getc()をアセンブラ化しました。
 *	  HuffmanDecoder_Decode()で、約39KB⇒約62KBの展開を行った時の速度が、約1.106秒⇒約0.790秒に高速化しました。(Clock=48MHz,Code=SRAM,Stack=FRAM)
 *	* Sat Nov 22 16:01:39 JST 2014 Naoyuki Sawa
 *	- HuffmanDecoder_Init()をアセンブラ化しました。
 *	  コードサイズが12バイト小さくなりました。速度にはほとんど影響ありません。
 *	* Sat Nov 22 17:24:18 JST 2014 Naoyuki Sawa
 *	- HuffmanDecoder_Decode()をアセンブラ化しました。
 *	  HuffmanDecoder_Decode()で、約39KB⇒約62KBの展開を行った時の速度が、約0.790秒⇒約0.759秒に高速化しました。(Clock=48MHz,Code=SRAM,Stack=FRAM)
 *	* Sun Nov 23 01:00:09 JST 2014 Naoyuki Sawa
 *	- cliphfm.cから、デコーダー部分をframhfm.cに分離しました。
 *	  P/ECE上ではデコーダーしか使用しないことが多いので、常にエンコーダーがリンクされて容量が増加することを防ぐためです。
 *	  framhfm.cを高速RAMに配置して、高速化することも可能です。
 *	  framhfm.cを高速RAMに配置すると、HuffmanDecoder_Decode()で、約39KB⇒約62KBの展開を行った時の速度が、約0.759秒⇒約0.419秒に高速化しました。(Clock=48MHz,Code=FRAM,Stack=FRAM)
 *	* Sun Nov 23 21:49:53 JST 2014 Naoyuki Sawa
 *	- HuffmanDecoder_Getc()に、「工夫した計算順序」を適用しました。(C言語版とアセンブラ版の両方)
 *	  HuffmanDecoder_Decode()で、約39KB⇒約62KBの展開を行った時の速度が、約0.759秒⇒約0.756秒に高速化しました。(Clock=48MHz,Code=SRAM,Stack=FRAM)
 *	* Sun Sep 04 21:41:17 JST 2016 Naoyuki Sawa
 *	- HuffmanDecoder_Init()が、(int)でアドレス演算を行っていたのを、(char*)で行うように修正しました。
 *	  64ビット対応のための準備ですが、32ビットでも(char*)で行う方が本当は正しいからです。
 *	  とは言え、32ビットではどちらでも同じ結果になるので、既存の32ビットコードには影響有りません。
 */
#include "clip.h"

/****************************************************************************
 *	ハフマンデコーダー
 ****************************************************************************/
//圧縮データ全体をデコードし、圧縮元データを作成する。
// - srcは、32bit境界に整列された圧縮データであること。dstはアライメント不要。
// - 圧縮元データがdstBytesを超えた場合は、越えた部分は格納しない。
//   格納の可否に関係なく、戻り値は、圧縮元データのバイト数である。
//   この性質を利用して、一回目は(dst=NULL,dstBytes=0)で呼び出し、必要なバッファサイズを確認,確保した後、再度呼び出す方法も可能です。
//   <例>
//   │dstBytes=HuffmanDecoder_Decode(src,NULL,0);
//   │dst=malloc(dstBytes);
//   │HuffmanDecoder_Decode(src,dst,dstBytes);
#ifndef PIECE
int HuffmanDecoder_Decode(const void* src, void* _dst, int dstBytes) {
	ST_HuffmanDecoder stHuffmanDecoder;
	unsigned char* dst = _dst;
	int value, dstPos = 0;
	HuffmanDecoder_Init(&stHuffmanDecoder, src);				//ハフマンデコーダーを初期化する。
	while((value = HuffmanDecoder_Getc(&stHuffmanDecoder)) != -1) {		//１バイトデコードする。
		if(dstPos++ < dstBytes) { *dst++ = value; }			//圧縮元データを格納する。
	}
	return dstPos;								//圧縮元データのバイト数を返す。
}
#else //PIECE
int HuffmanDecoder_Decode(const void* src, void* _dst, int dstBytes);
#if 0		//'素直な実装'と'工夫した実装'のどちらを使っても、結果は同じです。現在のところ、'工夫した実装'を使うことにしました。
//□素直な実装。
asm("
		.code
		.align		1
		.global		HuffmanDecoder_Decode
HuffmanDecoder_Decode:
		pushn		%r2
		xsub		%sp, %sp, 8					;//%sp  := &stHuffmanDecoder
		ld.w		%r0, %r13					;//%r0  := dst
		ld.w		%r1, %r14					;//%r1  := dstBytes
		ld.w		%r13, %r12					;//%r13 := src
		ld.w		%r12, %sp					;//%r12 :=             &stHuffmanDecoder
		xcall.d		HuffmanDecoder_Init				;//HuffmanDecoder_Init(&stHuffmanDecoder, src)
		ld.w		%r2, 0						;//%r2  := dstPos = 0						*delay*
		;//%sp  := &stHuffmanDecoder
		;//%r0  := dst
		;//%r1  := dstBytes
		;//%r2  := dstPos
HuffmanDecoder_Decode_LOOP:							;//for(;;) {
		ld.w		%r12, %sp					;//  %r12 :=                             &stHuffmanDecoder
		xcall		HuffmanDecoder_Getc				;//  %r10 := value = HuffmanDecoder_Getc(&stHuffmanDecoder)
		cmp		%r10, -1					;//  if(value == -1) { break }
		jreq		HuffmanDecoder_Decode_RET
		cmp		%r2, %r1					;//  if(dstPos < dstBytes) {
		jrge.d		3
		 add		%r2, 1						;//  %r2  := dstPos++						*delay*
		 ld.b		[%r0]+, %r10					;//    *dst++ = value }
		jp		HuffmanDecoder_Decode_LOOP
HuffmanDecoder_Decode_RET:							;//}
		ld.w		%r10, %r2					;//%r10 := dstPos
		xadd		%sp, %sp, 8
		popn		%r2
		ret
");
#else
//□工夫した実装。素直な実装よりも4バイト増えるが高速。
asm("
		.code
		.align		1
		.global		HuffmanDecoder_Decode
HuffmanDecoder_Decode:
		pushn		%r3
		xsub		%sp, %sp, 8					;//%sp  := &stHuffmanDecoder
		ld.w		%r0, %sp					;//%r0  := &stHuffmanDecoder							%spのままでは、callの遅延スロットで既に変化しているので、%r0にもコピーしておく。
		ld.w		%r1, %r13					;//%r1  := dst
		ld.w		%r2, %r14					;//%r2  := dstBytes
		ld.w		%r13, %r12					;//%r13 := src
		xcall.d		HuffmanDecoder_Init				;//HuffmanDecoder_Init(&stHuffmanDecoder, src)
		ld.w		%r12, %r0					;//%r12 :=             &stHuffmanDecoder			*delay*
		jp.d		HuffmanDecoder_Decode_START			;//goto START
		ld.w		%r3, -1						;//%r3  := dstPos = -1						*delay*		最後のループを抜ける時もプレインクリメントする分と相殺するため(-1)に初期化する。
		;//%sp  := &stHuffmanDecoder
		;//%r0  := &stHuffmanDecoder
		;//%r1  := dst
		;//%r2  := dstBytes
		;//%r3  := dstPos
HuffmanDecoder_Decode_LOOP:							;//do {
		cmp		%r3, %r2					;//  if(dstPos < dstBytes) {							プレインクリメントであるが比較条件を(<=)に変更しないよう注意せよ。(-1)に初期化しているのでプレインクリメント分とは相殺済みである。従って比較条件は'素直な実装'と変わらない。
		jrge		2
		 ld.b		[%r1]+, %r10					;//    *dst++ = value }
HuffmanDecoder_Decode_START:
		xcall.d		HuffmanDecoder_Getc				;//  %r10 := value = HuffmanDecoder_Getc(&stHuffmanDecoder)
		ld.w		%r12, %r0					;//  %r12 :=                             &stHuffmanDecoder	*delay*
		cmp		%r10, -1					;//} while(value != -1)
		jrne.d		HuffmanDecoder_Decode_LOOP			;//
		add		%r3, 1						;//  %r3  := dstPos++						*delay*
		ld.w		%r10, %r3					;//%r10 := dstPos
		xadd		%sp, %sp, 8
		popn		%r3
		ret
");
#endif
#endif//PIECE
/*--------------------------------------------------------------------------*/
//ハフマンデコーダーを初期化する。
#ifndef PIECE
void HuffmanDecoder_Init(ST_HuffmanDecoder* pHuffmanDecoder, const void* src) {
	const unsigned char* hdr;
	int codeLenMask, codeLenCount;
	//--- 符号表を読み飛ばす処理 ---
	pHuffmanDecoder->src = src;						//符号表のアドレスを格納する。
	//符号表の部分は、bitarray_msb1st_getではなく、(codeLenMask+バイト配列)と見なしてアクセスする。エンコーダとデコーダでアクセス方法を合わせないと、バイト配列部分の順序が一致しないので注意せよ。
	hdr         = pHuffmanDecoder->src;
	codeLenMask = *(int*)hdr;
	hdr        += 4;
	do {									//codeLenMaskが最初から0だった場合にも、無駄に1回処理してしまうが、「if(codeLenMask<0)」で除外されるので、結果は正確であり問題無い。尚、codeLenMaskが最初から0になるのは、圧縮元のデータが0バイトだった場合のみであり、無駄処理の影響は小さいはず。そんなレアケースよりも、通常の処理効率を優先した。while(){〜}よりも、do{〜}while()の方が、処理効率が高い。
		if(codeLenMask < 0) {						//デコーダをasm化した時は、「add %rX,%rX;jruge 〜」で処理せよ。
			codeLenCount = *hdr++ + 1;				//エンコーダの(-1)とデコーダが(+1)が相殺して、(1〜256)に復元する。
			hdr += codeLenCount;					//符号長に割り当てられている値のリストを読み飛ばす。
		}
	} while(codeLenMask <<= 1);
//{{2016/09/04変更:HuffmanDecoder_Init()が、(int)でアドレス演算を行っていたのを、(char*)で行うように修正しました。
//	pHuffmanDecoder->srcPos = ((int)hdr - (int)pHuffmanDecoder->src) << 3;	//圧縮データのビット位置を求める。	srcからの相対
//↓2016/09/04変更:HuffmanDecoder_Init()が、(int)でアドレス演算を行っていたのを、(char*)で行うように修正しました。
	pHuffmanDecoder->srcPos = ((char*)hdr - (char*)pHuffmanDecoder->src) << 3;	//圧縮データのビット位置を求める。	srcからの相対
//}}2016/09/04変更:HuffmanDecoder_Init()が、(int)でアドレス演算を行っていたのを、(char*)で行うように修正しました。
	pHuffmanDecoder->srcPos = (pHuffmanDecoder->srcPos + 31) & ~31;		//圧縮データの部分は、bitarray_msb1st_getでアクセスするので、32bit境界まで進めておく必要が有る。
}
#else //PIECE
void HuffmanDecoder_Init(ST_HuffmanDecoder* pHuffmanDecoder, const void* src);
asm("
		.code
		.align		1
		.global		HuffmanDecoder_Init
HuffmanDecoder_Init:
		ld.w		[%r12], %r13					;//pHuffmanDecoder->src = src,       %r13 := hdr
		ld.w		%r4, [%r13]+					;//%r4  := codeLenMask = *(int*)hdr, %r13 := hdr += 4
HuffmanDecoder_Init_LOOP:							;//do {
		add		%r4, %r4					;//  %psr(C) := (codeLenMask < 0), %r4  := codeLenMask <<= 1, %psr(Z) := !codeLenMask	─┐
		jruge		HuffmanDecoder_Init_L10				;//  if(%psr(C)) {────────────┐						　│
		ld.ub		%r5, [%r13]+					;//    %r5  := codeLenCount-1 = *hdr++	　│		//codeLenCount-1 := 0〜255	　│
		adc		%r13, %r5					;//    %r4  := hdr += codeLenCount-1 + 1←┘						　│	ここでは必ず%psr(C)=1であることを利用して、adcを利用して+1する工夫をしました。
		cmp		%r4, 0						;//                                                           %psr(Z) := !codeLenMask	─┤
HuffmanDecoder_Init_L10:							;//  }											　│
		jrne		HuffmanDecoder_Init_LOOP			;//} while(codeLenMask)	←────────────────────────────────┘
		ld.w		%r4, [%r12]+					;//%r4  :=                                      pHuffmanDecoder->src
		sub		%r13, %r4					;//%r13 :=                     ((int)hdr - (int)pHuffmanDecoder->src)
		sla		%r13, 3						;//%r13 :=                     ((int)hdr - (int)pHuffmanDecoder->src) << 3
		add		%r13, 31					;//%r13 :=                    (((int)hdr - (int)pHuffmanDecoder->src) << 3) + 31
		and		%r13, -32					;//%r13 :=                   ((((int)hdr - (int)pHuffmanDecoder->src) << 3) + 31) & ~31
		ld.w		[%r12], %r13					;//pHuffmanDecoder->srcPos = ((((int)hdr - (int)pHuffmanDecoder->src) << 3) + 31) & ~31
		ret
");
#endif//PIECE
/*--------------------------------------------------------------------------*/
//１バイトデコードする。
//圧縮データの終端ならば、(-1)を返す。
#ifndef PIECE
int HuffmanDecoder_Getc(ST_HuffmanDecoder* pHuffmanDecoder) {
	const unsigned char* hdr;
	int code, codeLenMask, codeLen, codeTmp1, codeTmp2, codeLenCount;
	//--- 圧縮データを展開する処理 ---
	code = bitarray_msb1st_get(pHuffmanDecoder->src, pHuffmanDecoder->srcPos, 32);	//実際の符号長にかかわらず、現在のビット位置から32bit取得する。
	//符号表の部分は、bitarray_msb1st_getではなく、(codeLenMask+バイト配列)と見なしてアクセスする。エンコーダとデコーダでアクセス方法を合わせないと、バイト配列部分の順序が一致しないので注意せよ。
	hdr         = pHuffmanDecoder->src;
	codeLenMask = *(int*)hdr;
	hdr        += 4;
	codeLen     = 0;
	codeTmp1    = 0;							//符号表から取得した符号をシフトイン(？)する変数
	codeTmp2    = 0;							//圧縮データから取得した符号をシフトインする変数
	do {									//codeLenMaskが最初から0だった場合にも、無駄に1回処理してしまうが、「if(codeLenMask<0)」で除外されるので、結果は正確であり問題無い。尚、codeLenMaskが最初から0になるのは、圧縮元のデータが0バイトだった場合のみであり、無駄処理の影響は小さいはず。そんなレアケースよりも、通常の処理効率を優先した。while(){〜}よりも、do{〜}while()の方が、処理効率が高い。
		codeTmp1 <<= 1;							//─符号表から取得した符号をシフトイン(？)する		//デコーダをasm化した時は、「codeTmp1<<=1」に相当する処理を、当ブロックのループ処理の遅延スロットに置いて構わない。codeTmpの初期値が0であるから、最初にシフトしても最後にシフトしても、同じ結果になるからです。
		codeTmp2 = (codeTmp2 << 1) | (code < 0);			//┬圧縮データから取得した符号をシフトインする		//デコーダをasm化した時は、「add %rX,%rX;adc %rY,%rY」で処理せよ。
		code <<= 1;							//┘
		codeLen++;							//比較する符号長を増やす。
		if(codeLenMask < 0) {						//デコーダをasm化した時は、「add %rX,%rX;jruge 〜」で処理せよ。		⇒訂正:左記の方法はできませんでした。下のwhile()まで%psr(Z)を維持できないからです。
//「素直な計算順序」と「工夫した計算順序」のどちらでも結果は同じになる。
#if 0	//□素直な計算順序。アルゴリズムを理解するにはこちらを参照せよ。
			codeLenCount = *hdr++ + 1;				//エンコーダの(-1)とデコーダが(+1)が相殺して、(1〜256)に復元する。
			codeTmp2 -= codeTmp1;					//───────────────────────┐
			if(codeTmp2 < 0) { DIE(); }	//バグ検出		//						│	//デコーダをasm化した時は、このバグ検査を行わなくて構わない。動作が安定したら、バグ検査よりも、処理速度の方が重要であるから。
			if(codeTmp2 < codeLenCount) {				//この符号長に属する符号ならば…		│
				pHuffmanDecoder->srcPos += codeLen;		//次に読み出す符号のビット位置を更新する。	│
				return hdr[codeTmp2];				//復号化した値を返す。				│
			}							//						↓
			codeTmp2 += codeTmp1;					//この符号長に属する符号でなければ、上で引いた分を足して相殺する。
			hdr      += codeLenCount;				//ヘッダの走査アドレスを、次の符号長へ進める。
			codeTmp1 += codeLenCount;				//比較する符号を、この符号長に属する符号の数、増やす。
#else	//□工夫した計算順序。アセンブラ化する時はこの方が高速化し易い。
			codeLenCount = *hdr++ + 1;				//エンコーダの(-1)とデコーダが(+1)が相殺して、(1〜256)に復元する。	□「工夫した計算順序」の式変形
			hdr      += codeLenCount;				//ヘッダの走査アドレスを、次の符号長へ進める。				│hdr' = hdr+codeLenCount
			codeTmp1 += codeLenCount;				//比較する符号を、この符号長に属する符号の数、増やす。			│codeTmp1' = codeTmp1+codeLenCount
			codeTmp2 -= codeTmp1;					//───────────────────────┐			│codeTmp2' = codeTmp2-codeTmp1' = codeTmp2-codeTmp1-codeLenCount
			if(codeTmp2 < 0) {					//この符号長に属する符号ならば…		│			│codeTmp2'<0 ⇒ (codeTmp2-codeTmp1-codeLenCount)<0 ⇒ (codeTmp2-codeTmp1)<codeLenCount
				pHuffmanDecoder->srcPos += codeLen;		//次に読み出す符号のビット位置を更新する。	│			│
				return hdr[codeTmp2];				//復号化した値を返す。				│			│hdr'[codeTmp2'] = (hdr+codeLenCount)[codeTmp2-codeTmp1-codeLenCount] = hdr[codeTmp2-codeTmp1]
			}							//						↓			│
			codeTmp2 += codeTmp1;					//この符号長に属する符号でなければ、上で引いた分を足して相殺する。	│codeTmp2'' = codeTmp2'+codeTmp1' = codeTmp2-codeTmp1'+codeTmp1' = codeTmp2
#endif
		}
	} while(codeLenMask <<= 1);						//デコーダが符号表を最後まで検索しても一致しなければ、終端符号だと判断できる。
	return -1;								//圧縮データの終端であることを示す、(-1)を返す。次に読み出す符号のビット位置を更新しないことに注意せよ。次に読み出す符号のビット位置を更新しないことによって、次以降にHuffmanDecoder_Getc()が呼び出された時も、今回と同じく(-1)を返すことができる。
}
#else //PIECE
int HuffmanDecoder_Getc(ST_HuffmanDecoder* pHuffmanDecoder);
#if 0		//'素直な実装'と'工夫した実装'のどちらを使っても、結果は同じです。現在のところ、'工夫した実装'を使うことにしました。
//□素直な実装。
asm("
		.code
		.align		1
		.global		HuffmanDecoder_Getc
HuffmanDecoder_Getc:
		pushn		%r0
		ld.w		%r0, %r12					;//%r0  :=  pHuffmanDecoder
		ld.w		%r12, [%r0]+					;//%r12 :=                            pHuffmanDecoder->src, %r0 := &pHuffmanDecoder->srcPos
		ld.w		%r13, [%r0]					;//%r13 :=                                                  pHuffmanDecoder->srcPos
		xld.w		%r14, 32					;//%r14 :=                                                                           32
		xcall.d		bitarray_msb1st_get				;//%r10 := code = bitarray_msb1st_get(pHuffmanDecoder->src, pHuffmanDecoder->srcPos, 32)
		sub		%r0, 4						;//%r0  :=  pHuffmanDecoder									*delay*
		ld.w		%r4, %r0					;//%r4  :=  pHuffmanDecoder
		ld.w		%r5, [%r4]+					;//%r4  := &pHuffmanDecoder->srcPos, %r5 := hdr = pHuffmanDecoder->src
		popn		%r0
		;//↑スタックを使用するのはここまで。↓これ以降はすぐにretして良い。
		;//%r4  := &pHuffmanDecoder->srcPos
		;//%r5  := hdr
		;//%r10 := code
		ld.w		%r6, [%r5]+					;//%r6  := codeLenMask = *(int*)hdr, %r5 := hdr += 4
		ld.w		%r11, 0						;//%r11 := codeTmp1 = 0
		ld.w		%r12, 0						;//%r12 := codeTmp2 = 0
		ld.w		%r7, 0						;//%r7  := codeLen  = 0
		;//%r4  := &pHuffmanDecoder->srcPos
		;//%r5  := hdr
		;//%r6  := codeLenMask
		;//%r7  := codeLen
		;//%r10 := code
		;//%r11 := codeTmp1
		;//%r12 := codeTmp2
HuffmanDecoder_Getc_LOOP:							;//do {
		add		%r10, %r10					;//  %psr(C) :=                           (code < 0), %r10 := code <<= 1
		adc		%r12, %r12					;//  %r12 := codeTmp2 = (codeTmp2 << 1) | (code < 0)
		cmp		%r6, 0						;//  if(codeLenMask < 0) {
		jrge.d		HuffmanDecoder_Getc_L20
		add		%r7, 1						;//  %r7  := codeLen++										*delay*
		ld.ub		%r13, [%r5]+					;//    %r13 := codeLenCount-1 = *hdr++			//codeLenCount-1 := 0〜255
		sub		%r12, %r11					;//    %r12 := codeTmp2 -= codeTmp1
		cmp		%r12, %r13					;//    if(codeTmp2 <= codeLenCount-1) {
		jrgt.d		HuffmanDecoder_Getc_L10
		add		%r13, 1						;//    %r13 := codeLenCount				//codeLenCount   := 1〜256		*delay*
		add		%r5, %r12					;//      %r5  :=        &hdr[codeTmp2]
		ld.w		%r9, [%r4]					;//      %r9  := srcPos = pHuffmanDecoder->srcPos
		ld.ub		%r10, [%r5]					;//      %r10 := value = hdr[codeTmp2]								*anti-interlock*
		add		%r9, %r7					;//      %r9  := srcPos += codeLen
		ld.w		[%r4], %r9					;//      pHuffmanDecoder->srcPos = srcPos
		ret								;//      return  value
HuffmanDecoder_Getc_L10:							;//    }
		add		%r12, %r11					;//    %r12 := codeTmp2 += codeTmp1
		add		%r5, %r13					;//    %r5  := hdr      += codeLenCount
		add		%r11, %r13					;//    %r11 := codeTmp1 += codeLenCount
HuffmanDecoder_Getc_L20:							;//  }
		sla		%r6, 1						;//} while(codeLenMask <<= 1)
		jrne.d		HuffmanDecoder_Getc_LOOP
		sla		%r11, 1						;//  %r11 := codeTmp1 <<= 1									*delay*
		ret.d								;//return  -1
		ld.w		%r10, -1					;//%r10 := -1											*delay*
");
#elif 0
//□工夫した実装。素直な実装よりも4バイト減り約1%高速。
asm("
		.code
		.align		1
		.global		HuffmanDecoder_Getc
HuffmanDecoder_Getc:
		pushn		%r1
		ld.w		%r0, %r12					;//%r0  :=  pHuffmanDecoder
		ld.w		%r1, [%r0]+					;//%r0  := &pHuffmanDecoder->srcPos, %r1  := pHuffmanDecoder->src
		ld.w		%r13, [%r0]					;//%r13 :=                                                         pHuffmanDecoder->srcPos
		xld.w		%r14, 32					;//%r14 :=                                                                                  32
		xcall.d		bitarray_msb1st_get				;//%r10 := code = bitarray_msb1st_get(       pHuffmanDecoder->src, pHuffmanDecoder->srcPos, 32)
		ld.w		%r12, %r1					;//%r12 :=                                   pHuffmanDecoder->src					*delay*
		;//%r0  :=      &pHuffmanDecoder->srcPos
		;//%r1  := hdr = pHuffmanDecoder->src
		;//%r10 := code
		ld.w		%r4, [%r1]+					;//%r4  := codeLenMask = *(int*)hdr, %r1  := hdr += 4
		ld.w		%r5, 0						;//%r5  := codeLen  = 0
		ld.w		%r6, 0						;//%r6  := codeTmp1 = 0
		ld.w		%r7, 0						;//%r7  := codeTmp2 = 0
		;//%r0  := &pHuffmanDecoder->srcPos
		;//%r1  := hdr
		;//%r4  := codeLenMask
		;//%r5  := codeLen
		;//%r6  := codeTmp1
		;//%r7  := codeTmp2
		;//%r10 := code
HuffmanDecoder_Getc_LOOP:							;//do {
		add		%r10, %r10					;//  %psr(C) :=                           (code < 0), %r10 := code <<= 1
		adc		%r7, %r7					;//  %r7  := codeTmp2 = (codeTmp2 << 1) | (code < 0)
		cmp		%r4, 0						;//  if(codeLenMask < 0) {
		jrge.d		HuffmanDecoder_Getc_L20
		add		%r5, 1						;//  %r5  := codeLen++											*delay*
		ld.ub		%r11, [%r1]+					;//    %r11 := codeLenCount-1 = *hdr++			//codeLenCount-1 := 0〜255
		sub		%r7, %r6					;//    %r7  := codeTmp2 -= codeTmp1
		cmp		%r7, %r11					;//    if(codeTmp2 <= codeLenCount-1) {
		jrgt.d		HuffmanDecoder_Getc_L10
		add		%r11, 1						;//    %r11 := codeLenCount				//codeLenCount   := 1〜256			*delay*
		add		%r1, %r7					;//      %r1  :=        &hdr[codeTmp2]
		ld.w		%r9, [%r0]					;//      %r9  := srcPos = pHuffmanDecoder->srcPos
		ld.ub		%r10, [%r1]					;//      %r10 := value = hdr[codeTmp2]									*anti-interlock*
		add		%r9, %r5					;//      %r9  := srcPos += codeLen
		ld.w		[%r0], %r9					;//      pHuffmanDecoder->srcPos = srcPos
HuffmanDecoder_Getc_RET:
		popn		%r1						;//return  value
		ret
HuffmanDecoder_Getc_L10:							;//    }
		add		%r7, %r6					;//    %r7  := codeTmp2 += codeTmp1
		add		%r1, %r11					;//    %r1  := hdr      += codeLenCount
		add		%r6, %r11					;//    %r6  := codeTmp1 += codeLenCount
HuffmanDecoder_Getc_L20:							;//  }
		sla		%r4, 1						;//} while(codeLenMask <<= 1)
		jrne.d		HuffmanDecoder_Getc_LOOP
		sla		%r6, 1						;//  %r6  := codeTmp1 <<= 1										*delay*
		jp.d		HuffmanDecoder_Getc_RET
		ld.w		%r10, -1					;//%r10 := value = -1											*delay*
");
#else
//□工夫した実装に加えて「工夫した計算順序」も適用した実装。4バイト減り約0.4%高速。
asm("
		.code
		.align		1
		.global		HuffmanDecoder_Getc
HuffmanDecoder_Getc:
		pushn		%r1
		ld.w		%r0, %r12					;//%r0  :=  pHuffmanDecoder
		ld.w		%r1, [%r0]+					;//%r0  := &pHuffmanDecoder->srcPos, %r1  := pHuffmanDecoder->src
		ld.w		%r13, [%r0]					;//%r13 :=                                                         pHuffmanDecoder->srcPos
		xld.w		%r14, 32					;//%r14 :=                                                                                  32
		xcall.d		bitarray_msb1st_get				;//%r10 := code = bitarray_msb1st_get(       pHuffmanDecoder->src, pHuffmanDecoder->srcPos, 32)
		ld.w		%r12, %r1					;//%r12 :=                                   pHuffmanDecoder->src					*delay*
		;//%r0  :=      &pHuffmanDecoder->srcPos
		;//%r1  := hdr = pHuffmanDecoder->src
		;//%r10 := code
		ld.w		%r4, [%r1]+					;//%r4  := codeLenMask = *(int*)hdr, %r1  := hdr += 4
		ld.w		%r5, 0						;//%r5  := codeLen  = 0
		ld.w		%r6, 0						;//%r6  := codeTmp1 = 0
		ld.w		%r7, 0						;//%r7  := codeTmp2 = 0
		;//%r0  := &pHuffmanDecoder->srcPos
		;//%r1  := hdr
		;//%r4  := codeLenMask
		;//%r5  := codeLen
		;//%r6  := codeTmp1
		;//%r7  := codeTmp2
		;//%r10 := code
HuffmanDecoder_Getc_LOOP:							;//do {
		add		%r10, %r10					;//  %psr(C) :=                           (code < 0), %r10 := code <<= 1
		adc		%r7, %r7					;//  %r7  := codeTmp2 = (codeTmp2 << 1) | (code < 0)
		cmp		%r4, 0						;//  if(codeLenMask < 0) {
		jrge.d		HuffmanDecoder_Getc_L20
		add		%r5, 1						;//  %r5  := codeLen++											*delay*
		ld.ub		%r11, [%r1]+					;//    %r11 := codeLenCount-1 = *hdr++			//codeLenCount-1 := 0〜255
		add		%r11, 1						;//    %r11 := codeLenCount				//codeLenCount   := 1〜256
	;//	add		%r1, %r11					;//    %r1  := hdr      += codeLenCount	─┐
		add		%r6, %r11					;//    %r6  := codeTmp1 += codeLenCount	　│
		sub		%r7, %r6					;//    %r7  := codeTmp2 -= codeTmp1	　│
		jrge.d		HuffmanDecoder_Getc_L10				;//    if(codeTmp2 < 0) {		　│
		add		%r1, %r11					;//    %r1  := hdr      += codeLenCount	←┘								*delay*
		add		%r7, %r1					;//      %r7  :=        &hdr[codeTmp2]
		ld.w		%r9, [%r0]					;//      %r9  := srcPos = pHuffmanDecoder->srcPos
		ld.ub		%r10, [%r7]					;//      %r10 := value = hdr[codeTmp2]									*anti-interlock*
		add		%r9, %r5					;//      %r9  := srcPos += codeLen
		ld.w		[%r0], %r9					;//      pHuffmanDecoder->srcPos = srcPos
HuffmanDecoder_Getc_RET:
		popn		%r1						;//return  value
		ret
HuffmanDecoder_Getc_L10:							;//    }
		add		%r7, %r6					;//    %r7  := codeTmp2 += codeTmp1
HuffmanDecoder_Getc_L20:							;//  }
		sla		%r4, 1						;//} while(codeLenMask <<= 1)
		jrne.d		HuffmanDecoder_Getc_LOOP
		sla		%r6, 1						;//  %r6  := codeTmp1 <<= 1										*delay*
		jp.d		HuffmanDecoder_Getc_RET
		ld.w		%r10, -1					;//%r10 := value = -1											*delay*
");
#endif
#endif//PIECE
