/*	
 *	machine.h
 *
 *	CPU固有の命令
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2014 Naoyuki Sawa
 *
 *	* Sun Mar 02 18:32:04 JST 2014 Naoyuki Sawa
 *	- 1st リリース。
 *	  ファイル名「machine.h」は、Renesasコンパイラ(Hew)のmachine.hに倣いました。
 *	* Mon Mar 03 23:23:15 JST 2014 Naoyuki Sawa
 *	- Win32用の実装を追加しました。
 */
#ifndef __MACHINE_H__
#define __MACHINE_H__

//■gcc33で追加されているレジスタ制約:
//│"h" -> %ahr 
//│"l" -> %alr 
//│"x" -> %ahr or %alr

//■「volatile」を付けなかった理由について:
//インラインアセンブラを計算処理の一部として利用する場合は、「volatile」を付けない方が良いです。
//なぜなら、「volatile」を付けると、GCCが、「インラインアセンブラ処理を実行すること自体に意味がある」と判断して、無駄処理を除去しなくなるからです。(test1参照)
//「volatile」を付けなければ、GCCが、「インラインアセンブラの結果が使用されていない場合は、無駄処理としてインラインアセンブラを除去」してくれます。(test2参照)
//
//│int test1(int x) {                                      // test1:
//│  int a;                                                //   ld.w %r10,%r12
//│  asm volatile ("mirror %0,%1" : "=r"(a) : "r"(x));     //   mirror %r11,%r10 ← 無駄コードが生成される
//│  return x;                                             //   ret
//│}
//│int test2(int x) {                                      // test2:
//│  int a;                                                //   ld.w %r10,%r12
//│  asm /*volatile*/ ("mirror %0,%1" : "=r"(a) : "r"(x)); //                    ← 最適化されて除去される
//│  return x;                                             //   ret
//│}
//
//インラインアセンブラを計算処理の一部として利用する場合は、「インラインアセンブラ処理を実行すること自体に意味がある」ケースは稀だと思います。
//そのような場合は、「volatile」を付けない方が良いでしょう。
 //
//これまで深く考えず常に「volatile」を付けていたのですが、場合によって使い分ける方が良さそうです。
//□まとめると:
//・インラインアセンブラの処理を実行すること自体に意味がある場合⇒必ず「volatile」を付ける。
//・インラインアセンブラの結果を使用する場合だけに意味がある場合⇒「volatile」を付けない方が良い。付けても良いが無駄コードが生成される可能性がある。

//==============================================================================
//	算術演算
//==============================================================================
//□mlt_hとmltu_hについて:
//│C言語で乗算を行うと、たとえshort変数同士の乗算であっても、「mlt(u).w」に展開されてしまいます。
//│「mlt(u).w」は5サイクル命令であり、遅いです。
//│16bitx16bit=32bit乗算で足ることが判っている場合は、1サイクル命令の「mlt(u).h」を使う方が効率が良いです。
//│S1C33のCコンパイラは「mlt(u).h」を生成しないので、代わりに、明示的に「mlt(u).h」を使えるようにしました。
#ifdef  PIECE
#define mlt_h(x,y) ({									\
	int __x__ = (x), __y__ = (y);							\
	asm /*volatile*/ ("mlt.h %1,%2" : "=l"(__x__) : "r"(__x__),"r"(__y__));		\
	__x__; })
#define mltu_h(x,y) ({									\
	int __x__ = (x), __y__ = (y);							\
	asm /*volatile*/ ("mltu.h %1,%2" : "=l"(__x__) : "r"(__x__),"r"(__y__));	\
	__x__; })
#else //PIECE
static __inline int mlt_h(int x, int y) {
	return (short)x * (short)y;
}
static __inline int mltu_h(int x, int y) {
	return (unsigned short)x * (unsigned short)y;
}
#endif//PIECE

//==============================================================================
//	シフト＆ローテート
//==============================================================================
//□xrrとxrlの使用例:
//│a = xrr(x,y)         'xrr reg,reg'に展開されます。
//│a = xrr(x,23)        'xrr reg,imm'に展開されます。 … 'xrr reg,reg'よりも効率の良いコードになります。このためにオペランド制約'r'でなく'g'を使用しました。
//│a = xrr(x,y+1)       'xrr reg,reg'に展開されます。
//│a = xrr(x,rand()%32) 'xrr reg,reg'に展開されます。
#ifdef  PIECE
#define xrr(x,y) ({									\
	int __x__ = (x);								\
	asm /*volatile*/ ("xrr %0,%2" : "=r"(__x__) : "0"(__x__),"g"(y) : "cc","%r9");	\
	__x__; })
