/*	
 *	cliplot.c
 *
 *	抽選処理
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2016 Naoyuki Sawa
 *
 *	* Tue May 29 00:54:45 JST 2012 Naoyuki Sawa
 *	- 1st リリース。
 *	* Sat Aug 03 00:18:29 JST 2013 Naoyuki Sawa
 *	- 抽選表のデータ構造を変更し、抽選列の数を追加しました。
 *	  LOT_draw_table()に不正な抽選列インデクスを指定した時、エラー停止するようにしました。
 *	- tool/MkLotTbl.awk を変更し、新しいデータ構造に沿った抽選表を出力するようにしました。
 *	  もう、古いデータ構造の抽選表を使用する事はありません。
 *	* Tue Jan 14 23:30:11 JST 2014 Naoyuki Sawa
 *	- 抽選表のデータ構造を変更し、抽選列のidを追加しました。
 *	  LOT_draw_table()の仕様を変更し、抽選列をインデクスでなくidとスキップ回数で指定するようにしました。
 *	- tool/MkLotTbl.awk を変更し、新しいデータ構造に沿った抽選表を出力するようにしました。
 *	  もう、古いデータ構造の抽選表を使用する事はありません。
 *	* Fri Jan 31 01:01:32 JST 2014 Naoyuki Sawa
 *	- LOT_get_column_weight()とLOT_get_table_weight()を追加しました。
 *	* Fri Feb 28 01:16:14 JST 2014 Naoyuki Sawa
 *	- LOT_get_table_size()とLOT_get_table_column_id()を追加しました。
 *	* Sat Aug 23 11:56:18 JST 2014 Naoyuki Sawa
 *	- LOT_draw_table_gl(),LOT_draw_table_ga(),LOT_draw_table_gv()を追加しました。
 *	- LOT_get_table_weight_gl(),LOT_get_table_weight_ga(),LOT_get_table_weight_gv()を追加しました。
 *	- LOT_get_table_size_g()を追加しました。
 *	* Mon Aug 25 20:01:41 JST 2014 Naoyuki Sawa
 *	- 「抽選表」の形式を変更しました。グループヘッダの概念は無くなりました。
 *	  既存の「「抽選表」に対する抽選処理」と「「グループヘッダ付き抽選表」に対する抽選処理」を削除して、
 *	  新しい「「抽選表」に対する抽選処理」を定義しました。
 *	* Thu Dec 04 21:39:33 JST 2014 Naoyuki Sawa
 *	- LotSym_ConvTo(),LotSym_ConvFrom()を追加しました。
 *	* Sun Mar 15 21:44:53 JST 2015 Naoyuki Sawa
 *	- LOT_get_column_weight()をリニアサーチ⇒バイナリサーチに変更しました。
 *	  関数仕様は変更有りません。
 *	  詳細は「clip/tool/dLotTblC/winapp.h」の2015/03/15コメントを参照してください。
 *	* Mon Oct 12 15:21:03 JST 2015 Naoyuki Sawa
 *	- USE_LOT_SEHシンボルを定義すると、cliplot.c内のDIE()を全て、SEH_throw(LotException)に置き換えるようにしました。
 *	  使用方法はclipprp.hのUSE_PRP_SEHと同様です。clipprp.hの2015/10/11のコメントを参照してください。
 *	* Mon Oct 12 16:53:24 JST 2015 Naoyuki Sawa
 *	- LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更し、LOT_draw_table_l()と統一しました。
 *	  LOT_get_table_weight_v(),LOT_get_table_weight_a()の引数順序を変更し、LOT_get_table_weight_l()と統一しました。
 *	  それに伴い、内部関数LOT_seek_and_call()の引数順序も変更しました。
 *	- これまでは、間違えて使用しないように意図的に引数順序を変えていましたが、実際に使って見るとその心配が少ない事が判ったからです。
 *	  一つ目の理由は、実際に使って見ると、ほとんど〜_l()経由でしか使わず、〜_a(),〜_v()と間違える事が生じるケースは少ないです。
 *	  二つ目の理由は、引数順序が統一されている方が、アセンブラ化した時にレジスタ間の値移動が少なく、最適化し易いからです。
 *	  以上の理由から、LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更する事に決定しました。
 *	- 今回の引数順序変更を、当モジュール内のコメントや使用例に、まだ反映していません。			┐
 *	  当モジュール内のコメントや使用例は、上記の関数の引数順序が実態と合っていない事に、注意してください。	├→※TODO:コメントや使用例も修正せよ。
 *	  今後、折を見て、コメントや使用例を修正する予定です。							┘
 *	* Wed Oct 14 21:50:46 JST 2015 Naoyuki Sawa
 *	- clipseh.hにてSEH_info構造体に'msg'フィールドを追加した事に伴い、当モジュールのLOT_throw()の実装も変更しました。
 *	* Fri Nov 06 21:43:13 JST 2015 Naoyuki Sawa
 *	- '_equally'版の関数を追加しました。
 *	  '_equally'版の関数は、抽選データのテスト用であり、高速化は不要だと思うので、アセンブラ化していません。	⇒{{2016/07/17追記:'_equally'版の関数をアセンブラ化しました。}}
 *	  詳細は、cliplot.hのLOT_draw_column_equally()関数宣言のコメントを参照して下さい。
 *	* Sat Nov 07 21:57:31 JST 2015 Naoyuki Sawa
 *	- LOT_get_column_weight()が汎用のbsearch()を呼び出すのをやめて、LOT_get_column_weight()自身がバイナリサーチを行うように変更して、高速化しました。
 *	  アルゴリズムや最適化の工夫はcliplibc.cのbsearch()の実装,及び,clipreg.cのREG_bsearch()で行った工夫と同じです。
 *	* Sun Jul 17 22:34:56 JST 2016 Naoyuki Sawa
 *	- '_equally'版の関数をアセンブラ化しました。
 *	  今回アセンブラ化した関数は、LOT_draw_table_equally_l(),LOT_draw_table_equally_a(),LOT_draw_table_equally_v()です。
 *	  LOT_draw_column_equally()は、例外投入処理が有りアセンブラ化しづらいので、今回はアセンブラ化していません。
 *	* Sat Aug 20 21:19:11 JST 2016 Naoyuki Sawa
 *	- Exp10_Decode(),Exp10_Encode()を追加しました。
 *	  詳細は、cliplot.hの「16ビットで大きな値を表現するための、指数表現」の、同日のコメントを参照して下さい。
 *	- dLotTblC.exeにも、指数表現を格納するためのキャスト演算子'(exp10)'を追加しました。
 *	  詳細は、/clip/tool/dLotTblC/winapp.h の、同日のコメントを参照して下さい。
 *	* Sun Aug 21 21:04:02 JST 2016 Naoyuki Sawa
 *	- Exp10_Decode(),Exp10_Encode()をアセンブラ化しました。
 *	  アセンブラ化の効果は、約10%の高速化、及び、40バイトのコード容量削減です。
 *	* Mon Sep 05 21:24:05 JST 2016 Naoyuki Sawa
 *	- 64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
 *	  setjmp()/longjmp()のパラメータは(int)であり、(void*)や(intptr_t)を使えないからです。
 *	  尚、32ビット版も64ビット版と共通に変更しても良いのですが、万一既存のコードに影響が生じる事を防ぐために、32ビット版はこれまで通りとしました。
 */
#include "clip.h"

//{{2015/10/12追加:USE_LOT_SEHシンボルを定義すると、cliplot.c内のDIE()を全て、SEH_throw(LotException)に置き換えるようにしました。
#ifdef  USE_LOT_SEH
//USE_LOT_SEHシンボルが定義されたら、cliplot.c内のDIE()を全て、SEH_throw(LotException)に置き換えます。
#undef  DIE
#ifndef PIECE
  #define DIE() SEH_throw(LotException)
#else //PIECE
  //P/ECEでも上のように定義しても良いのですが、メモリ節約のため下のように定義する事にしました。結果は同じになります。
  //以下の定義はclipseh.hのSEH_throw()の定義に依存しています。もし今後SEH_throw()を変更する時は以下も変更して下さい。
  #define DIE() do { LOT_throw(__FILE__, __LINE__); } while(0)
  static void __attribute__((noreturn)) LOT_throw(const char* file, int line) {
    SEH_info.file = file;
    SEH_info.line = line;
    SEH_info.msg  = NULL;
    SEH_longjmp((int)LotException); }
#endif//PIECE
//{{2016/09/05変更:64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
//const char LotException[1/*dummy*/];
//↓2016/09/05変更:64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
#ifndef _WIN64
const char LotException[1/*dummy*/];	//32ビット版
#endif//_WIN64
//}}2016/09/05変更:64ビット版では、例外コードをアドレスでなく、一意なFourCC識別子で表すようにしました。
#endif//USE_LOT_SEH
//}}2015/10/12追加:USE_LOT_SEHシンボルを定義すると、cliplot.c内のDIE()を全て、SEH_throw(LotException)に置き換えるようにしました。

