/*	
 *	machine.h
 *
 *	CPU固有の命令
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2016 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用の実装を追加しました。
 *	* Sat Aug 16 15:46:20 JST 2014 Naoyuki Sawa
 *	- get_psr(),set_psr()を追加しました。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'〜'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 *	* Sun Dec 25 23:57:41 JST 2016 Naoyuki Sawa
 *	- xscan0()とxscan1()の最後に無駄なsllが有ったので削除しました。
*/
#ifndef __MACHINE_H__
#define __MACHINE_H__

#ifdef  __cplusplus
extern "C" {
#endif//__cplusplus

//■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」を付けない方が良い。付けても良いが無駄コードが生成される可能性がある。

//==============================================================================
//	データ転送
//==============================================================================
#ifdef  PIECE
struct psr {
	unsigned n : 1; /* [    0] */
	unsigned z : 1; /* [    1] */
	unsigned v : 1; /* [    2] */
	unsigned c : 1; /* [    3] */
	unsigned ie: 1; /* [    4] */
	unsigned   : 1; /* [    5] */
	unsigned ds: 1; /* [    6] */
	unsigned mo: 1; /* [    7] */
	unsigned il: 4; /* [11: 8] */
	unsigned   :20; /* [31:12] */
};
#define get_psr() ({				\
	struct psr __x__;			\
	asm("ld.w %0,%%psr" :  "=r"(__x__));	\
	__x__; })
#define set_psr(x) ({				\
	struct psr __x__ = (x);			\
	asm("ld.w %%psr,%0" : : "r"(__x__)); })
#endif//PIECE

//==============================================================================
//	算術演算
//==============================================================================
//□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
//{{2016/12/25変更:xscan0()とxscan1()の最後に無駄なsllが有ったので削除しました。
//#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__; })
//↓2016/12/25変更:xscan0()とxscan1()の最後に無駄なsllが有ったので削除しました。
// * Sun Dec 25 23:57:41 JST 2016 Naoyuki Sawa
// - xscan0()とxscan1()の最後に無駄なsllが有ったので削除しました。
//   33000Core-J.pdfのp.142の<例>を参考にして実装していたのですが、左記の<例>が元々無駄なsllを含んでいたようです。
//   最後のsllは結果には関係無いので、無駄な処理で削除可能でした。
#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                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                add %0,%%r9 \n"		\
		: "=&r"(__x__),"=r"(__dummy__) : "1"(__x__) : "cc","%r9");	\
	__x__; })
//}}2016/12/25変更:xscan0()とxscan1()の最後に無駄なsllが有ったので削除しました。
#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

#ifdef  __cplusplus
}//extern "C"
#endif//__cplusplus

#endif//__MACHINE_H__