#define xrl(x,y) ({									\
	int __x__ = (x);								\
	asm /*volatile*/ ("xrl %0,%2" : "=r"(__x__) : "0"(__x__),"g"(y) : "cc","%r9");	\
	__x__; })
#else //PIECE
static __inline int xrr(int x, int y) {
	while(y--) { x = ((unsigned)x >> 1) | ((unsigned)x << 31); }
	return x;
}
static __inline int xrl(int x, int y) {
	while(y--) { x = ((unsigned)x << 1) | ((unsigned)x >> 31); }
	return x;
}
#endif//PIECE

//==============================================================================
//	その他
//==============================================================================
//□xscan0とxscan1について:
//│命令エクステンダ(ext33.exe)にはxscan0,xscan1は無いので、「S1C33000コアCPUマニュアル」のコード例を参照して実装した。
//│%0と%2に同じレジスタが割り当てられないように、制約修飾子「&」を使用して%0が早期破壊オペランドであることを示す。
//│%2は入力オペランドであるが破壊されるので、__dummy__変数を用いて出力オペランド%1としても指定する必要がある。
//│参考資料:「GCCのインラインアセンブラの書き方 for x86」(http://d.hatena.ne.jp/wocota/20090628/1246188338)特定のレジスタをオペランドに割り当てとダミー変数
#ifdef  PIECE
#define xscan0(x) ({								\
	int __x__ = (x), __dummy__;						\
	asm /*volatile*/ (							\
		"scan0   %0,%2 \n sll %2,  %0 \n"				\
		"scan0 %%r9,%2 \n sll %2,%%r9 \n add %0,%%r9 \n"		\
		"scan0 %%r9,%2 \n sll %2,%%r9 \n add %0,%%r9 \n"		\
		"scan0 %%r9,%2 \n sll %2,%%r9 \n add %0,%%r9 \n"		\
		: "=&r"(__x__),"=r"(__dummy__) : "1"(__x__) : "cc","%r9");	\
	__x__; })
#define xscan1(x) ({								\
	int __x__ = (x), __dummy__;						\
	asm /*volatile*/ (							\
		"scan1   %0,%2 \n sll %2,  %0 \n"				\
		"scan1 %%r9,%2 \n sll %2,%%r9 \n add %0,%%r9 \n"		\
		"scan1 %%r9,%2 \n sll %2,%%r9 \n add %0,%%r9 \n"		\
		"scan1 %%r9,%2 \n sll %2,%%r9 \n add %0,%%r9 \n"		\
		: "=&r"(__x__),"=r"(__dummy__) : "1"(__x__) : "cc","%r9");	\
	__x__; })
#define swap(x) ({							\
	int __x__ = (x);						\
	asm /*volatile*/ ("swap %0,%1" : "=r"(__x__) : "r"(__x__));	\
	__x__; })
#define mirror(x) ({							\
	int __x__ = (x);						\
	asm /*volatile*/ ("mirror %0,%1" : "=r"(__x__) : "r"(__x__));	\
	__x__; })
#else //PIECE
static __inline int xscan0(int x) {
	int i;
	for(i = 0; i < 32; i++, x <<= 1) { if(x >= 0) { break; } }
	return i;
}
static __inline int xscan1(int x) {
	int i;
	for(i = 0; i < 32; i++, x <<= 1) { if(x <  0) { break; } }
	return i;
}
static __inline int swap(int x) {
	return (((unsigned char)((unsigned)x >>  0)) << 24) |
	       (((unsigned char)((unsigned)x >>  8)) << 16) |
	       (((unsigned char)((unsigned)x >> 16)) <<  8) |
	       (((unsigned char)((unsigned)x >> 24)) <<  0);
}
static __inline int mirror(int x) {
	extern const unsigned char mirror_table[0x100];//clipmirr.c
	return (mirror_table[(unsigned char)((unsigned)x >>  0)] <<  0) |
	       (mirror_table[(unsigned char)((unsigned)x >>  8)] <<  8) |
	       (mirror_table[(unsigned char)((unsigned)x >> 16)] << 16) |
	       (mirror_table[(unsigned char)((unsigned)x >> 24)] << 24);
}
#endif//PIECE

#endif//__MACHINE_H__