/****************************************************************************
 *	「抽選列」に対する抽選処理
 ****************************************************************************/

#ifndef PIECE
int LOT_draw_column(const unsigned short* column, int column_size, int rndval) {
	int hitval, weight;
	for(;;) {
		/* 抽選列の終端に到達したら、-1を返します。 */
		if(--column_size < 0) { return -1; }
		/*  当選値   を取得します。 */
		hitval = *column++;
		/* (重み値-1)を取得します。 */
		weight = *column++;
		/* 乱数値から重み値を引き、0未満になったら当選です。 */
		if((rndval -= (weight + 1)) < 0) { return hitval; }
	}
}
#else /*PIECE*/
int LOT_draw_column(const unsigned short* column, int column_size, int rndval);
asm("
		.code
		.align		1
		.global		LOT_draw_column
LOT_draw_column:
		;// %r12 := column
		;// %r13 := column_size
		;// %r14 := rndval
LOT_draw_column_LOOP:
		sub		%r13, 1			;// %r13 := column_size--
		jrlt		LOT_draw_column_MISS	;// if(column_size < 0) return -1
		;//
		ld.uh		%r10, [%r12]+		;// %r10 := hitval = *column++
		ld.uh		%r11, [%r12]+		;// %r11 := weight = *column++
;//{{高速化
;//		add		%r11, 1			;// %r11 :=           (weight + 1)
;//		sub		%r14, %r11		;// %r14 := rndval -= (weight + 1)
;//		jrge		LOT_draw_column_LOOP	;// if(rndval <  0) return hitval
;//↓高速化
		sub		%r14, %r11		;// %r14 := rndval -= (weight    )
		jrgt.d		LOT_draw_column_LOOP	;// if(rndval <= 0) return hitval
		sub		%r14, 1			;// %r14 := rndval -= (         1)	*delay*
;//}}高速化
		ret					;// return  hitval
LOT_draw_column_MISS:
		ret.d					;// return  -1
		ld.w		%r10, -1		;// %r10 := -1				*delay*
");
#endif/*PIECE*/

//{{2015/11/06追加:'_equally'版の関数を追加しました。
#ifdef  USE_LOT_EQUALLY
int LOT_draw_column_equally(const unsigned short* column, int column_size, int rndval) {
	if(column_size <= 0) { DIE(); }
	rndval = (unsigned)rndval % (unsigned)column_size;
	return column[(rndval * 2/*{hitval,weight}*/) + 0/*hitval*/];
}
#endif//USE_LOT_EQUALLY
//}}2015/11/06追加:'_equally'版の関数を追加しました。

/*--------------------------------------------------------------------------*/

//{{2015/03/15変更:LOT_get_column_weight()をリニアサーチ⇒バイナリサーチに変更しました。関数仕様は変更有りません。詳細は「clip/tool/dLotTblC/winapp.h」の2015/03/15コメントを参照してください。
//#ifndef PIECE
//int LOT_get_column_weight(const unsigned short* column, int column_size, int hitval_sel) {
//	int hitval, weight;
//	for(;;) {
//		/* 抽選列の終端に到達したら、0を返します。 */
//		if(--column_size < 0) { return 0; }
//		/*  当選値   を取得します。 */
//		hitval = *column++;
//		/* (重み値-1)を取得します。 */
//		weight = *column++;
//		/* 当選値が一致したら、重み値(1〜65536)を返します。 */
//		if(hitval == hitval_sel) { return (weight + 1); }
//	}
//}
//#else /*PIECE*/
//int LOT_get_column_weight(const unsigned short* column, int column_size, int hitval_sel);
//asm("
//		.code
//		.align		1
//		.global		LOT_get_column_weight
//LOT_get_column_weight:
//		;// %r12 := column
//		;// %r13 := column_size
//		;// %r14 := hitval_sel
//LOT_get_column_weight_LOOP:
//		sub		%r13, 1				;// %r13 := column_size--
//		jrlt		LOT_get_column_weight_MISS	;// if(column_size < 0) return 0
//		;//
//		ld.uh		%r11, [%r12]+			;// %r11 := hitval = *column++
//		ld.uh		%r10, [%r12]+			;// %r10 := weight = *column++
//		cmp		%r11, %r14			;// if(hitval == hitval_sel)
//		jrne		LOT_get_column_weight_LOOP
//		ret.d						;//   return  (weight + 1)
//		add		%r10, 1				;//   %r10 := (weight + 1)	*delay*
//LOT_get_column_weight_MISS:
//		ret.d						;// return  0
//		ld.w		%r10, 0				;// %r10 := 0			*delay*
//");
//#endif/*PIECE*/
//↓2015/03/15変更:LOT_get_column_weight()をリニアサーチ⇒バイナリサーチに変更しました。関数仕様は変更有りません。詳細は「clip/tool/dLotTblC/winapp.h」の2015/03/15コメントを参照してください。
//#ifndef PIECE
//static int LOT_get_column_weight_compar(const void* _x, const void* _y) {
//	int x = *(unsigned short*)_x;	//x[2]={hitval,weight}のhitvalの部分のみを参照します。
//	int y = *(unsigned short*)_y;	//y[2]={hitval,weight}のhitvalの部分のみを参照します。
//	return x - y;	//(unsigned short)なのでオーバーフローの心配は無く単純な減算結果を返せば良い。
//}
//int LOT_get_column_weight(const unsigned short* column, int column_size, int hitval_sel) {
//	//当選値(0〜65535)の範囲外の値が指定された場合は、指定された当選値の行が見つからなかったのと同じで0を返します。
//	if((unsigned)hitval_sel > USHRT_MAX) { return 0; }
//	//指定された当選値の行を検索します。
//	column = bsearch(
//		&hitval_sel,	//下位ハーフワード部分のみを参照します。
//		column,
//		column_size,
//		sizeof(unsigned short) * 2/*{hitval,weight}*/,
//		LOT_get_column_weight_compar);
//	//指定された当選値の行が見つからなければ0を返します。
//	if(!column) { return 0; }
//	//指定された当選値の行が見つかったら重み値(1〜65536)を返します。
//	return *(column + 1/*weight*/) + 1;
//}
//#else //PIECE
//int LOT_get_column_weight(const unsigned short* column, int column_size, int hitval_sel);
//asm("
//		.code
//		.align		1
//		.global		LOT_get_column_weight
//LOT_get_column_weight:
//		;//%r12 := column
//		;//%r13 := column_size
//		;//%r14 := hitval_sel
//		xcmp		%r14, 0xFFFF				;//if((unsigned)hitval_sel > USHRT_MAX) {
//		jrugt.d		LOT_get_column_weight_RET		;//  %r10     := x = -1
//		ld.w		%r10, -1				;//  goto RET }																		*delay*
//		xsub		%sp, %sp, 8				;//
//		xld.h		[%sp+4], %r14				;//[%sp+4].uh := hitval_sel
//		ld.w		%r14, %r13				;//%r14       := column_size
//		ld.w		%r13, %r12				;//%r13       := column
//		ld.w		%r12, %sp				;//%r12       := &[%sp+0]
//		xld.w		%r9, LOT_get_column_weight_compar	;//%r9        := LOT_get_column_weight_compar
//		ld.w		[%r12]+, %r9				;//[%sp+0].w  := LOT_get_column_weight_compar, %r12 := &hitval_sel
//		xcall.d		bsearch					;//%r10       := column = bsearch(&hitval_sel, column, column_size, sizeof(unsigned short) * 2/*{hitval,weight}*/, LOT_get_column_weight_compar)
//		ld.w		%r15, 4					;//%r15       :=                                                    sizeof(unsigned short) * 2/*{hitval,weight}*/					*delay*
//		sub		%r10, 1					;//%r10       := x = column - 1
//		jrult.d		4					;//if(x != -1) {
//		 xadd		%sp, %sp, 8				;//																			*delay*
//		 add		%r10, 3					;//  %r10     :=   column + sizeof(unsigned short) = x + 1 + sizeof(unsigned short)
//		 ld.uh		%r10, [%r10]				;//  %r10     := *(column + sizeof(unsigned short))
//LOT_get_column_weight_RET:
//		ret.d							;//return        x + 1
//		add		%r10, 1					;//%r10       := x + 1																	*delay*
//		;//-----------------------------------------------------;//
//LOT_get_column_weight_compar:
//		;//%r12 := _x
//		;//%r13 := _y
//		ld.uh		%r10, [%r12]				;//%r10 := x = *(unsigned short*)_x
//		ld.uh		%r9 , [%r13]				;//%r9  := y = *(unsigned short*)_y
//		ret.d							;//return  x - y
//		sub		%r10, %r9				;//%r10 := x - y																	*delay*
//");
//#endif//PIECE
//↓2015/11/07変更:LOT_get_column_weight()が汎用のbsearch()を呼び出すのをやめて、LOT_get_column_weight()自身がバイナリサーチを行うように変更して、高速化しました。
// * Sat Nov 07 21:57:31 JST 2015 Naoyuki Sawa
// - LOT_get_column_weight()が汎用のbsearch()を呼び出すのをやめて、LOT_get_column_weight()自身がバイナリサーチを行うように変更して、高速化しました。
//   アルゴリズムや最適化の工夫はcliplibc.cのbsearch()の実装,及び,clipreg.cのREG_bsearch()で行った工夫と同じです。
#ifndef PIECE
int LOT_get_column_weight(const unsigned short* column, int column_size/*>=0*/, int hitval_sel) {
	const unsigned short* mid;
	int hitval, weight;
	if((unsigned)hitval_sel <= USHRT_MAX) {	//当選値(0〜65535)の範囲外の値が指定された場合は、指定された当選値の行が見つからなかったのと同じで0を返します。
		goto L_START;
		do {
			mid = column + ((column_size >> 1) * 2/*{hitval,weight}*/);
			hitval = *mid++;
			weight = *mid++;
			hitval -= hitval_sel;
			if(!hitval) { return weight + 1; }	//指定された当選値の行が見つかったら重み値(1〜65536)を返します。
			if(hitval < 0) {
				column = mid;	//bsearch()の場合は(mid+size)を代入する所だが、当関数の場合midは既に(mid+size)へ進んでいるのでmidの代入で済む。
				column_size--;
			}
			column_size >>= 1;
L_START:		;
		} while(column_size);
	}
	return 0;	//指定された当選値の行が見つからなければ0を返します。
}
#else //PIECE
int LOT_get_column_weight(const unsigned short* column, int column_size/*>=0*/, int hitval_sel);
asm("
		.code
		.align		1
		.global		LOT_get_column_weight
LOT_get_column_weight:
		;//%r12 := column
		;//%r13 := column_size
		;//%r14 := hitval_sel
		xcmp		%r14, 65535				;//if((unsigned)hitval_sel <= USHRT_MAX) {
		jrugt		LOT_get_column_weight_RET0		;//  
		jp.d		LOT_get_column_weight_START		;//  goto L_START
		cmp		%r13, 0					;//  %psr(Z) := !column_size	────────────────────────┐	*delay*
LOT_get_column_weight_LOOP:						;//  do {									│
		sra		%r4, 1					;//    %r4  :=                 (column_size >> 1)				│
		sla		%r4, 2					;//    %r4  :=                ((column_size >> 1) * 2/*{hitval,weight}*/)	│
		add		%r4, %r12				;//    %r4  := mid = column + ((column_size >> 1) * 2/*{hitval,weight}*/)	│
		ld.uh		%r5, [%r4]+				;//    %r5  := hitval = *mid++							│
		ld.uh		%r10, [%r4]+				;//    %r10 := weight = *mid++							│
		sub		%r5, %r14				;//    %r5  := hitval -= hitval_sel						│
		jreq		LOT_get_column_weight_RETW		;//    if(!diff) { return weight + 1 }						│
		jrge		3					;//    if(diff < 0) {								│
		 ld.w		%r12, %r4				;//      %r12 := column = mid							│
		 sub		%r13, 1					;//      %r13 := column_size-- }						│
		sra		%r13, 1					;//    %r13 := column_size >>= 1						│
LOT_get_column_weight_START:						;//    										│
		jrne.d		LOT_get_column_weight_LOOP		;//  } while(column_size)	←───────────────────────┘
		ld.w		%r4, %r13				;//    %r4  := column_size								*delay*
LOT_get_column_weight_RET0:						;//}
		ld.w		%r10, -1				;//return  (-1+1)/*=0*/
LOT_get_column_weight_RETW:						;//
		ret.d							;//return  weight + 1
		add		%r10, 1					;//%r10 := weight + 1									*delay*
");
#endif//PIECE
//}}2015/11/07変更:LOT_get_column_weight()をリニアサーチ⇒バイナリサーチに変更しました。関数仕様は変更有りません。詳細は「clip/tool/dLotTblC/winapp.h」の2015/03/15コメントを参照してください。

//{{2014/08/25削除:「抽選表」形式変更のために、古いコードを削除しました。古いコードは2014/08/24まで問題無く動作していたので、参考用としてコメント化したまま残しておきます。
//	
//	/****************************************************************************
//	 *	「抽選表」に対する抽選処理
//	 ****************************************************************************/
//	
//	#ifndef PIECE
//	static int LOT_seek_and_call(const unsigned short* table, int id_skip, int param, int (*fn)(const unsigned short* column, int column_size, int param)) {
//		int id, skip, table_size, column_id, column_size;
//		/* 抽選列のidとスキップ回数を分離します。 */
//		id   = (unsigned short)(id_skip >>  0); /* 0〜65535 */
//		skip = (unsigned short)(id_skip >> 16); /* 0〜65535 */
//		/* 抽選表の列数を取得します。 */
//		table_size = *table++;
//		for(;;) {
//			/* 抽選表の最終列を超えていたら、エラー停止します。 */
//			if(--table_size < 0) { DIE(); } /* データエラー: 抽選表の中に、指定されたidを持つ抽選列が、(skip+1)回以上出現しなかった。 */
//			/* 抽選列のidを取得します。 */
//			column_id   = *table++;
//			/* 抽選列の要素数を取得します。 */
//			column_size = *table++;
//			/* 指定されたidを持つ抽選列が見つかったら、スキップ回数を減らし0未満になったら、関数を実行します。 */
//			if((column_id == id) && (--skip < 0)) { return (*fn)(table, column_size, param); }
//			/* 抽選列をスキップします。 */
//			table += column_size * 2/*{hitval,weight}*/;
//		}
//	}
//	#else /*PIECE*/
//	/*static*/ int LOT_seek_and_call(const unsigned short* table, int id_skip, int param, int (*fn)(const unsigned short* column, int column_size, int param));
//	asm("
//			.code
//			.align		1
//	LOT_seek_and_call:
//			;// %r12        := table
//			;// %r13[15: 0] := id
//			;// %r13[31:16] := skip
//			;// %r14        := param
//			;// %r15        := fn
//			ld.uh		%r4, %r13		;// %r4  := id   = (unsigned short)(id_skip >>  0) /* 0〜65535 */
//			ld.w		%r5, %r13		;// %r5  := skip = (unsigned short)(id_skip >> 16) /* 0〜65535 */
//			xsrl		%r5, 16
//			ld.uh		%r6, [%r12]+		;// %r6  := table_size = *table++
//	LOT_seek_and_call_LOOP:					;// for(;;) {
//			sub		%r6, 1			;//   %r6  := table_size--
//			jrlt		LOT_seek_and_call_DIE	;//   if(table_size < 0) { DIE() } /* データエラー: 抽選表の中に、指定されたidを持つ抽選列が、(skip+1)回以上出現しなかった。 */
//			ld.uh		%r9, [%r12]+		;//   %r9  := column_id   = *table++
//			ld.uh		%r13, [%r12]+		;//   %r13 := column_size = *table++
//			cmp		%r9, %r4		;//   if((column_id == id)
//			jrne		3
//			 sub		%r5, 1			;//   && (--skip < 0)) { break }
//			 jrlt		LOT_seek_and_call_RET
//			sla		%r13, 2			;//   %r13 :=          column_size * 4
//			jp.d		LOT_seek_and_call_LOOP	;// }
//			add		%r12, %r13		;//   %r12 := table += column_size * 4	*delay*
//	LOT_seek_and_call_RET:
//			jp		%r15			;// return (*fn)(table, column_size, param)
//	");
//	static void __attribute__((noreturn,unused)) LOT_seek_and_call_DIE() { DIE(); /*抽選列インデクスが不正*/ } /*asmブロックから参照*/
//	#endif/*PIECE*/
//	
//	/*--------------------------------------------------------------------------*/
//	
//	#ifndef PIECE
//	int LOT_draw_table(const unsigned short* table, int id_skip, int rndval) {
//		return LOT_seek_and_call(table, id_skip, rndval, LOT_draw_column);
//	}
//	#else /*PIECE*/
//	int LOT_draw_table(const unsigned short* table, int id_skip, int rndval);
//	asm("
//			.code
//			.align		1
//			.global		LOT_draw_table
//	LOT_draw_table:
//			xld.w		%r15, LOT_draw_column
//			jp		LOT_seek_and_call
//	");
//	#endif/*PIECE*/
//	
//	/*--------------------------------------------------------------------------*/
//	
//	#ifndef PIECE
//	int LOT_get_table_weight(const unsigned short* table, int id_skip, int hitval_sel) {
//		return LOT_seek_and_call(table, id_skip, hitval_sel, LOT_get_column_weight);
//	}
//	#else /*PIECE*/
//	int LOT_get_table_weight(const unsigned short* table, int id_skip, int hitval_sel);
//	asm("
//			.code
//			.align		1
//			.global		LOT_get_table_weight
//	LOT_get_table_weight:
//			xld.w		%r15, LOT_get_column_weight
//			jp		LOT_seek_and_call
//	");
//	#endif/*PIECE*/
//	
//	/*--------------------------------------------------------------------------*/
//	
//	#ifndef PIECE
//	int LOT_get_table_column_id(const unsigned short* table, int i_column) {
//		int table_size, column_size, id, skip;
//		const unsigned short* column;
//		/* 抽選表の列数を取得します。 */
//		table_size = *table++;
//		/* 抽選表の列数が、抽選列の順番(0〜)以下である場合は、エラー停止します。 */
//		if(table_size <= i_column) { DIE(); }
//		/* (i_column)番目の抽選列の、idを取得します。 */
//		column = table;
//		while(--i_column >= 0) {
//			               column++; /*column_id*/
//			column_size = *column++;
//			               column += column_size * 2/*{hitval,weight}*/;
//		}
//		id = *column;
//		/* (i_column)番目の抽選列よりも前に、(i_column)番目の抽選列と同じidの抽選列が存在する場合、その列数をスキップ回数として数えます。 */
//		skip = 0;
//		while(table != column) {
//			           if(*table++ == id) { skip += (1<<16); } /*column_id*/
//			column_size = *table++;
//			               table += column_size * 2/*{hitval,weight}*/;
//		}
//		/* 抽選列のidと、スキップ回数を返します。 */
//		return id | skip;
//	}
//	#else /*PIECE*/
//	asm("
//			.code
//			.align		1
//			.global		LOT_get_table_column_id
//	LOT_get_table_column_id:
//			ld.uh		%r15, [%r12]+			;// %r15 := table_size = *table++;
//			cmp		%r15, %r13			;// if(table_size <= i_column) { DIE() }
//			jrle		LOT_get_table_column_id_DIE
//			ld.w		%r14, %r12			;// %r14 := column
//			;// %r12 := table	抽選列[0]を指している
//			;// %r13 := i_column
//			;// %r14 := column	抽選列[0]を指している
//	LOT_get_table_column_id_LOOP1:
//			sub		%r13, 1				;// while(--i_column >= 0) {
//			jrlt		LOT_get_table_column_id_EXIT1
//			add		%r14, 2				;//   %r14 :=                column++
//			ld.uh		%r15, [%r14]+			;//   %r15 := column_size = *column++
//			sla		%r15, 2				;//   %r15 :=                          (column_size * 4)
//			jp.d		LOT_get_table_column_id_LOOP1	;// }
//			add		%r14, %r15			;//   %r14 :=                column += (column_size * 4)	*delay*
//	LOT_get_table_column_id_EXIT1:
//			ld.uh		%r10, [%r14]			;// %r10 := id = *column
//			ld.w		%r11, 0				;// %r11 := skip = 0
//			;// %r10 := id		抽選列[i_column]のcolumn_id
//			;// %r11 := skip
//			;// %r12 := table	抽選列[0]を指している
//			;// %r14 := column	抽選列[i_column]を指している
//	LOT_get_table_column_id_LOOP2:
//			cmp		%r12, %r14			;// while(table != column) {
//			jreq		LOT_get_table_column_id_EXIT2
//			ld.uh		%r13, [%r12]+			;//   %r13 := column_id   = *table++
//			ld.uh		%r15, [%r12]+			;//   %r15 := column_size = *table++
//			cmp		%r13, %r10			;//   if(column_id == id) {
//			jrne.d		LOT_get_table_column_id_SKIP
//			 sla		%r15, 2				;//   %r15 :=                         (column_size * 4)		*delay*
//			 xadd		%r11, %r11, 0x10000		;//     %r11 := skip += (1<<16)							「ここで1加算し最後に16ビットシフトしてorする」よりも「ここで(1<<16)加算し最後にそのままorする」方が一命令節約できる。一般的な抽選表ではskip=0であることが多くここを通ることは少ないので性能低下はほぼ無いであろう。
//	LOT_get_table_column_id_SKIP:
//			jp.d		LOT_get_table_column_id_LOOP2	;// }
//			add		%r12, %r15			;//   %r12 :=                table += (column_size * 4)		*delay*
//	LOT_get_table_column_id_EXIT2:
//			ret.d						;// return  id | skip
//			or		%r10, %r11			;// %r10 := id | skip						*delay*
//	");
//	static void __attribute__((noreturn,unused)) LOT_get_table_column_id_DIE() { DIE(); }
//	#endif/*PIECE*/
//	
//	/****************************************************************************
//	 *	「グループヘッダ付き抽選表」に対する抽選処理
//	 ****************************************************************************/
//	
//	static int LOT_seek_and_call_g(const unsigned short* table_g, const int* vp, int param, int (*fn)(const unsigned short* column, int column_size, int param)) {
//		int i, num_grps, grp_cols, id_skip = 0;
//		/* グループ数を取得する。 */
//		num_grps = *table_g++;
//		for(;;) {
//			/* グループインデクス,又は,抽選列のidを取得する。 */
//			i = *vp++;
//			/* グループインデクス,又は,抽選列のidが、符号無しハーフワード値であることを確認する。 */
//			if((unsigned)i >= USHRT_MAX) { DIE(); }
//			/* グループが無ければ(=デクリメントする前に0だったら)、抜ける。 */				//iは抽選列のidである。
//			if(--num_grps < 0) { break; }
//			/* グループ列数を取得する。 */
//			grp_cols = *table_g++;
//			/* グループ列数が0でないことと、グループインデクスがグループ列数未満であることを確認する。 */	//iはグループインデクスである。
//			if((unsigned)i >= (unsigned)grp_cols) { DIE(); }
//			/* 上位のスキップ回数に今回のグループ列数を乗じて、グループインデクスを加える。 */
//			id_skip = (id_skip * grp_cols) + i;
//			/* スキップ回数が、符号無しハーフワード値であることを確認する。 */	//オーバーフローを見落とさないよう、最終結果だけではなく毎回確認する。
//			if((unsigned)id_skip >= USHRT_MAX) { DIE(); }
//		}
//		/* スキップ回数を上位ハーフワードへシフトして、下位ハーフワードに抽選列のidを格納する。 */
//		id_skip = (id_skip << 16) | i;
//		/* 可変引数の終端が、(-1)であることを確認する。 */
//		if(*vp != -1) { DIE(); }
//		/* スキップ回数と抽選列のidの組合せを用いて、関数を実行する。 */
//		return (*fn)(table_g, id_skip, param);
//	}
//	
//	/*--------------------------------------------------------------------------*/
//	
//	int LOT_draw_table_gl(const unsigned short* table_g, int rndval, ...) {
//		int retval;
//		va_list ap;
//		va_start(ap, rndval);
//		retval = LOT_draw_table_ga(table_g, ap, rndval);
//		va_end(ap);
//		return retval;
//	}
//	int LOT_draw_table_ga(const unsigned short* table_g, va_list ap, int rndval) {
//		int vp[(7+1)/*調整可*/], i = 0;			//グループ数7(終端含め8)有れば充分と考えた。不足した場合は増やせ。
//		for(;;) {
//			if((vp[i] = va_arg(ap, int)) == -1) { break; }
//			if(++i >= ARRAY_SIZE(vp)) { DIE(); }	//ここで停止した場合、vp[]不足か,又は,呼出し側が終端を忘れている。おそらく後者であろう。
//		}
//		return LOT_draw_table_gv(table_g, vp, rndval);
//	}
//	int LOT_draw_table_gv(const unsigned short* table_g, const int* vp, int rndval) {
//		return LOT_seek_and_call_g(table_g, vp, rndval, LOT_draw_table);
//	}
//	
//	/*--------------------------------------------------------------------------*/
//	
//	int LOT_get_table_weight_gl(const unsigned short* table_g, int hitval_sel, ...) {
//		int retval;
//		va_list ap;
//		va_start(ap, hitval_sel);
//		retval = LOT_get_table_weight_ga(table_g, ap, hitval_sel);
//		va_end(ap);
//		return retval;
//	}
//	int LOT_get_table_weight_ga(const unsigned short* table_g, va_list ap, int hitval_sel) {
//		int vp[(7+1)/*調整可*/], i = 0;			//グループ数7(終端含め8)有れば充分と考えた。不足した場合は増やせ。
//		for(;;) {
//			if((vp[i] = va_arg(ap, int)) == -1) { break; }
//			if(++i >= ARRAY_SIZE(vp)) { DIE(); }	//ここで停止した場合、vp[]不足か,又は,呼出し側が終端を忘れている。おそらく後者であろう。
//		}
//		return LOT_get_table_weight_gv(table_g, vp, hitval_sel);
//	}
//	int LOT_get_table_weight_gv(const unsigned short* table_g, const int* vp, int hitval_sel) {
//		return LOT_seek_and_call_g(table_g, vp, hitval_sel, LOT_get_table_weight);
//	}
//	
//}}2014/08/25削除:「抽選表」形式変更のために、古いコードを削除しました。古いコードは2014/08/24まで問題無く動作していたので、参考用としてコメント化したまま残しておきます。

//{{2014/08/25追加:これ以降は、2014/08/25「抽選表」形式変更後に追加した、新しいコードです。}}

/****************************************************************************
 *	「抽選表」に対する抽選処理
 ****************************************************************************/

#ifndef PIECE
//{{2015/10/12変更:LOT_seek_and_call()の引数順序を変更しました。
//static int LOT_seek_and_call(const unsigned short* table, const int* pid, int param, int (*fn)(const unsigned short* column, int column_size, int param)) {
//↓2015/10/12変更:LOT_seek_and_call()の引数順序を変更しました。
static int LOT_seek_and_call(const unsigned short* table, int param, const int* pid, int (*fn)(const unsigned short* column, int column_size, int param)) {
//}}2015/10/12変更:LOT_seek_and_call()の引数順序を変更しました。
	int table_size, id_size, column_size, n_id, diff;
	/* 抽選表の列数を取得します。 */
	table_size = *table++;
	/* 抽選列のid行数を取得します。 */
	id_size    = *table++;
	for(;;) {
		/* 抽選表の最終列を超えていたら、エラー停止します。 */
		if(--table_size < 0) { DIE(); }
		/* 抽選列のidを比較します。 */
		n_id = id_size;
		diff = 0;
		while(--n_id >= 0) { diff |= (*table++ - *pid++); }		//アプリケーションが誤って抽選列のid行数を少なく指定した場合、ここで不一致となる。
		/* 抽選列の要素数を取得します。 */
		column_size = *table++;
		/* 指定されたidの組合せを持つ抽選列が見つかったら、抜けます。 */
		if(!diff) { break; }
		/* 指定されたidの組合せのポインタを戻します。 */
		pid -= id_size;
		/* 抽選列をスキップします。 */
		table += column_size * 2/*{hitval,weight}*/;
	}
	/* 指定された抽選列のidの組合せの、終端を確認します。 */
	if(*pid != -1) { DIE(); }						//アプリケーションが誤って抽選列のid行数を多く指定した場合、ここでエラー停止する。
	/* 関数を実行します。 */
	return (*fn)(table, column_size, param);
}
#else /*PIECE*/
//{{2015/10/12変更:LOT_seek_and_call()の引数順序を変更しました。
///*static*/ int LOT_seek_and_call(const unsigned short* table, const int* pid, int param, int (*fn)(const unsigned short* column, int column_size, int param));
//asm("
//		.code
//		.align		1
//LOT_seek_and_call:
//		;//%r12 := table
//		;//%r13 := pid
//		;//%r14 := param
//		;//%r15 := fn
//		ld.uh		%r4, [%r12]+					;//%r4  := table_size = *table++
//		ld.uh		%r5, [%r12]+					;//%r5  := id_size    = *table++
//		sla		%r5, 2						;//%r5  := id_size * sizeof(int)
//LOT_seek_and_call_L1:								;//for(;;) {
//		;//%r4  := table_size
//		;//%r5  := id_size * sizeof(int)
//		;//%r12 := table
//		;//%r13 := pid
//		;//%r14 := param
//		;//%r15 := fn
//		sub		%r4, 1						;//%r4  := table_size--
//		jrlt		LOT_seek_and_call_DIE				;//if(table_size < 0) { DIE() }
//		ld.w		%r6, %r5					;//%r6  := n_id = id_size * sizeof(int)
//		ld.w		%r7, 0						;//%r7  := diff = 0
//LOT_seek_and_call_L2:								;//for(;;) {
//		;//%r4  := table_size
//		;//%r5  := id_size * sizeof(int)
//		;//%r6  := n_id
//		;//%r7  := diff
//		;//%r12 := table
//		;//%r13 := pid
//		;//%r14 := param
//		;//%r15 := fn
//		sub		%r6, 4						;//%r6  := n_id -= sizeof(int)
//		jrlt		LOT_seek_and_call_L3				;//if(n_id < 0) { break }
//		ld.uh		%r10, [%r12]+					;//%r10 :=          id1       = *table++
//		ld.w		%r11, [%r13]+					;//%r11 :=                id2 = *pid++
//		sub		%r10, %r11					;//%r10 :=         (id1 - id2)
//		jp.d		LOT_seek_and_call_L2				;//}
//		or		%r7, %r10					;//%r7  := diff |= (id1 - id2)					*delay*
//LOT_seek_and_call_L3:
//		;//%r4  := table_size
//		;//%r5  := id_size * sizeof(int)
//		;//%r7  := diff
//		;//%r12 := table
//		;//%r13 := pid
//		;//%r14 := param
//		;//%r15 := fn
//		ld.uh		%r6, [%r12]+					;//%r6  := column_size = *table++
//		cmp		%r7, 0						;//if(!diff) { break }
//		jreq		LOT_seek_and_call_L4
//		sub		%r13, %r5					;//%r13 := pid -=   (    id_size *     sizeof(int)           )
//		sla		%r6, 2						;//%r6  :=          (column_size * 2 * sizeof(unsigned short))
//		jp.d		LOT_seek_and_call_L1				;//}
//		add		%r12, %r6					;//%r12 := table += (column_size * 2 * sizeof(unsigned short))	*delay*
//LOT_seek_and_call_L4:
//		;//%r6  := column_size
//		;//%r12 := table
//		;//%r13 := pid
//		;//%r14 := param
//		;//%r15 := fn
//		ld.w		%r4, [%r13]					;//%r4  := id2 = *pid
//		ld.w		%r13, %r6					;//%r13 := column_size		←───┐			*anti-interlock*
//		cmp		%r4, -1						;//if(id2 != -1) { DIE() }		│
//		jrne		LOT_seek_and_call_DIE				;//					│
//;//		ld.w		%r13, %r6					;//%r13 := column_size		────┘
//		jp		%r15						;//return (*fn)(table, column_size, param)			(jp.d %rbは不可)
//");
//static void __attribute__((noreturn,unused/*asmブロックから参照*/)) LOT_seek_and_call_DIE() { DIE(); }
//↓2015/10/12変更:LOT_seek_and_call()の引数順序を変更しました。
/*static*/ int LOT_seek_and_call(const unsigned short* table, int param, const int* pid, int (*fn)(const unsigned short* column, int column_size, int param));
asm("
		.code
		.align		1
LOT_seek_and_call:
		;//%r12 := table
		;//%r13 := param
		;//%r14 := pid
		;//%r15 := fn
		ld.uh		%r4, [%r12]+					;//%r4  := table_size = *table++
		ld.uh		%r5, [%r12]+					;//%r5  := id_size    = *table++
		sla		%r5, 2						;//%r5  := id_size * sizeof(int)
LOT_seek_and_call_L1:								;//for(;;) {
		;//%r4  := table_size
		;//%r5  := id_size * sizeof(int)
		;//%r12 := table
		;//%r13 := param
		;//%r14 := pid
		;//%r15 := fn
		sub		%r4, 1						;//%r4  := table_size--
		jrlt		LOT_seek_and_call_DIE				;//if(table_size < 0) { DIE() }
		ld.w		%r6, %r5					;//%r6  := n_id = id_size * sizeof(int)
		ld.w		%r7, 0						;//%r7  := diff = 0
LOT_seek_and_call_L2:								;//for(;;) {
		;//%r4  := table_size
		;//%r5  := id_size * sizeof(int)
		;//%r6  := n_id
		;//%r7  := diff
		;//%r12 := table
		;//%r13 := param
		;//%r14 := pid
		;//%r15 := fn
		sub		%r6, 4						;//%r6  := n_id -= sizeof(int)
		jrlt		LOT_seek_and_call_L3				;//if(n_id < 0) { break }
		ld.uh		%r10, [%r12]+					;//%r10 :=          id1       = *table++
		ld.w		%r11, [%r14]+					;//%r11 :=                id2 = *pid++
		sub		%r10, %r11					;//%r10 :=         (id1 - id2)
		jp.d		LOT_seek_and_call_L2				;//}
		or		%r7, %r10					;//%r7  := diff |= (id1 - id2)					*delay*
LOT_seek_and_call_L3:
		;//%r4  := table_size
		;//%r5  := id_size * sizeof(int)
		;//%r7  := diff
		;//%r12 := table
		;//%r13 := param
		;//%r14 := pid
		;//%r15 := fn
		ld.uh		%r6, [%r12]+					;//%r6  := column_size = *table++
		cmp		%r7, 0						;//if(!diff) { break }
		jreq		LOT_seek_and_call_L4
		sub		%r14, %r5					;//%r14 := pid -=   (    id_size *     sizeof(int)           )
		sla		%r6, 2						;//%r6  :=          (column_size * 2 * sizeof(unsigned short))
		jp.d		LOT_seek_and_call_L1				;//}
		add		%r12, %r6					;//%r12 := table += (column_size * 2 * sizeof(unsigned short))	*delay*
LOT_seek_and_call_L4:
		;//%r6  := column_size
		;//%r12 := table
		;//%r13 := param
		;//%r14 := pid
		;//%r15 := fn
		ld.w		%r4, [%r14]					;//%r4  := id2 = *pid
		ld.w		%r14, %r13					;//%r14 :=                          param			*anti-interlock*
		cmp		%r4, -1						;//if(id2 != -1) { DIE() }
		jrne		LOT_seek_and_call_DIE				;//
		ld.w		%r13, %r6					;//%r13 :=             column_size
		jp		%r15						;//return (*fn)(table, column_size, param)			(jp.d %rbは不可)
");
static void __attribute__((noreturn,unused/*asmブロックから参照*/)) LOT_seek_and_call_DIE() { DIE(); }
//}}2015/10/12変更:LOT_seek_and_call()の引数順序を変更しました。
#endif/*PIECE*/

/*--------------------------------------------------------------------------*/

#ifndef PIECE
//{{2015/10/12変更:LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更し、LOT_draw_table_l()と統一しました。
//int LOT_draw_table_l(const unsigned short* table, int rndval, ...) {
//	int retval;
//	va_list ap;
//	va_start(ap, rndval);
//	retval = LOT_draw_table_a(table, ap, rndval);
//	va_end(ap);
//	return retval;
//}
//int LOT_draw_table_a(const unsigned short* table, va_list ap, int rndval) {
//	int id[(7+1)/*調整可*/], i = 0;			//実用上、抽選列のid行数が7以下(終端含め8以下)と考えて充分だろう。不足した場合は増やせ。
//	for(;;) {
//		if((id[i] = va_arg(ap, int)) == -1) { break; }
//		if(++i >= ARRAY_SIZE(id)) { DIE(); }	//ここで停止した場合は、id[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
//	}
//	return LOT_draw_table_v(table, id, rndval);
//}
//int LOT_draw_table_v(const unsigned short* table, const int* pid, int rndval) {
//	return LOT_seek_and_call(table, pid, rndval, LOT_draw_column);
//}
//↓2015/10/12変更:LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更し、LOT_draw_table_l()と統一しました。
int LOT_draw_table_l(const unsigned short* table, int rndval, ...) {
	int retval;
	va_list ap;
	va_start(ap, rndval);
	retval = LOT_draw_table_a(table, rndval, ap);
	va_end(ap);
	return retval;
}
int LOT_draw_table_a(const unsigned short* table, int rndval, va_list ap) {
	int id[(7+1)/*調整可*/], i = 0;			//実用上、抽選列のid行数が7以下(終端含め8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((id[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(id)) { DIE(); }	//ここで停止した場合は、id[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return LOT_draw_table_v(table, rndval, id);
}
int LOT_draw_table_v(const unsigned short* table, int rndval, const int* pid) {
	return LOT_seek_and_call(table, rndval, pid, LOT_draw_column);
}
//}}2015/10/12変更:LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更し、LOT_draw_table_l()と統一しました。
#else /*PIECE*/
//{{2015/10/12変更:LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更し、LOT_draw_table_l()と統一しました。
//int LOT_draw_table_l(const unsigned short* table, int rndval, ...);
//int LOT_draw_table_a(const unsigned short* table, va_list ap, int rndval);
//int LOT_draw_table_v(const unsigned short* table, const int* pid, int rndval);
//asm("
//		.code
//		.align		1
//		.global		LOT_draw_table_l
//		.global		LOT_draw_table_a
//		.global		LOT_draw_table_v
//LOT_draw_table_l:
//		;//%r12    := table
//		;//[%sp+0] := retp
//		;//[%sp+4] := rndval
//		;//[%sp+8] := ...
//		xadd		%r13, %sp, 8					;//%r13 := ap = &...
//		xld.w		%r14, [%sp+4]					;//%r14 := rndval
//LOT_draw_table_a:		;//┐アセンブラプログラムでは、
//LOT_draw_table_v:		;//┘この二つの関数は同じです。
//		;//%r12    := table
//		;//%r13    := pid = ap
//		;//%r14    := rndval
//		xld.w		%r15, LOT_draw_column				;//%r15 := LOT_draw_column
//		xjp		LOT_seek_and_call				;//return LOT_seek_and_call(table, pid, rndval, LOT_draw_column)
//");
//↓2015/10/12変更:LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更し、LOT_draw_table_l()と統一しました。
int LOT_draw_table_l(const unsigned short* table, int rndval, ...);
int LOT_draw_table_a(const unsigned short* table, int rndval, va_list ap);
int LOT_draw_table_v(const unsigned short* table, int rndval, const int* pid);
asm("
		.code
		.align		1
		.global		LOT_draw_table_l
		.global		LOT_draw_table_a
		.global		LOT_draw_table_v
LOT_draw_table_l:
		;//%r12    := table
		;//[%sp+0] := retp
		;//[%sp+4] := rndval
		;//[%sp+8] := ...
		xld.w		%r13, [%sp+4]					;//%r13 := rndval
		xadd		%r14, %sp, 8					;//%r14 := ap = &...
LOT_draw_table_a:		;//┐アセンブラプログラムでは、
LOT_draw_table_v:		;//┘この二つの関数は同じです。
		;//%r12    := table
		;//%r13    := rndval
		;//%r14    := pid
		xld.w		%r15, LOT_draw_column				;//%r15 :=                                      LOT_draw_column
		xjp		LOT_seek_and_call				;//return LOT_seek_and_call(table, rndval, pid, LOT_draw_column)
");
//}}2015/10/12変更:LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更し、LOT_draw_table_l()と統一しました。
#endif/*PIECE*/

//{{2015/11/06追加:'_equally'版の関数を追加しました。
#ifdef  USE_LOT_EQUALLY
#ifndef PIECE
int LOT_draw_table_equally_l(const unsigned short* table, int rndval, ...) {
	int retval;
	va_list ap;
	va_start(ap, rndval);
	retval = LOT_draw_table_equally_a(table, rndval, ap);
	va_end(ap);
	return retval;
}
int LOT_draw_table_equally_a(const unsigned short* table, int rndval, va_list ap) {
	int id[(7+1)/*調整可*/], i = 0;			//実用上、抽選列のid行数が7以下(終端含め8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((id[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(id)) { DIE(); }	//ここで停止した場合は、id[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return LOT_draw_table_equally_v(table, rndval, id);
}
int LOT_draw_table_equally_v(const unsigned short* table, int rndval, const int* pid) {
	return LOT_seek_and_call(table, rndval, pid, LOT_draw_column_equally);
}
#else //PIECE
int LOT_draw_table_equally_l(const unsigned short* table, int rndval, ...);
int LOT_draw_table_equally_a(const unsigned short* table, int rndval, va_list ap);
int LOT_draw_table_equally_v(const unsigned short* table, int rndval, const int* pid);
asm("
		.code
		.align		1
		.global		LOT_draw_table_equally_l
		.global		LOT_draw_table_equally_a
		.global		LOT_draw_table_equally_v
LOT_draw_table_equally_l:
		;//%r12    := table
		;//[%sp+0] := retp
		;//[%sp+4] := rndval
		;//[%sp+8] := ...
		xld.w		%r13, [%sp+4]					;//%r13 := rndval
		xadd		%r14, %sp, 8					;//%r14 := ap = &...
LOT_draw_table_equally_a:	;//┐アセンブラプログラムでは、
LOT_draw_table_equally_v:	;//┘この二つの関数は同じです。
		;//%r12    := table
		;//%r13    := rndval
		;//%r14    := pid
		xld.w		%r15, LOT_draw_column_equally			;//%r15 :=                                      LOT_draw_column_equally
		xjp		LOT_seek_and_call				;//return LOT_seek_and_call(table, rndval, pid, LOT_draw_column_equally)
");
#endif//PIECE
#endif//USE_LOT_EQUALLY
//}}2015/11/06追加:'_equally'版の関数を追加しました。

/*--------------------------------------------------------------------------*/

#ifndef PIECE
//{{2015/10/12変更:LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更し、LOT_draw_table_l()と統一しました。
//int LOT_get_table_weight_l(const unsigned short* table, int hitval_sel, ...) {
//	int retval;
//	va_list ap;
//	va_start(ap, hitval_sel);
//	retval = LOT_get_table_weight_a(table, ap, hitval_sel);
//	va_end(ap);
//	return retval;
//}
//int LOT_get_table_weight_a(const unsigned short* table, va_list ap, int hitval_sel) {
//	int id[(7+1)/*調整可*/], i = 0;			//実用上、抽選列のid行数が7以下(終端含め8以下)と考えて充分だろう。不足した場合は増やせ。
//	for(;;) {
//		if((id[i] = va_arg(ap, int)) == -1) { break; }
//		if(++i >= ARRAY_SIZE(id)) { DIE(); }	//ここで停止した場合は、id[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
//	}
//	return LOT_get_table_weight_v(table, id, hitval_sel);
//}
//int LOT_get_table_weight_v(const unsigned short* table, const int* pid, int hitval_sel) {
//	return LOT_seek_and_call(table, pid, hitval_sel, LOT_get_column_weight);
//}
//↓2015/10/12変更:LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更し、LOT_draw_table_l()と統一しました。
int LOT_get_table_weight_l(const unsigned short* table, int hitval_sel, ...) {
	int retval;
	va_list ap;
	va_start(ap, hitval_sel);
	retval = LOT_get_table_weight_a(table, hitval_sel, ap);
	va_end(ap);
	return retval;
}
int LOT_get_table_weight_a(const unsigned short* table, int hitval_sel, va_list ap) {
	int id[(7+1)/*調整可*/], i = 0;			//実用上、抽選列のid行数が7以下(終端含め8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((id[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(id)) { DIE(); }	//ここで停止した場合は、id[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return LOT_get_table_weight_v(table, hitval_sel, id);
}
int LOT_get_table_weight_v(const unsigned short* table, int hitval_sel, const int* pid) {
	return LOT_seek_and_call(table, hitval_sel, pid, LOT_get_column_weight);
}
//}}2015/10/12変更:LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更し、LOT_draw_table_l()と統一しました。
#else /*PIECE*/
//{{2015/10/12変更:LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更し、LOT_draw_table_l()と統一しました。
//int LOT_get_table_weight_l(const unsigned short* table, int hitval_sel, ...);
//int LOT_get_table_weight_a(const unsigned short* table, va_list ap, int hitval_sel);
//int LOT_get_table_weight_v(const unsigned short* table, const int* pid, int hitval_sel);
//asm("
//		.code
//		.align		1
//		.global		LOT_get_table_weight_l
//		.global		LOT_get_table_weight_a
//		.global		LOT_get_table_weight_v
//LOT_get_table_weight_l:
//		;//%r12    := table
//		;//[%sp+0] := retp
//		;//[%sp+4] := hitval_sel
//		;//[%sp+8] := ...
//		xadd		%r13, %sp, 8					;//%r13 := ap = &...
//		xld.w		%r14, [%sp+4]					;//%r14 := hitval_sel
//LOT_get_table_weight_a:		;//┐アセンブラプログラムでは、
//LOT_get_table_weight_v:		;//┘この二つの関数は同じです。
//		;//%r12    := table
//		;//%r13    := pid = ap
//		;//%r14    := hitval_sel
//		xld.w		%r15, LOT_get_column_weight			;//%r15 := LOT_get_column_weight
//		xjp		LOT_seek_and_call				;//return LOT_seek_and_call(table, pid, hitval_sel, LOT_get_column_weight)
//");
//↓2015/10/12変更:LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更し、LOT_draw_table_l()と統一しました。
int LOT_get_table_weight_l(const unsigned short* table, int hitval_sel, ...);
int LOT_get_table_weight_a(const unsigned short* table, int hitval_sel, va_list ap);
int LOT_get_table_weight_v(const unsigned short* table, int hitval_sel, const int* pid);
asm("
		.code
		.align		1
		.global		LOT_get_table_weight_l
		.global		LOT_get_table_weight_a
		.global		LOT_get_table_weight_v
LOT_get_table_weight_l:
		;//%r12    := table
		;//[%sp+0] := retp
		;//[%sp+4] := hitval_sel
		;//[%sp+8] := ...
		xld.w		%r13, [%sp+4]					;//%r13 := hitval_sel
		xadd		%r14, %sp, 8					;//%r14 := ap = &...
LOT_get_table_weight_a:		;//┐アセンブラプログラムでは、
LOT_get_table_weight_v:		;//┘この二つの関数は同じです。
		;//%r12    := table
		;//%r13    := hitval_sel
		;//%r14    := pid
		xld.w		%r15, LOT_get_column_weight			;//%r15 :=                                          LOT_get_column_weight
		xjp		LOT_seek_and_call				;//return LOT_seek_and_call(table, hitval_sel, pid, LOT_get_column_weight)
");
//}}2015/10/12変更:LOT_draw_table_v(),LOT_draw_table_a()の引数順序を変更し、LOT_draw_table_l()と統一しました。
#endif/*PIECE*/

/*--------------------------------------------------------------------------*/

#ifndef PIECE
void LOT_get_table_column_id(const unsigned short* table, int i_column, int* pid) {
	int table_size, id_size, column_size;
	/* 抽選表の列数を取得します。 */
	table_size = *table++;
	/* 抽選列のid行数を取得します。 */
	id_size    = *table++;
	/* 抽選表の列数が、抽選列の順番(0〜)以下である場合は、エラー停止します。 */
	if(table_size <= i_column) { DIE(); }
	/* (i_column)番目の抽選列の、idの組合せのポインタを取得します。 */
	while(--i_column >= 0) {
		table += id_size;
		column_size = *table++;
		table += column_size * 2/*{hitval,weight}*/;
	}
	/* idの組合せを格納します。 */
	while(--id_size >= 0) { *pid++ = *table++; }
	*pid++ = -1/*終端*/;
}
#else /*PIECE*/
void LOT_get_table_column_id(const unsigned short* table, int i_column, int* pid);
asm("
		.code
		.align		1
		.global		LOT_get_table_column_id
LOT_get_table_column_id:
		;//%r12 := table
		;//%r13 := i_column
		;//%r14 := pid
		ld.uh		%r4, [%r12]+					;//%r4  := table_size = *table++
		ld.uh		%r5, [%r12]+					;//%r5  := id_size    = *table++
		cmp		%r4, %r13					;//if(table_size <= i_column) { DIE() }
		jrle		LOT_get_table_column_id_DIE
		sla		%r5, 1						;//%r5  := id_size * sizeof(unsigned short)
LOT_get_table_column_id_L1:							;//for(;;) {
		;//%r5  := id_size * sizeof(unsigned short)
		;//%r12 := table
		;//%r13 := i_column
		;//%r14 := pid
		sub		%r13, 1						;//%r13 := i_column--
		jrlt		LOT_get_table_column_id_L2			;//if(i_column < 0) { break }
		add		%r12, %r5					;//%r12 := table += (    id_size     * sizeof(unsigned short))
		ld.uh		%r6, [%r12]+					;//%r6  :=           column_size = *table++
		sla		%r6, 2						;//%r6  :=          (column_size * 2 * sizeof(unsigned short))
		jp.d		LOT_get_table_column_id_L1			;//}
		add		%r12, %r6					;//%r12 := table += (column_size * 2 * sizeof(unsigned short))	*delay*
LOT_get_table_column_id_L2:							;//for(;;) {
		;//%r5  := id_size * sizeof(unsigned short)
		;//%r12 := table
		;//%r14 := pid
		sub		%r5, 2						;//%r5  := (id_size * sizeof(unsigned short)) -= sizeof(unsigned short)
		jrlt		LOT_get_table_column_id_L3			;//     if((id_size * sizeof(unsigned short)) < 0) { break }
		ld.uh		%r4, [%r12]+					;//%r4  :=  id = *table++
		ld.w		[%r14]+, %r4					;//*pid++ = id
		jp		LOT_get_table_column_id_L2			;//}
LOT_get_table_column_id_L3:
		ld.w		%r4, -1						;//%r4  :=  id = -1
		ld.w		[%r14], %r4					;//*pid   = id
		ret
");
static void __attribute__((noreturn,unused/*asmブロックから参照*/)) LOT_get_table_column_id_DIE() { DIE(); }
#endif/*PIECE*/

/****************************************************************************
 *	抽選列idのシンボル値変換(汎用的なテーブル変換にも利用可能)
 ****************************************************************************/

#ifndef PIECE
int LotSym_ConvTo(const unsigned short (*pTBL)[2], int x) {	//[0]⇒[1]変換
	const unsigned short* p = (const unsigned short*)pTBL;
	for(;;) {
		int xValue = *p++;				//[0]の値を読み出す。
		int yValue = *p++;				//[1]の値を読み出す。
		if(xValue == USHRT_MAX) { DIE(); }		//(pTBL[i][0]=USHRT_MAX)ならば終端。	←どちらの関数も[0]の値で終端を判断することに注意せよ。
		if(xValue == x) { return yValue; }		//[0]の値に一致したら[1]の値を返す。
	}
}
int LotSym_ConvFrom(const unsigned short (*pTBL)[2], int y) {	//[1]⇒[0]変換
	const unsigned short* p = (const unsigned short*)pTBL;
	for(;;) {
		int xValue = *p++;				//[0]の値を読み出す。
		int yValue = *p++;				//[1]の値を読み出す。
		if(xValue == USHRT_MAX) { DIE(); }		//(pTBL[i][0]=USHRT_MAX)ならば終端。	←どちらの関数も[0]の値で終端を判断することに注意せよ。
		if(yValue == y) { return xValue; }		//[1]の値に一致したら[0]の値を返す。
	}
}
#else //PIECE
int LotSym_ConvTo(const unsigned short (*pTBL)[2], int x);
int LotSym_ConvFrom(const unsigned short (*pTBL)[2], int y);
asm("
		.code
		.align		1
		.global		LotSym_ConvTo
		.global		LotSym_ConvFrom
LotSym_ConvTo:
		xld.w		%r4, 0xFFFF			;//%r4  := USHRT_MAX
LotSym_ConvTo_LOOP:						;//for(;;) {
		ld.uh		%r5, [%r12]+			;//  %r5  := xValue = *p++
		ld.uh		%r10, [%r12]+			;//  %r10 := yValue = *p++
		cmp		%r5, %r4			;//  if(xValue == USHRT_MAX) { DIE() }
		jreq		LotSym_ConvTo_ConvFrom_DIE	;//
		cmp		%r5, %r13			;//  if(xValue == x) { break }
		jrne		LotSym_ConvTo_LOOP		;//}
		ret						;//return yValue
LotSym_ConvFrom:
		xld.w		%r4, 0xFFFF			;//%r4  := USHRT_MAX
LotSym_ConvFrom_LOOP:						;//for(;;) {
		ld.uh		%r10, [%r12]+			;//  %r10 := xValue = *p++
		ld.uh		%r5, [%r12]+			;//  %r5  := yValue = *p++
		cmp		%r10, %r4			;//  if(xValue == USHRT_MAX) { DIE() }
		jreq		LotSym_ConvTo_ConvFrom_DIE	;//
		cmp		%r5, %r13			;//  if(yValue == y) { break }
		jrne		LotSym_ConvFrom_LOOP		;//}
		ret						;//return xValue
");
static void __attribute__((noreturn,unused))/*asmブロックから参照*/ LotSym_ConvTo_ConvFrom_DIE() { DIE(); }
#endif//PIECE

/****************************************************************************
 *	16ビットで大きな値を表現するための、指数表現
 ****************************************************************************/
#ifndef PIECE
int Exp10_Decode(int _x) {
	unsigned x = _x, e;
	if(x > UINT16_MAX) { DIE(); }	//呼び出し側のバグ
	//指数を求める。
	e = x % 6;			//0〜5
	//仮数を求める。
	x = x / 6;			//0〜10922
	//(仮数×10^指数)を求める。
	while(e--) { x *= 10; }		//0〜1092100000(=0x41181FA0)
	return x;
}
int Exp10_Encode(int _x) {
	unsigned x = _x, e = 0;
	//指数を求める。
	while(x && !(x % 10) && (e < 5)) {
		x /= 10;
		e++;
	}
	//(仮数×6＋指数)を求める。
	if(x > UINT16_MAX) { return -1; }	//エンコード値が16ビットを超えるならば、エンコード出来ない事を示す-1を返す。	「(x*6)+e」がオーバーフローする可能性が有るので、「(x*6)+e」の前でも調べる必要が有る事に注意せよ。
	x = (x * 6) + e;
	if(x > UINT16_MAX) { return -1; }	//エンコード値が16ビットを超えるならば、エンコード出来ない事を示す-1を返す。
	return x;
}
#else //PIECE
int Exp10_Decode(int _x);
int Exp10_Encode(int _x);
asm("
		.code
		.align		1
		.global		Exp10_Decode
		.global		Exp10_Encode
Exp10_Decode:
		xcmp		%r12, 65535			;//if(x > UINT16_MAX) { DIE() }
		jrugt		Exp10_Decode_DIE		;//
		xcall.d		__umodsi3			;//%r10 := e = x % 6					除算ルーチンは%r9,%r10,%alr,%ahr,%psr以外を破壊しません。/clip/ksvec200.s,及び,/clip/keep/08_高速除算ルーチン転送先変更前保存.20150103/clipidiv.sを参照して下さい。
		ld.w		%r13, 6				;//%r13 :=         6			*delay*
		xcall.d		__udivsi3			;//%r10 := x = x / 6					除算ルーチンは%r9,%r10,%alr,%ahr,%psr以外を破壊しません。/clip/ksvec200.s,及び,/clip/keep/08_高速除算ルーチン転送先変更前保存.20150103/clipidiv.sを参照して下さい。
		ld.w		%r4, %r10			;//%r4  := %r10				*delay*
		ld.w		%r5, 10				;//%r5  := 10
Exp10_Decode_L10:						;//for(;;) {
		sub		%r4, 1				;//  %r11 := e--
		jrult		Exp10_Decode_L20		;//  if(e == -1) { break }
		mltu.w		%r10, %r5			;//  %alr := x *= 10
		jp.d		Exp10_Decode_L10		;//}
		ld.w		%r10, %alr			;//  %r10 := x				*delay*
Exp10_Decode_L20:						;//
		ret						;//return    x
		;//---------------------------------------------;//
Exp10_Encode:
		ld.w		%r4, 0				;//%r4  := e = 0
		ld.w		%r13, 10			;//%r13 := 10
Exp10_Encode_L10:						;//for(;;) {
		cmp		%r12, 0				;//  if(!x) { break }
		jreq		Exp10_Encode_L20		;//  
		xcall		__umodsi3			;//  %r10 := x % 10					除算ルーチンは%r9,%r10,%alr,%ahr,%psr以外を破壊しません。/clip/ksvec200.s,及び,/clip/keep/08_高速除算ルーチン転送先変更前保存.20150103/clipidiv.sを参照して下さい。
		cmp		%r10, 0				;//  if(x % 10) { break }
		jrne		Exp10_Encode_L20		;//  
		cmp		%r4, 4				;//  if(e > 4) break }
		jrugt		Exp10_Encode_L20		;//  
		xcall.d		__udivsi3			;//  %r10 := x /= 10					除算ルーチンは%r9,%r10,%alr,%ahr,%psr以外を破壊しません。/clip/ksvec200.s,及び,/clip/keep/08_高速除算ルーチン転送先変更前保存.20150103/clipidiv.sを参照して下さい。
		add		%r4, 1				;//  %r4  := e++			*delay*
		jp.d		Exp10_Encode_L10		;//}
		ld.w		%r12, %r10			;//  %r10 := x				*delay*
Exp10_Encode_L20:						;//
		ld.w		%r10, -1			;//%r10 := -1
		ld.uh		%r5, %r10			;//%r5  := UINT16_MAX
		cmp		%r12, %r5			;//if(x > UINT16_MAX) { return -1 }
		jrugt		Exp10_Encode_RET		;//
		ld.w		%r6, 6				;//%r6  :=      6
		mltu.h		%r12, %r6			;//%alr :=  x * 6					ここへ来た時は、%r12,%r6共に(0〜65535)の範囲内である事が保証出来るので、mltu.hで足ります。mltu.wでも構いませんが、mltu.hの方が高速で、結果は同じになります。
		ld.w		%r12, %alr			;//%r12 :=  x * 6
		add		%r12, %r4			;//%r12 := (x * 6) + e
		cmp		%r12, %r5			;//if(x > UINT16_MAX) { return -1 }
		jrugt		Exp10_Encode_RET		;//
		ld.w		%r10, %r12			;//%r10 := x
Exp10_Encode_RET:						;//
		ret						;//return  x,又は,-1
");
static void __attribute__((noreturn,unused))/*asmブロックから参照*/ Exp10_Decode_DIE() { DIE(); }
#endif//PIECE
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#if 0
//□テストプログラム
void Test() {
	int a, b, c, d, e;
	for(a = 0; a <= UINT16_MAX; a++) {
		b = Exp10_Decode(a);
		c = Exp10_Encode(b);
		d = Exp10_Decode(c);
		e = Exp10_Encode(d);
		printf("%5d %d\n", a, b);
	//	if(a != c) { DIE(); }	//─この検査は行えません。ある整数値を表す指数表現は複数有るので、a:指数表現⇒b:整数値⇒c:指数表現で、cがaと同じになるとは限らないからです。
		if(b != d) { DIE(); }	//┬ただし、Exp10_Decode()とExp10_Encode()を使って変換した場合は一意なので、bとdの比較,及び,cとeの比較は可能です。
		if(c != e) { DIE(); }	//┘
	}
	puts("ok");
}
#endif
