/*	
 *	clipslot.c
 *
 *	スロットゲーム用サブルーチン集
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2016 Naoyuki Sawa
 *
 *	* Sun Jun 02 15:09:44 JST 2013 Naoyuki Sawa
 *	- 1stリリース。
 *	* Sun Aug 18 17:39:58 JST 2013 Naoyuki Sawa
 *	- 役比管理を追加しました。
 *	* Sat Mar 29 15:51:51 JST 2014 Naoyuki Sawa
 *	- テンパイ判定を追加しました。
 *	* Tue Apr 01 00:42:49 JST 2014 Naoyuki Sawa
 *	- 入賞判定を追加しました。
 *	- リール配列を追加しました。
 *	* Tue Apr 08 00:24:56 JST 2014 Naoyuki Sawa
 *	- ラインを追加しました。
 *	- 押順を追加しました。
 *	* Sat May 03 23:21:41 JST 2014 Naoyuki Sawa
 *	- 停止制御を追加しました。
 *	* Mon May 05 15:01:01 JST 2014 Naoyuki Sawa
 *	- 停止制御データビルダを追加しました。
 *	  PC上でツールを作成する時に使用します。P/ECE上では使用しません。
 *	* Mon May 12 12:39:59 JST 2014 Naoyuki Sawa
 *	- スペックデータ作成・出力を追加しました。
 *	  PC上でスペックデータを作成する時に使用します。P/ECE上では使用しません。
 *	* Sat May 31 13:04:14 JST 2014 Naoyuki Sawa
 *	- Slot_PrintStpCtl()が、ST_Slot_StpCtl構造体も出力するように変更しました。
 *	  これまでは、Slot_PrintStpCtl()は個々のテーブルを出力して、アプリケーション側でST_Slot_StpCtl構造体を定義していました。
 *	  今後は、Slot_PrintStpCtl()がST_Slot_StpCtl構造体にまとめて出力するので、アプリケーション側で定義する必要はありません。
 *	* Wed Jun 18 20:20:39 JST 2014 Naoyuki Sawa
 *	- Slot_GetLineRow(),Slot_CheckTenpai(),Slot_CheckPrize()を、5ライン用⇒7ライン用に拡張しました。
 *	  機種によって不要なラインは、アプリケーション側でマスクして使用してください。
 *	* Tue Jun 24 21:30:13 JST 2014 Naoyuki Sawa
 *	- Slot_MakeSpec()をclipsl5n.h,clipsl5n.cへ分離しました。
 *	  当モジュール(clipslot.h,clipslot.c)には、ライン数やタイプにかかわらず共通のサブルーチンのみを残しました。
 *	* Tue Dec 16 21:51:08 JST 2014 Naoyuki Sawa
 *	- 順序番号付き8byte形式コマンドを追加しました。
 *	* Wed Dec 17 21:50:28 JST 2014 Naoyuki Sawa
 *	- シンボル'SlotPos_Max'で、リール駒数を設定できるようにしました。
 *	  設定可能範囲は、「SlotPos_Max=20」(リール駒数=21駒),又は,「SlotPos_Max=19」(リール駒数=20駒)です。
 *	  上記の範囲外は、引込駒数も変える必要が有るので、設定不可です。(引込駒数は4駒決め打ちでハードコーディングしているため。)
 *	- シンボル'SlotPos_Max'を変更した場合は、当モジュールのリビルドが必要です。
 *	  当モジュールをリビルドせずに、アプリケーション側の設定のみで変更することはできません。
 *	- 「SlotPos_Max=19」時の動作は未確認です。(これまでは「SlotPos_Max=20」決め打ちで作成してきたため。)				←┬2014/12/17時点での※TODOです。
 *	  引き続き「SlotPos_Max=19」時の動作確認と、必要に応じて処理の修正を行う必要が有ります。					←┘終了したらこの二行を削除せよ。
 *	* Sun Jul 24 21:18:15 JST 2016 Naoyuki Sawa
 *	- Slot_BuildStpCtl()にて、TinyLZ_compress()の結果が256以上になった時に、正しくはエラー停止すべき所、そのまま(unsigned char)配列に格納してしまい、間違ったデータが生成されていたバグを修正しました。
 *	  修正方法としては、格納する前に(n<256)を検査しても良かったのですが、もし今後(unsigned char)配列を(unsigned short)配列に変更する場合に備えて、格納後に元の値と同じかを比較して検査する事にしました。
 *	* Thu Sep 29 21:37:05 JST 2016 Naoyuki Sawa
 *	- Hewでは停止制御を含めないようにしました。
 */
#include "clip.h"

/****************************************************************************
 *	出率管理
 ****************************************************************************/

void SlotDeritu_Init(ST_SlotDeritu* Me) {
	/* 全てのフィールドを0クリアする。 */
	memset(Me, 0, sizeof(ST_SlotDeritu));
}

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

void SlotDeritu_Update(ST_SlotDeritu* Me, int In, int Out) {
	/* 短期,中期,長期のゲーム数定義 */
	static const unsigned short TermLength[3/*0=短,1=中,2=長*/] = { 400, 6000, 17500 };
	int iTerm, iLog;
	/* 投入枚数が0〜3、払出枚数が0〜15の範囲であることを確認する。 */
	if(((unsigned)In > 3) || ((unsigned)Out > 15)) { DIE(); }
	/* 短期,中期,長期について･･･ */
	for(iTerm = 0; iTerm < 3/*0=短,1=中,2=長*/; iTerm++) {
		/* Nゲーム前の投入(払出)枚数が格納されている、レコードインデクス(0〜17499)を求める。 */
		iLog = (unsigned)(Me->GameCount - TermLength[iTerm] + 17500) % (unsigned)17500;
		/* 総投入(払出)枚数に、今回の投入(払出)枚数を足し、Nゲーム前の投入(払出)枚数を引く。
		 * - Nゲーム前の投入(払出)枚数が未格納ならば、レコード値は0なので、同じ処理で構わない。
		 */
		Me->TotalIn[ iTerm] += (In  - ((Me->InLog[ iLog>>2] >> ((iLog&3)<<1)) &  3));
		Me->TotalOut[iTerm] += (Out - ((Me->OutLog[iLog>>1] >> ((iLog&1)<<2)) & 15));
		/*                           └──── Nゲーム前の投入(払出)枚数 ────┘ */
		/* Nゲーム以上経過している場合のみ、Nゲーム間の出率を算出可能である。
		 * - ここではまだ経過ゲーム数を進めていないので、(Nゲーム-1)と比較することに注意せよ。
		 */
		if((unsigned)Me->GameCount >= (unsigned)(TermLength[iTerm] - 1/*上記コメント参照*/)) {
			/* 出率[%]＝総払出枚数[枚]÷総投入枚数[枚]×100 である。
			 * - ただし、Nゲーム間の総投入枚数が0の場合のみ、出率＝総払出枚数×100 とする。
			 *   Nゲーム間、全て再遊技が当選した場合に、総投入枚数が0となることがあり得る。
			 */
			Me->Deritu[iTerm] = (double)Me->TotalOut[iTerm] * 100.0;
			if(Me->TotalIn[iTerm] != 0) { Me->Deritu[iTerm] /= Me->TotalIn[iTerm]; }
		} else {
			/* Nゲーム以上経過するまでは、Nゲーム間の出率を、初期値(0.0)のまま維持する。 */
		}
	}
	/* 今回の投入(払出)枚数を格納する、レコードインデクス(0〜17499)を求める。 */
	iLog = Me->GameCount % 17500;
	/* 投入(払出)枚数ログに、今回の投入(払出)枚数を格納する。 */
	Me->InLog[ iLog>>2] = (Me->InLog[ iLog>>2] & ~( 3 << ((iLog&3)<<1))) | (In  << ((iLog&3)<<1));
	Me->OutLog[iLog>>1] = (Me->OutLog[iLog>>1] & ~(15 << ((iLog&1)<<2))) | (Out << ((iLog&1)<<2));
	/* 経過ゲーム数を進める。オーバーフローしたら、エラー停止とする。 */
	if(++Me->GameCount == 0) { DIE(); }
}

/****************************************************************************
 *	役比管理
 ****************************************************************************/

void SlotYakuhi_Init(ST_SlotYakuhi* Me) {
	/* 全てのフィールドを0クリアする。 */
	memset(Me, 0, sizeof(ST_SlotYakuhi));
}

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

void SlotYakuhi_Update(ST_SlotYakuhi* Me, int Yak, int Out) {
	int iLog, YakLog, OutLog;
	/* 役物作動中フラグを、0,又は1の値に変換する。 */
	if(Yak) { Yak = 1; }
	/* 払出枚数が0〜15の範囲であることを確認する。 */
	if((unsigned)Out > 15) { DIE(); }
	/* 全払出枚数に、今回の払出枚数を足す。 */
	Me->AllOut += Out;
	/* 今回役物作動中ならば、役物作動中払出枚数にも、今回の払出枚数を足す。 */
	if(Yak) { Me->YakOut += Out; }
	/* 6000ゲーム前の役物作動中フラグ,及び,払出枚数が格納されている、レコードインデクス(0〜5999)を求める。 */
	iLog = Me->GameCount % 6000;
	/* 6000ゲーム前の役物作動中フラグ,及び,払出枚数を取得する。 */
	YakLog = (Me->YakLog[iLog>>3] >> ((iLog&7)   )) &  1;
	OutLog = (Me->OutLog[iLog>>1] >> ((iLog&1)<<2)) & 15;
	/* ログに、今回の役物作動中フラグ,及び,払出枚数を格納する。 */
	Me->YakLog[iLog>>3] = (Me->YakLog[iLog>>3] & ~( 1 << ((iLog&7)   ))) | (Yak << ((iLog&7)   ));
	Me->OutLog[iLog>>1] = (Me->OutLog[iLog>>1] & ~(15 << ((iLog&1)<<2))) | (Out << ((iLog&1)<<2));
	/* 全払出枚数から、6000ゲーム前の払出枚数を引く。 */
	Me->AllOut -= OutLog;
	/* 6000ゲーム前が役物作動中ならば、役物作動中払出枚数からも、6000ゲーム前の払出枚数を引く。 */
	if(YakLog) { Me->YakOut -= OutLog; }
	/* 経過ゲーム数を進める。オーバーフローしたら、エラー停止とする。 */
	if(++Me->GameCount == 0) { DIE(); }
	/* 6000ゲーム以上経過している場合のみ、6000ゲーム間の役比を算出可能である。 */
	if(Me->GameCount >= 6000) {
		/* 役比[%]＝役物作動中払出枚数[枚]÷全払出枚数[枚]×100 である。
		 * - ただし、6000ゲーム間の全払出枚数が0の場合のみ、役比＝役物作動中払出枚数×100 とする。
		 *   6000ゲーム間、全てはずれ,又は,再遊技が当選した場合に、全払出枚数が0となることがあり得る。
		 */
		Me->Yakuhi = (double)Me->YakOut * 100.0;
		if(Me->AllOut != 0) { Me->Yakuhi /= Me->AllOut; }
	} else {
		/* 6000ゲーム以上経過するまでは、6000ゲーム間の役比を、初期値(0.0)のまま維持する。 */
	}
}

/****************************************************************************
 *	押順
 ****************************************************************************/

#ifndef PIECE
int Slot_GetOrderReel(int iOrder, int iStop) {
	if(((unsigned)iOrder > 5) || ((unsigned)iStop > 2)) { DIE(); }
	if((iOrder -= 3) < 0) { iOrder += iStop; }	/* LCR,CRL,RLC */	//(-3〜1)┐
	                 else { iOrder -= iStop; }	/* LRC,CLR,RCL */	//(-2〜2)┴(-3〜2)
	if(iOrder < 0) { iOrder += 3; }						//         ( 0〜2)
	return iOrder;
}
#else //PIECE
int Slot_GetOrderReel(int iOrder, int iStop);
asm("
		.code
		.align		1
		.global		Slot_GetOrderReel
Slot_GetOrderReel:
		cmp		%r12, 5			;// if((unsigned)iOrder > 5) { DIE }
		jrugt		Slot_GetOrderReel_DIE
		cmp		%r13, 2			;// if((unsigned)iStop  > 2) { DIE }
		jrugt		Slot_GetOrderReel_DIE
		sub		%r12, 3			;// %r12 :=   iOrder -= 3
		jrlt.d		4			;// if(iOrder) < 0) {
		add		%r12, %r13		;// %r12 :=   iOrder += iStop } else {	*delay*		%psr(N)=?,%psr(V)=0	────┐この加算でオーバーフローは発生しないので、常に%psr(V)=0となる。
		 sub		%r12, %r13		;//   %r12 := iOrder									│
		 sub		%r12, %r13		;//   %r12 := iOrder -= iStop }				%psr(N)=?,%psr(V)=0	────┤この減算でオーバーフローは発生しないので、常に%psr(V)=0となる。
		jrge		2			;// if(iOrder < 0) {					←───────────────┘jrgeの分岐条件は(N=V)。%psr(V)=0なので、%psr(N)のみで判断する。
		 add		%r12, 3			;//   %r12 := iOrder += 3 }
		ret.d					;// return    iOrder
		ld.w		%r10, %r12		;// %r10   := iOrder			*delay*
");
static void __attribute__((noreturn,unused)) Slot_GetOrderReel_DIE() { DIE(); }
#endif//PIECE

//□テストスイート
//void TestSuite() {
//  if((Slot_GetOrderReel(Slot_Order_LCR,0)!=0)||(Slot_GetOrderReel(Slot_Order_LCR,1)!=1)||(Slot_GetOrderReel(Slot_Order_LCR,2)!=2)){DIE();}
//  if((Slot_GetOrderReel(Slot_Order_CRL,0)!=1)||(Slot_GetOrderReel(Slot_Order_CRL,1)!=2)||(Slot_GetOrderReel(Slot_Order_CRL,2)!=0)){DIE();}
//  if((Slot_GetOrderReel(Slot_Order_RLC,0)!=2)||(Slot_GetOrderReel(Slot_Order_RLC,1)!=0)||(Slot_GetOrderReel(Slot_Order_RLC,2)!=1)){DIE();}
//  if((Slot_GetOrderReel(Slot_Order_LRC,0)!=0)||(Slot_GetOrderReel(Slot_Order_LRC,1)!=2)||(Slot_GetOrderReel(Slot_Order_LRC,2)!=1)){DIE();}
//  if((Slot_GetOrderReel(Slot_Order_CLR,0)!=1)||(Slot_GetOrderReel(Slot_Order_CLR,1)!=0)||(Slot_GetOrderReel(Slot_Order_CLR,2)!=2)){DIE();}
//  if((Slot_GetOrderReel(Slot_Order_RCL,0)!=2)||(Slot_GetOrderReel(Slot_Order_RCL,1)!=1)||(Slot_GetOrderReel(Slot_Order_RCL,2)!=0)){DIE();}
//}

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

#ifndef PIECE
int Slot_FindOrder(int iReel1, int iReel2) {
	if(((unsigned)iReel1 > 2) || ((unsigned)iReel2 > 2) || (iReel1 == iReel2)) { DIE(); }
	if((iReel2 -= iReel1) < 0) { iReel2 += 3; }	//iReel2=1,2
	if(iReel2 != 1) { iReel1 += 3; }		//iReel1=0~5
	return iReel1;
}
#else //PIECE
int Slot_FindOrder(int iReel1, int iReel2);
asm("
		.code
		.align		1
		.global		Slot_FindOrder
Slot_FindOrder:
		cmp		%r12, 2			;// if((unsigned)iReel1 > 2) { DIE }
		jrugt		Slot_FindOrder_DIE
		cmp		%r13, 2			;// if((unsigned)iReel2 > 2) { DIE }
		jrugt		Slot_FindOrder_DIE
		sub		%r13, %r12		;// %r13 := iReel2 -= iReel1
		jrgt		3			;// if(  iReel2 <= 0) {
		 jreq		Slot_FindOrder_DIE	;//   if(iReel2 == 0) { DIE }
		 add		%r13, 3			;//   %r13 := iReel2 += 3 }
		cmp		%r13, 1			;// if(iReel2 != 1) {
		jreq		2
		 add		%r12, 3			;//   %r12 := iReel1 += 3 }
		ret.d					;// return  iReel1
		ld.w		%r10, %r12		;// %r10 := iReel1		*delay*
");
static void __attribute__((noreturn,unused)) Slot_FindOrder_DIE() { DIE(); }
#endif//PIECE

//□テストスイート
//void TestSuite() {
//  if(Slot_FindOrder(0,1)!=Slot_Order_LCR){DIE();}
//  if(Slot_FindOrder(1,2)!=Slot_Order_CRL){DIE();}
//  if(Slot_FindOrder(2,0)!=Slot_Order_RLC){DIE();}
//  if(Slot_FindOrder(0,2)!=Slot_Order_LRC){DIE();}
//  if(Slot_FindOrder(1,0)!=Slot_Order_CLR){DIE();}
//  if(Slot_FindOrder(2,1)!=Slot_Order_RCL){DIE();}
//}

/****************************************************************************
 *	ライン
 ****************************************************************************/

#ifndef PIECE
static const unsigned char TBL_Slot_LineRow[7/*上中下降昇谷山*/] = {
#else //PIECE
static const unsigned char TBL_Slot_LineRow[7/*上中下降昇谷山*/] __attribute__((unused))/*asmブロックから参照*/ = {
#endif//PIECE
	(0/*上*/<<0)|(0/*上*/<<2)|(0/*上*/<<4),// 0 上段ライン
	(1/*中*/<<0)|(1/*中*/<<2)|(1/*中*/<<4),// 1 中段ライン
	(2/*下*/<<0)|(2/*下*/<<2)|(2/*下*/<<4),// 2 下段ライン
	(0/*上*/<<0)|(1/*中*/<<2)|(2/*下*/<<4),// 3 降斜ライン
	(2/*下*/<<0)|(1/*中*/<<2)|(0/*上*/<<4),// 4 昇斜ライン
	(0/*上*/<<0)|(1/*中*/<<2)|(0/*上*/<<4),// 5 小谷ライン
	(2/*下*/<<0)|(1/*中*/<<2)|(2/*下*/<<4),// 6 小山ライン
};

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

#ifndef PIECE
int Slot_GetLineRow(int iLine, int iReel) {
	if(((unsigned)iLine > 6) || ((unsigned)iReel > 2)) { DIE(); }
	return (TBL_Slot_LineRow[iLine] >> (iReel * 2)) & 3;
}
#else //PIECE
int Slot_GetLineRow(int iLine, int iReel);
asm("
		.code
		.align		1
		.global		Slot_GetLineRow
Slot_GetLineRow:
		cmp		%r12, 6			;// if(((unsigned)iLine > 6) { DIE }
		jrugt		Slot_GetLineRow_DIE
		cmp		%r13, 2			;// if(((unsigned)iCol  > 2) { DIE }
		jrugt		Slot_GetLineRow_DIE
		ext		TBL_Slot_LineRow@ah	;// %r10 := TBL_Slot_LineRow[iLine]
		ext		TBL_Slot_LineRow@al
		ld.ub		%r10, [%r12]
		add		%r13, %r13		;// %r13 :=                             (iReel * 2)		*anti-interlock*
		srl		%r10, %r13		;// %r10 := (TBL_Slot_LineRow[iLine] >> (iReel * 2))
		ret.d					;// return  (TBL_Slot_LineRow[iLine] >> (iReel * 2)) & 3
		and		%r10, 3			;// %r10 := (TBL_Slot_LineRow[iLine] >> (iReel * 2)) & 3	*delay*
");
static void __attribute__((noreturn,unused)) Slot_GetLineRow_DIE() { DIE(); }
#endif//PIECE

//□テストスイート
//void TestSuite() {
//  if((Slot_GetLineRow(Slot_Line_T,0)!=0)||(Slot_GetLineRow(Slot_Line_T,1)!=0)||(Slot_GetLineRow(Slot_Line_T,2)!=0)){DIE();}
//  if((Slot_GetLineRow(Slot_Line_M,0)!=1)||(Slot_GetLineRow(Slot_Line_M,1)!=1)||(Slot_GetLineRow(Slot_Line_M,2)!=1)){DIE();}
//  if((Slot_GetLineRow(Slot_Line_B,0)!=2)||(Slot_GetLineRow(Slot_Line_B,1)!=2)||(Slot_GetLineRow(Slot_Line_B,2)!=2)){DIE();}
//  if((Slot_GetLineRow(Slot_Line_F,0)!=0)||(Slot_GetLineRow(Slot_Line_F,1)!=1)||(Slot_GetLineRow(Slot_Line_F,2)!=2)){DIE();}
//  if((Slot_GetLineRow(Slot_Line_Z,0)!=2)||(Slot_GetLineRow(Slot_Line_Z,1)!=1)||(Slot_GetLineRow(Slot_Line_Z,2)!=0)){DIE();}
//  if((Slot_GetLineRow(Slot_Line_V,0)!=0)||(Slot_GetLineRow(Slot_Line_V,1)!=1)||(Slot_GetLineRow(Slot_Line_V,2)!=0)){DIE();}
//  if((Slot_GetLineRow(Slot_Line_A,0)!=2)||(Slot_GetLineRow(Slot_Line_A,1)!=1)||(Slot_GetLineRow(Slot_Line_A,2)!=2)){DIE();}
//}

/****************************************************************************
 *	テンパイ判定
 ****************************************************************************/

#ifndef PIECE
int Slot_CheckTenpai(const unsigned char aStopPict[3/*上中下*/][3/*左中右*/], int iPictLCR) {
	int iTenpaiLineMask = 0;
	int iPictL, iPictC, iPictR, iMask, iRow, iStopPict;
	const unsigned char* pRow;
	/* 同一回胴内に停止と未停止が混在していないことを確認する。(=｢上中下の内一つでも0｣,かつ,｢上中下の内一つでも0以外｣ならばエラー。) */
	if(((aStopPict[0][0]*aStopPict[1][0]*aStopPict[2][0]) == 0) && ((aStopPict[0][0]+aStopPict[1][0]+aStopPict[2][0]) != 0)) { DIE(); }
	if(((aStopPict[0][1]*aStopPict[1][1]*aStopPict[2][1]) == 0) && ((aStopPict[0][1]+aStopPict[1][1]+aStopPict[2][1]) != 0)) { DIE(); }
	if(((aStopPict[0][2]*aStopPict[1][2]*aStopPict[2][2]) == 0) && ((aStopPict[0][2]+aStopPict[1][2]+aStopPict[2][2]) != 0)) { DIE(); }
	/* 絵柄組合せを分解する。 */
	iPictL = (iPictLCR>>0) & 15;
	iPictC = (iPictLCR>>4) & 15;
	iPictR = (iPictLCR>>8) & 15;
	/* 各ラインについて… */
	iMask = (1<<0);				// 0 上段ライン から
	pRow = TBL_Slot_LineRow;
	do {
		iRow = *pRow++;	/* [1:0]=左,[3:2]=中,[5:4]=右 */
		/* 一回胴でも「非Any,かつ,停止済みで、不一致」ならば、このラインでテンパイではない。 */
		if((iPictL != 0)/*非Any*/ && ((iStopPict = aStopPict[(iRow/*>>0*/)  &3  ][0/*左*/]) != 0)/*停止済み*/ && (iPictL != iStopPict)/*不一致*/) { continue; }
		if((iPictC != 0)/*非Any*/ && ((iStopPict = aStopPict[(iRow  >>2  )  &3  ][1/*中*/]) != 0)/*停止済み*/ && (iPictC != iStopPict)/*不一致*/) { continue; }
		if((iPictR != 0)/*非Any*/ && ((iStopPict = aStopPict[(iRow  >>4  )/*&3*/][2/*右*/]) != 0)/*停止済み*/ && (iPictR != iStopPict)/*不一致*/) { continue; }
		/* このラインでテンパイである。テンパイラインのビットマスクに、このラインのビットマスクを追加する。 */
		iTenpaiLineMask |= iMask;
	} while((iMask <<= 1) <= (1<<6));	// 6 小山ライン まで
	/* テンパイラインのビットマスクを返す。 */
	return  iTenpaiLineMask;
}
#else //PIECE
int Slot_CheckTenpai(const unsigned char aStopPict[3/*上中下*/][3/*左中右*/], int iPictLCR);
asm("
		.code
		.align		1
		.global		Slot_CheckTenpai
Slot_CheckTenpai:
		;// %r12 := aStopPict
		;// %r13 := iPictLCR
		ld.ub		%r4,  [%r12]+			;// %r4  := aStopPict[0][0]
		ld.ub		%r5,  [%r12]+			;// %r5  := aStopPict[0][1]
		ld.ub		%r6,  [%r12]+			;// %r6  := aStopPict[0][2]
;//{{容量節約
;//		ld.ub		%r9,  [%r12]+			;// %r9  :=                 aStopPict[1][0]
;//		mltu.h		%r4,  %r9			;// %alr := aStopPict[0][0]*aStopPict[1][0]
;//		ld.w		%r4,  %alr			;// %r4  := aStopPict[0][0]*aStopPict[1][0]
;//		ld.ub		%r9,  [%r12]+			;// %r9  :=                 aStopPict[1][1]
;//		mltu.h		%r5,  %r9			;// %alr := aStopPict[0][1]*aStopPict[1][1]
;//		ld.w		%r5,  %alr			;// %r5  := aStopPict[0][1]*aStopPict[1][1]
;//		ld.ub		%r9,  [%r12]+			;// %r9  :=                 aStopPict[1][2]
;//		mltu.h		%r6,  %r9			;// %alr := aStopPict[0][2]*aStopPict[1][2]
;//		ld.w		%r6,  %alr			;// %r6  := aStopPict[0][2]*aStopPict[1][2]
;//		ld.ub		%r9,  [%r12]+			;// %r9  :=                                 aStopPict[2][0]
;//		mltu.h		%r4,  %r9			;// %alr := aStopPict[0][0]*aStopPict[1][0]*aStopPict[2][0]
;//		ld.w		%r4,  %alr			;// %r4  := aStopPict[0][0]*aStopPict[1][0]*aStopPict[2][0]
;//		ld.ub		%r9,  [%r12]+			;// %r9  :=                                 aStopPict[2][1]
;//		mltu.h		%r5,  %r9			;// %alr := aStopPict[0][1]*aStopPict[1][1]*aStopPict[2][1]
;//		ld.w		%r5,  %alr			;// %r5  := aStopPict[0][1]*aStopPict[1][1]*aStopPict[2][1]
;//		ld.ub		%r9,  [%r12]			;// %r9  :=                                 aStopPict[2][2]
;//		mltu.h		%r6,  %r9			;// %alr := aStopPict[0][2]*aStopPict[1][2]*aStopPict[2][2]
;//		ld.w		%r6,  %alr			;// %r6  := aStopPict[0][2]*aStopPict[1][2]*aStopPict[2][2]
;//↓容量節約
		ld.w		%r7,  2				;// %r7  := i = 2; do {
		 ld.ub		%r9,  [%r12]+			;//   %r9  :=                 aStopPict[1][0]│%r9  :=                                 aStopPict[2][0]
		 mltu.h		%r4,  %r9			;//   %alr := aStopPict[0][0]*aStopPict[1][0]│%alr := aStopPict[0][0]*aStopPict[1][0]*aStopPict[2][0]
		 ld.w		%r4,  %alr			;//   %r4  := aStopPict[0][0]*aStopPict[1][0]│%r4  := aStopPict[0][0]*aStopPict[1][0]*aStopPict[2][0]
		 ld.ub		%r9,  [%r12]+			;//   %r9  :=                 aStopPict[1][1]│%r9  :=                                 aStopPict[2][1]
		 mltu.h		%r5,  %r9			;//   %alr := aStopPict[0][1]*aStopPict[1][1]│%alr := aStopPict[0][1]*aStopPict[1][1]*aStopPict[2][1]
		 ld.w		%r5,  %alr			;//   %r5  := aStopPict[0][1]*aStopPict[1][1]│%r5  := aStopPict[0][1]*aStopPict[1][1]*aStopPict[2][1]
		 ld.ub		%r9,  [%r12]+			;//   %r9  :=                 aStopPict[1][2]│%r9  :=                                 aStopPict[2][2]
		 mltu.h		%r6,  %r9			;//   %alr := aStopPict[0][2]*aStopPict[1][2]│%alr := aStopPict[0][2]*aStopPict[1][2]*aStopPict[2][2]
		 ld.w		%r6,  %alr			;//   %r6  := aStopPict[0][2]*aStopPict[1][2]│%r6  := aStopPict[0][2]*aStopPict[1][2]*aStopPict[2][2]
		 sub		%r7,  1				;//   %r7  := i--
		jrne		-10				;// } while(i)
;//}}容量節約
		sub		%r12, 9				;// %r12 := aStopPict
		ld.ub		%r7,  [%r12]+			;// %r7  := aStopPict[0][0]
		ld.ub		%r10, [%r12]+			;// %r10 := aStopPict[0][1]
		ld.ub		%r11, [%r12]+			;// %r11 := aStopPict[0][2]
		ld.ub		%r9,  [%r12]+			;// %r9  :=                 aStopPict[1][0]
		add		%r7,  %r9			;// %r7  := aStopPict[0][0]+aStopPict[1][0]
		ld.ub		%r9,  [%r12]+			;// %r9  :=                 aStopPict[1][1]
		add		%r10, %r9			;// %r10 := aStopPict[0][1]+aStopPict[1][1]
		ld.ub		%r9,  [%r12]+			;// %r9  :=                 aStopPict[1][2]
		add		%r11, %r9			;// %r11 := aStopPict[0][2]+aStopPict[1][2]
		ld.ub		%r9,  [%r12]+			;// %r9  :=                                 aStopPict[2][0]
		add		%r7,  %r9			;// %r7  := aStopPict[0][0]+aStopPict[1][0]+aStopPict[2][0]
		jreq.d		4				;//     if((aStopPict[0][0]+aStopPict[1][0]+aStopPict[2][0]) != 0) &&
		 ld.w		%r14, %r13			;// %r14 :=           iPictLCR			*delay*		←───────┐
		 cmp		%r4,  0				;//        (aStopPict[0][0]*aStopPict[1][0]*aStopPict[2][0]) == 0)) {		│
		 jreq		Slot_CheckTenpai_DIE		;//        DIE }								│
		ld.ub		%r9,  [%r12]+			;// %r9  :=                                 aStopPict[2][1]			│
		add		%r10, %r9			;// %r10 := aStopPict[0][1]+aStopPict[1][1]+aStopPict[2][1]			│
		jreq.d		4				;//     if((aStopPict[0][1]+aStopPict[1][1]+aStopPict[2][1]) != 0) &&		│
		 ld.w		%r15, %r13			;// %r15 :=           iPictLCR			*delay*		←────────┐
		 cmp		%r5,  0				;//        (aStopPict[0][1]*aStopPict[1][1]*aStopPict[2][1]) == 0)) {		││
		 jreq		Slot_CheckTenpai_DIE		;//        DIE }								││
		ld.ub		%r9,  [%r12]			;// %r9  :=                                 aStopPict[2][2]			││
		add		%r11, %r9			;// %r11 := aStopPict[0][2]+aStopPict[1][2]+aStopPict[2][2]			││
		jreq.d		4				;//     if((aStopPict[0][2]+aStopPict[1][2]+aStopPict[2][2]) != 0) &&		││
		 sub		%r12, 8				;// %r12 := aStopPict				*delay*		←───┐	││
		 cmp		%r6,  0				;//        (aStopPict[0][2]*aStopPict[1][2]*aStopPict[2][2]) == 0)) {	│	││
		 jreq		Slot_CheckTenpai_DIE		;//        DIE }							│	││
;//		sub		%r12, 8				;// %r12 := aStopPict						────┘	││
		;//---------------------------------------------;//										││
;//		ld.w		%r14, %r13			;// %r14 :=           iPictLCR					────────┘│
;//		ld.w		%r15, %r13			;// %r15 :=           iPictLCR					─────────┘
		sra		%r14, 4				;// %r14 :=          (iPictLCR>>4)
		sra		%r15, 8				;// %r15 :=          (iPictLCR>>8)
		and		%r13, 15			;// %r13 := iPictL = (iPictLCR>>0) & 15
		and		%r14, 15			;// %r14 := iPictC = (iPictLCR>>4) & 15
		and		%r15, 15			;// %r15 := iPictR = (iPictLCR>>8) & 15
		ld.w		%r4,  1				;// %r4  := iMask = (1<<0)
		ld.w		%r5,  3				;// %r5  := sizeof aStopPict[0] = 3
		ld.w		%r10, 0				;// %r10 := iTenpaiLineMask = 0
		xld.w		%r11, TBL_Slot_LineRow		;// %r11 := pRow = TBL_Slot_LineRow
		;// %r4  := iMask
		;// %r5  := sizeof aStopPict[0]
		;// %r10 := iTenpaiLineMask
		;// %r11 := pRow
		;// %r12 := aStopPict
		;// %r13 := iPictL
		;// %r14 := iPictC
		;// %r15 := iPictR
Slot_CheckTenpai_LOOP:						;// do {
		ld.ub		%r7, [%r11]+			;//   %r7  :=           (iRow>>0) = *pRow++
		cmp		%r13, 0				;//   if(iPictL) {
		jreq		11				;//     							─┐ 0
		 ld.w		%r6,  %r7			;//     %r6  :=         (iRow>>0)				　│ 1
		 and		%r6,  3				;//     %r6  := iRowL = (iRow>>0) & 3				　│ 2
		 mlt.h		%r6,  %r5			;//     %alr := iRowL *= 3					　│ 3
		 ld.w		%r6,  %alr			;//     %r6  :=                       iRowL			　│ 4
		 add		%r6,  %r12			;//     %r6  :=             aStopPict[iRowL]			　│ 5
		 ld.ub		%r6,  [%r6]			;//     %r6  := iStopPict = aStopPict[iRowL][0]			　│ 6
		 cmp		%r6,  0				;//     if(iStopPict) {				!INTERLOCK!	　│ 7
		 jreq		3				;//       							　│ 8
		  cmp		%r13, %r6			;//       if(iPictL != iStopPict) { continue }			　│ 9
		  jrne		Slot_CheckTenpai_NEXT		;//   } }							　│10
		cmp		%r14, 0				;//   if(iPictC) {						←┘11
		jreq		13				;//     							─┐ 0
		 ld.w		%r6,  %r7			;//     %r6  :=         (iRow>>0)				　│ 1
		 srl		%r6,  2				;//     %r6  :=         (iRow>>2)				　│ 2
		 and		%r6,  3				;//     %r6  := iRowC = (iRow>>2) & 3				　│ 3
		 mlt.h		%r6,  %r5			;//     %alr := iRowC *= 3					　│ 4
		 ld.w		%r6,  %alr			;//     %r6  :=                        iRowC			　│ 5
		 add		%r6,  %r12			;//     %r6  :=              aStopPict[iRowC]			　│ 6
		 ext		1				;//     							　│ 7
		 ld.ub		%r6,  [%r6]			;//     %r6  := iStopPict = aStopPict[iRowC][1]			　│ 8
		 cmp		%r6,  0				;//     if(iStopPict) {				!INTERLOCK!	　│ 9
		 jreq		3				;//       							　│10
		  cmp		%r14, %r6			;//       if(iPictC != iStopPict) { continue }			　│11
		  jrne		Slot_CheckTenpai_NEXT		;//   } }							　│12
		cmp		%r15, 0				;//   if(iPictR) {						←┘13
		jreq		11				;//     							─┐ 0
		 srl		%r7,  4				;//     %r7  := iRowR = (iRow>>4)				　│ 1
		 mlt.h		%r7,  %r5			;//     %alr := iRowR *= 3					　│ 2
		 ld.w		%r7,  %alr			;//     %r7  :=                        iRowR			　│ 3
		 add		%r7,  %r12			;//     %r7  :=              aStopPict[iRowR]			　│ 4
		 ext		2				;//     							　│ 5
		 ld.ub		%r7,  [%r7]			;//     %r7  := iStopPict = aStopPict[iRowR][2]			　│ 6
		 cmp		%r7,  0				;//     if(iStopPict) {				!INTERLOCK!	　│ 7
		 jreq		3				;//       							　│ 8
		  cmp		%r15, %r7			;//       if(iPictR != iStopPict) { continue }			　│ 9
		  jrne		Slot_CheckTenpai_NEXT		;//   } }							　│10
		or		%r10, %r4			;//   %r10 := iTenpaiLineMask |= iMask				←┘11
Slot_CheckTenpai_NEXT:						;//
;//{{高速化
;//		sla		%r4,  1				;// } while((iMask <<= 1) <= (1<<6))
;//		xcmp		%r4, 64				;// 
;//		jrle		Slot_CheckTenpai_LOOP		;// 
;//↓高速化
		xcmp		%r4, 32				;// } while((iMask <<= 1) <= (1<<6))
		jrle.d		Slot_CheckTenpai_LOOP		;// 
		sla		%r4,  1				;// 						*delay*
;//}}高速化
		ret
");
static void __attribute__((noreturn,unused)) Slot_CheckTenpai_DIE() { DIE(); }
#endif//PIECE

/****************************************************************************
 *	入賞判定
 ****************************************************************************/

#ifndef PIECE
#if 0
/* 単純な実装。処理内容の意図を把握するには、こちらを参照してください。 */
void Slot_CheckPrize(const unsigned char aStopPict[3/*上中下*/][3/*左中右*/], const unsigned short aHitFlg[/*nHitFlg*/], int nHitFlg, unsigned char aResult[7/*上中下降昇谷山*/]) {
	int iHitFlg, iMask, iLine;
	/* 引数nHitFlg(絵柄組合せテーブルの要素数)が、(1〜256)であることを確認する。 */
	if((nHitFlg < 1) || (nHitFlg > 256)) { DIE(); }
	/* 絵柄組合せテーブルの各要素について… */
	for(iHitFlg = 0; iHitFlg < nHitFlg; iHitFlg++) {
		/* この絵柄組合せについて、7ラインの入賞判定を行う。 */
		iMask = Slot_CheckTenpai(aStopPict, aHitFlg[iHitFlg]);
		/* 各ラインについて… */
		for(iLine = 0; iLine < 7; iLine++) {
			/* このラインに入賞していたら、この絵柄組合せ番号を結果配列へ格納する。 */
			if(iMask & (1<<iLine)) { aResult[iLine] = iHitFlg; }
		}
	}
}
#else
/* 最適化した実装。アセンブラ版は、これをベースにアセンブラ化しました。 */
void Slot_CheckPrize(const unsigned char aStopPict[3/*上中下*/][3/*左中右*/], const unsigned short aHitFlg[/*nHitFlg*/], int nHitFlg, unsigned char aResult[7/*上中下降昇谷山*/]) {
	/* 引数nHitFlg(絵柄組合せテーブルの要素数)が、(1〜256)であることを確認する。ただし、処理の都合上あらかじめ(-1)しているので、(0〜255)であることを確認する。 */
	if((unsigned)--nHitFlg > 255) { DIE(); } /* 引数不正 */
	/* nHitFlg[31:8]=(絵柄組合せテーブルの残り要素数-1),nHitFlg[7:0]=(絵柄組合せ番号)とする。ループ変数を一つ減らすための工夫である。 */
	nHitFlg <<= 8;
	/* 絵柄組合せテーブルの各要素について… */
	do {
		/* この絵柄組合せについて、7ラインの入賞判定を行う。 */
		int iMask = Slot_CheckTenpai(aStopPict, *aHitFlg++);
		/* 各ラインについて… */
		unsigned char* pResult = aResult; /* 最初のラインに対する、結果配列へのポインタ */
		do {
			/* このラインに入賞していたら、この絵柄組合せ番号を結果配列へ格納する。 */
			if(iMask & 1) { *pResult = nHitFlg; } /* nHitFlg[7:0]=(絵柄組合せ番号) */
			/* 結果配列へのポインタを、次のラインへ進める。 */
			pResult++;
		} while(iMask >>= 1); /* 入賞フラグを次のラインへ進める。1のビットが無くなったら終了する。7ライン入賞無しでも、1ループ回ることになるが、害は無い。 */
	/* nHitFlg[31:8]=(絵柄組合せテーブルの残り要素数-1)を(-1)し,nHitFlg[7:0]=(絵柄組合せ番号)を(+1)する。即ち、nHitFlg[31:0]を(-255)する。 */
	/* - ループ終了条件は、0*未満*ではなく、0*以下*であることに注意せよ。                                                                  */
	/*   呼出時の引数(nHitFlg=256)の場合、最後は(nHitFlg[31:8]:0⇒0,nHitFlg[7:0]:255⇒0)、即ち(nHitFlg[31:0]:255⇒0)で終了するからである。 */
	} while((nHitFlg -= 255) > 0);
}
#endif
#else //PIECE
void Slot_CheckPrize(const unsigned char aStopPict[3/*上中下*/][3/*左中右*/], const unsigned short aHitFlg[/*nHitFlg*/], int nHitFlg, unsigned char aResult[7/*上中下降昇谷山*/]);
asm("
		.code
		.align		1
		.global		Slot_CheckPrize
Slot_CheckPrize:
		;// %r12 := aStopPict
		;// %r13 := aHitFlg
		;// %r14 := nHitFlg
		;// %r15 := aResult
		sub		%r14, 1			;// if((unsigned)--nHitFlg > 255) {
		xcmp		%r14, 255		;//   DIE
		jrugt		Slot_CheckPrize_DIE	;// }
		pushn		%r3
		ld.w		%r0, %r12		;// %r0       := aStopPict
		ld.w		%r1, %r13		;// %r1       := aHitFlg
		ld.w		%r2, %r14		;// %r2[31:8] := nHitFlg
		sla		%r2, 8			;// %r2[ 7:0] := iHitFlg = 0
		ld.w		%r3, %r15		;// %r3       := aResult
		;// %r0       := aStopPict
		;// %r1       := aHitFlg
		;// %r2[31:8] := nHitFlg
		;// %r2[ 7:0] := iHitFlg = 0
		;// %r3       := aResult
Slot_CheckPrize_LOOP:					;// do {
		ld.uh		%r13, [%r1]+		;//   %r13 :=                                     *aHitFlg++
		xcall.d		Slot_CheckTenpai	;//   %r10 := iMask = Slot_CheckTenpai(aStopPict, *aHitFlg++)	iMask[ 0] := 上段, iMask[ 1] := 中段, iMask[ 2] := 下段, iMask[ 3] := 降斜, iMask[ 4] := 昇斜, iMask[ 5] := 小谷, iMask[ 6] := 小山
		ld.w		%r12, %r0		;//   %r12 :=                          aStopPict		*delay*
		swap		%r10, %r10		;//   %r10 := iMask =   swap(iMask)				iMask[24] := 上段, iMask[25] := 中段, iMask[26] := 下段, iMask[27] := 降斜, iMask[28] := 昇斜, iMask[29] := 小谷, iMask[30] := 小山
		mirror		%r10, %r10		;//   %r10 := iMask = mirror(iMask)				iMask[31] := 上段, iMask[30] := 中段, iMask[29] := 下段, iMask[28] := 降斜, iMask[27] := 昇斜, iMask[26] := 小谷, iMask[25] := 小山
		ld.w		%r12, %r3		;//   %r12 := pResult = aResult
		add		%r10, %r10		;//   do {
		 jruge		2			;//     %psr(C) := iMask[31], %r10 := iMask <<= 1
		  ld.b		[%r12], %r2		;//     if(%psr(C)) { *pResult = iHitFlg }
		jrne.d		-3			;//   } while(iMask)
		add		%r12, 1			;//   %r12 := pResult++						*delay*
		xsub		%r2, %r2, 255		;//   %r2[31:8] := nHitFlg--, %r2[7:0] := iHitFlg++
		jrgt		Slot_CheckPrize_LOOP	;// } while(((nHitFlg<<8)|iHitFlg) > 0)				呼出時の引数(nHitFlg=256)の場合、最後は(nHitFlg:0⇒0,iHitFlg:255⇒0)、即ち(%r2:255⇒0)で終了する。容量節約前と判断条件が違うことに注意せよ。jrgeでなくjrgtである。
		popn		%r3
		ret
");
static void __attribute__((noreturn,unused)) Slot_CheckPrize_DIE() { DIE(); }
#endif//PIECE

/****************************************************************************
 *	リール配列
 ****************************************************************************/

#ifndef PIECE
int Slot_GetReelPict(const unsigned short aReel[/*(SlotPos_Max+1)*/], int iPos, int iReel) {
	int iPict;
	/* 回胴番号が(0〜2)の範囲であることを確認する。 */
	if((unsigned)iReel > 2) { DIE(); }
	/* 絵柄位置が(0〜SlotPos_Max)の範囲外ならば、(0〜SlotPos_Max)の範囲に折り返す。 */
	if((iPos %= (SlotPos_Max+1)) < 0) { iPos += (SlotPos_Max+1); }
	/* リール配列の、絵柄位置の要素の、回胴番号の絵柄を取得する。 */
	iPict = (aReel[iPos] >> (iReel << 2)) & 15;
	if(!iPict) { DIE(); }
	return iPict;
}
#else //PIECE
int Slot_GetReelPict(const unsigned short aReel[/*(SlotPos_Max+1)*/], int iPos, int iReel);
#if    (SlotPos_Max == 20)
asm("
		.code
		.align		1
		.global		Slot_GetReelPict
Slot_GetReelPict:
		cmp		%r14, 2				;// if((unsigned)iReel > 2) {
		jrugt		Slot_GetReelPict_DIE		;//   DIE() }
		ld.w		%r15, %r12			;// %r15 := aReel
		ld.w		%r12, %r13			;// %r12 := iPos
		xcall.d		__modsi3			;// %r10 := iPos %= 21
		ld.w		%r13, 21			;// %r13 :=         21		*delay*
		add		%r10, %r10			;// %r10 := iPos *= sizeof aReel[0]
		jrge.d		3				;// if(iPos < 0) {
		 sla		%r14, 2				;// %r14 := iReel *= 4		*delay*
		 add		%r10, 42			;//   %r10 := iPos += (21 * sizeof aReel[0]) }
		add		%r10, %r15			;// %r10 := iPict =  aReel += iPos
		ld.uh		%r10, [%r10]			;// %r10 := iPict = *aReel
		sra		%r10, %r14			;// %r10 := iPict >>= iReel	!INTERLOCK!
		and		%r10, 15			;// %r10 := iPict &= 15
		jreq		Slot_GetReelPict_DIE		;// if(!iPict) { DIE() }
		ret						;// return  iPict
");
#elif  (SlotPos_Max == 19)
asm("
		.code
		.align		1
		.global		Slot_GetReelPict
Slot_GetReelPict:
		cmp		%r14, 2				;// if((unsigned)iReel > 2) {
		jrugt		Slot_GetReelPict_DIE		;//   DIE() }
		ld.w		%r15, %r12			;// %r15 := aReel
		ld.w		%r12, %r13			;// %r12 := iPos
		xcall.d		__modsi3			;// %r10 := iPos %= 20
		ld.w		%r13, 20			;// %r13 :=         20		*delay*
		add		%r10, %r10			;// %r10 := iPos *= sizeof aReel[0]
		jrge.d		3				;// if(iPos < 0) {
		 sla		%r14, 2				;// %r14 := iReel *= 4		*delay*
		 add		%r10, 40			;//   %r10 := iPos += (20 * sizeof aReel[0]) }
		add		%r10, %r15			;// %r10 := iPict =  aReel += iPos
		ld.uh		%r10, [%r10]			;// %r10 := iPict = *aReel
		sra		%r10, %r14			;// %r10 := iPict >>= iReel	!INTERLOCK!
		and		%r10, 15			;// %r10 := iPict &= 15
		jreq		Slot_GetReelPict_DIE		;// if(!iPict) { DIE() }
		ret						;// return  iPict
");
#else //SlotPos_Max
#error  SlotPos_Maxの定義が不正です。
#endif//SlotPos_Max
static void __attribute__((noreturn,unused)) Slot_GetReelPict_DIE() { DIE(); }
#endif//PIECE

//■メモ
//リール配列データのビット12〜15は不定値で構わないので、アプリケーションが他の用途に利用して構わない。
//実際のところ、有効な利用方法は無いだろう。実質、これらのビットは無駄である。
//そこで、絵柄位置3行を2バイトにパックする案も考えてみた。実装例は下記の通り:
//□実装例
//│	int Slot_GetReelPict_Packed(const unsigned char aReel[/*32*/], int iPos, int iReel) {
//│		int i, iPict;
//│		/* 回胴番号が(0〜2)の範囲であることを確認する。 */
//│		if((unsigned)iReel > 2) { DIE(); }
//│		/* 絵柄位置が(0〜SlotPos_Max)の範囲外ならば、(0〜SlotPos_Max)の範囲に折り返す。 */
//│		if((iPos %= (SlotPos_Max+1)) < 0) { iPos += (SlotPos_Max+1); }
//│		/* 絵柄位置と回胴番号から、リール配列へのニブル単位のインデクスを求める。 */
//│		i = (iPos * 3) + iReel;
//│		/* リール配列の、絵柄位置の要素の、回胴番号の絵柄を取得する。 */
//│		iPict = (aReel[i>>1] >> ((i&1)<<2)) & 15;
//│		if(!iPict) { DIE(); }
//│		return iPict;
//│	}
//│上記のバージョンを使うと、リール配列データに無駄なビットが生じない。
//│しかし、計算してみると、リール配列データの減少分よりも、コードサイズの増加分の方が多かった。
//│・ﾃﾞｰﾀｻｲｽﾞ: 42⇒32 10ﾊﾞｲﾄ減
//│・ｺｰﾄﾞｻｲｽﾞ: 17⇒23 12ﾊﾞｲﾄ増
//│というわけで、上記のバージョンは利点が無かったので、採用しない。一応、記録までに残しておく。

#ifndef __RENESAS__	//{{2016/09/29追加:Hewでは停止制御を含めないようにしました。}}
/****************************************************************************
 *	停止制御
 ****************************************************************************/

/*--------------------------------------------------------------------------*
 *	1リール停止制御
 *--------------------------------------------------------------------------*/

/* 引込セット1番号(iHkmSet1)の、押下位置1が(iPushPos1)の、引込駒数を取得する。
 * [in]
 *	pStpCtl		停止制御データ
 *	iHkmSet1	引込セット1番号		0〜(HkmSet1_Size-1)
 *	iPushPos1	押下位置1		0〜SlotPos_Max
 * [out]
 *	戻り値		引込駒数		0〜4
 * [note]
 *	- 引込セット1とは、(引込駒数×押下位置1)の組合せを、重複無く登録したものです。
 */
static int GetHkmSet1(const ST_Slot_StpCtl* pStpCtl, int iHkmSet1, int iPushPos1) {
	unsigned char (*Buf/*[HkmSet1_CompUnit]*/)[((SlotPos_Max+1) + 2) / 3] = alloca(pStpCtl->HkmSet1_CompUnit * (((SlotPos_Max+1) + 2) / 3));
	int nHkmCnt, iCompData, iCompSize, nUncompSize;
	if((unsigned)iHkmSet1 >= pStpCtl->HkmSet1_Size) { DIE(); }
	if((unsigned)iPushPos1 > SlotPos_Max) { DIE(); }
	iCompData = 0;
	for(iCompSize = 0;
	    iCompSize < (iHkmSet1 / pStpCtl->HkmSet1_CompUnit);
	    iCompSize++) {
		iCompData += pStpCtl->TBL_HkmSet1_CompSize[iCompSize];
	}
	if((unsigned)iCompData >= pStpCtl->HkmSet1_CompData_Size) { DIE(); }
	nUncompSize = TinyLZ_uncompress(
		Buf, pStpCtl->HkmSet1_CompUnit * (SlotPos_Max+1),
		&pStpCtl->TBL_HkmSet1_CompData[iCompData],
		 pStpCtl->TBL_HkmSet1_CompSize[iCompSize]);
	if(((nUncompSize % (((SlotPos_Max+1) + 2) / 3)) != 0) ||
	   ((nUncompSize / (((SlotPos_Max+1) + 2) / 3)) < (iHkmSet1 % pStpCtl->HkmSet1_CompUnit))) { DIE(); }
	nHkmCnt = Buf[iHkmSet1 % pStpCtl->HkmSet1_CompUnit][iPushPos1 / 3];
	switch(iPushPos1 % 3) {
	case 0: nHkmCnt = nHkmCnt      % 6; break;
	case 1: nHkmCnt = nHkmCnt /  6 % 6; break;
	case 2: nHkmCnt = nHkmCnt / 36    ; break;
	default: DIE();
	}
	if((unsigned)nHkmCnt > 4) { DIE(); }
	return nHkmCnt;
}

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

int Slot_GetStpCtl1(const ST_Slot_StpCtl* pStpCtl, int iHitCd, int iReel1, int iPushPos1) {
	int iHkmSet1;
	if((unsigned)iHitCd >= pStpCtl->HitCd_Size) { DIE(); }
	if((unsigned)iReel1 > 2) { DIE(); }
	if((unsigned)iPushPos1 > SlotPos_Max) { DIE(); }
	iHkmSet1 = pStpCtl->TBL_StpCtl1[iHitCd][iReel1];
	return GetHkmSet1(pStpCtl, iHkmSet1, iPushPos1);
}

/*--------------------------------------------------------------------------*
 *	2リール停止制御
 *--------------------------------------------------------------------------*/

/* 引込セット2番号(iHkmSet2)の、停止位置1が(iStopPos1),押下位置2が(iPushPos2)の、引込駒数を取得する。
 * [in]
 *	pStpCtl		停止制御データ
 *	iHkmSet2	引込セット2番号		0〜(HkmSet2_Size-1)
 *	iStopPos1	停止位置1		0〜SlotPos_Max
 *	iPushPos2	押下位置2		0〜SlotPos_Max
 * [out]
 *	戻り値		引込駒数		0〜4
 * [note]
 *	- 引込セット2とは、(引込セット1番号×停止位置1)の組合せを、重複無く登録したものです。
 *	- 引込セット2データは、(HkmSet2_CompUnit)個単位で、圧縮されています。
 */
static int GetHkmSet2(const ST_Slot_StpCtl* pStpCtl, int iHkmSet2, int iStopPos1, int iPushPos2) {
	unsigned char (*Buf/*[HkmSet2_CompUnit]*/)[(SlotPos_Max+1)] = alloca(pStpCtl->HkmSet2_CompUnit * (SlotPos_Max+1));
	int iHkmSet1, iCompData, iCompSize, nUncompSize;
	if((unsigned)iHkmSet2 >= pStpCtl->HkmSet2_Size) { DIE(); }
	if((unsigned)iStopPos1 > SlotPos_Max) { DIE(); }
	if((unsigned)iPushPos2 > SlotPos_Max) { DIE(); }
	iCompData = 0;
	for(iCompSize = 0;
	    iCompSize < (iHkmSet2 / pStpCtl->HkmSet2_CompUnit);
	    iCompSize++) {
		iCompData += pStpCtl->TBL_HkmSet2_CompSize[iCompSize];
	}
	if((unsigned)iCompData >= pStpCtl->HkmSet2_CompData_Size) { DIE(); }
	nUncompSize = TinyLZ_uncompress(
		Buf, pStpCtl->HkmSet2_CompUnit * (SlotPos_Max+1),
		&pStpCtl->TBL_HkmSet2_CompData[iCompData],
		 pStpCtl->TBL_HkmSet2_CompSize[iCompSize]);
	if(((nUncompSize % (SlotPos_Max+1)) != 0) ||
	   ((nUncompSize / (SlotPos_Max+1)) < (iHkmSet2 % pStpCtl->HkmSet2_CompUnit))) { DIE(); }
	iHkmSet1 = Buf[iHkmSet2 % pStpCtl->HkmSet2_CompUnit][iStopPos1];
	return GetHkmSet1(pStpCtl, iHkmSet1, iPushPos2);
}

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

int Slot_GetStpCtl2(const ST_Slot_StpCtl* pStpCtl, int iHitCd, int iReel1, int iReel2, int iStopPos1, int iPushPos2) {
	int iHkmSet2, iOrder;
	if((unsigned)iHitCd >= pStpCtl->HitCd_Size) { DIE(); }
	if((unsigned)iReel1 > 2) { DIE(); }
	if((unsigned)iReel2 > 2) { DIE(); }
	if((unsigned)iStopPos1 > SlotPos_Max) { DIE(); }
	if((unsigned)iPushPos2 > SlotPos_Max) { DIE(); }
	iOrder = Slot_FindOrder(iReel1, iReel2);
	iHkmSet2 = pStpCtl->TBL_StpCtl2[iHitCd][iOrder];
	return GetHkmSet2(pStpCtl, iHkmSet2, iStopPos1, iPushPos2);
}

/*--------------------------------------------------------------------------*
 *	3リール停止制御
 *--------------------------------------------------------------------------*/

/* 引込セット3番号(iHkmSet3)の、停止位置1が(iStopPos1),停止位置2が(iStopPos2),押下位置3が(iPushPos3)の、引込駒数を取得する。
 * [in]
 *	pStpCtl		停止制御データ
 *	iHkmSet3	引込セット3番号		0〜(HkmSet3_Size-1)
 *	iStopPos1	停止位置1		0〜SlotPos_Max
 *	iStopPos2	停止位置2		0〜SlotPos_Max
 *	iPushPos3	押下位置3		0〜SlotPos_Max
 * [out]
 *	戻り値		引込駒数		0〜4
 * [note]
 *	- 引込セット3とは、(引込セット2番号×停止位置1)の組合せを、重複無く登録したものです。
 *	- 引込セット3データは、(HkmSet3_CompUnit)個単位で、圧縮されています。
 */
static int GetHkmSet3(const ST_Slot_StpCtl* pStpCtl, int iHkmSet3, int iStopPos1, int iStopPos2, int iPushPos3) {
	unsigned char (*Buf/*[HkmSet3_CompUnit]*/)[(SlotPos_Max+1)] = alloca(pStpCtl->HkmSet3_CompUnit * (SlotPos_Max+1));
	int iHkmSet2, iCompData, iCompSize, nUncompSize;
	if((unsigned)iHkmSet3 >= pStpCtl->HkmSet3_Size) { DIE(); }
	if((unsigned)iStopPos1 > SlotPos_Max) { DIE(); }
	if((unsigned)iStopPos2 > SlotPos_Max) { DIE(); }
	if((unsigned)iPushPos3 > SlotPos_Max) { DIE(); }
	iCompData = 0;
	for(iCompSize = 0;
	    iCompSize < (iHkmSet3 / pStpCtl->HkmSet3_CompUnit);
	    iCompSize++) {
		iCompData += pStpCtl->TBL_HkmSet3_CompSize[iCompSize];
	}
	if((unsigned)iCompData >= pStpCtl->HkmSet3_CompData_Size) { DIE(); }
	nUncompSize = TinyLZ_uncompress(
		Buf, pStpCtl->HkmSet3_CompUnit * (SlotPos_Max+1),
		&pStpCtl->TBL_HkmSet3_CompData[iCompData],
		 pStpCtl->TBL_HkmSet3_CompSize[iCompSize]);
	if(((nUncompSize % (SlotPos_Max+1)) != 0) ||
	   ((nUncompSize / (SlotPos_Max+1)) < (iHkmSet3 % pStpCtl->HkmSet3_CompUnit))) { DIE(); }
	iHkmSet2 = Buf[iHkmSet3 % pStpCtl->HkmSet3_CompUnit][iStopPos1];
	return GetHkmSet2(pStpCtl, iHkmSet2, iStopPos2, iPushPos3);
}

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

int Slot_GetStpCtl3(const ST_Slot_StpCtl* pStpCtl, int iHitCd, int iReel1, int iReel2, int iReel3, int iStopPos1, int iStopPos2, int iPushPos3) {
	int iHkmSet3, iOrder;
	if((unsigned)iHitCd >= pStpCtl->HitCd_Size) { DIE(); }
	if((unsigned)iReel1 > 2) { DIE(); }
	if((unsigned)iReel2 > 2) { DIE(); }
	if((unsigned)iReel3 > 2) { DIE(); }
	if((unsigned)iStopPos1 > SlotPos_Max) { DIE(); }
	if((unsigned)iStopPos2 > SlotPos_Max) { DIE(); }
	if((unsigned)iPushPos3 > SlotPos_Max) { DIE(); }
	iOrder = Slot_FindOrder(iReel1, iReel2);
	iHkmSet3 = pStpCtl->TBL_StpCtl3[iHitCd][iOrder];
	return GetHkmSet3(pStpCtl, iHkmSet3, iStopPos1, iStopPos2, iPushPos3);
}
#endif//__RENESAS__	//{{2016/09/29追加:Hewでは停止制御を含めないようにしました。}}

/****************************************************************************
 *	停止制御データビルダ
 ****************************************************************************/
#ifdef  WIN32	//PC上で停止制御データを作成する時に使用します。P/ECE上では使用しません。
/* 停止制御データビルダ */
typedef struct _ST_Slot_StpCtl_Builder {
	unsigned short HkmSet1_Size;
	unsigned short HkmSet2_Size;
	unsigned short HkmSet3_Size;
	unsigned short HkmSet1_CompData_Size;
	unsigned short HkmSet2_CompData_Size;
	unsigned short HkmSet3_CompData_Size;
	unsigned char (*TBL_StpCtl1/*[HitCd_Size]*/)[3]/*[(SlotPos_Max+1)]*/;					//                                                                                          ⇒TBL_HkmSet1
	unsigned char (*TBL_StpCtl2/*[HitCd_Size]*/)[6]/*[(SlotPos_Max+1)][(SlotPos_Max+1)]*/;			//                                             ⇒(TBL_HkmSet2_CompSize,TBL_HkmSet2_CompData)⇒TBL_HkmSet1
	unsigned char (*TBL_StpCtl3/*[HitCd_Size]*/)[6]/*[(SlotPos_Max+1)][(SlotPos_Max+1)][(SlotPos_Max+1)]*/;	//⇒(TBL_HkmSet3_CompSize,TBL_HkmSet3_CompData)⇒(TBL_HkmSet2_CompSize,TBL_HkmSet2_CompData)⇒TBL_HkmSet1
	unsigned char TBL_HkmSet1[256/*HkmSet1_Sizeの上限*/][(SlotPos_Max+1)];
	unsigned char TBL_HkmSet2[256/*HkmSet2_Sizeの上限*/][(SlotPos_Max+1)];
	unsigned char TBL_HkmSet3[256/*HkmSet3_Sizeの上限*/][(SlotPos_Max+1)];
	unsigned char TBL_HkmSet1_CompSize[ 256/*充分なサイズ*/];
	unsigned char TBL_HkmSet2_CompSize[ 256/*充分なサイズ*/];
	unsigned char TBL_HkmSet3_CompSize[ 256/*充分なサイズ*/];
	unsigned char TBL_HkmSet1_CompData[8192/*充分なサイズ*/];
	unsigned char TBL_HkmSet2_CompData[8192/*充分なサイズ*/];
	unsigned char TBL_HkmSet3_CompData[8192/*充分なサイズ*/];
	unsigned char (*TBL_StpFlg1/*[HitCd_Size]*/)[/*iPos1*/(SlotPos_Max+1)];					//1リール停止フラグ。条件装置が(HitCd_Size)で、押順が(bit0-5に対応)の時に、第1停止リールが(iPos1)に停止し得るかを示す。
	unsigned char (*TBL_StpFlg2/*[HitCd_Size]*/)[/*iPos1*/(SlotPos_Max+1)][/*iPos2*/(SlotPos_Max+1)];	//2リール停止フラグ。条件装置が(HitCd_Size)で、押順が(bit0-5に対応)の時に、第1停止リールが(iPos1),第2停止リールが(iPos2)に停止し得るかを示す。
	unsigned char TBL_HkmSet1_Pack[256/*HkmSet1_Sizeの上限*/][((SlotPos_Max+1) + 2) / 3];
} ST_Slot_StpCtl_Builder;
/*--------------------------------------------------------------------------*/
static int memcmp21(const void* x, const void* y) { return memcmp(x, y, (SlotPos_Max+1)); }
/*--------------------------------------------------------------------------*/
/* 引込セット1を重複無く登録する */
static int UnionHkmSet1(ST_Slot_StpCtl_Builder* pBuilder, const unsigned char aHkmCnt[(SlotPos_Max+1)]) {
	int iHkmSet1;
	for(iHkmSet1 = 0; iHkmSet1 < pBuilder->HkmSet1_Size; iHkmSet1++) {
		if(!memcmp21(pBuilder->TBL_HkmSet1[iHkmSet1], aHkmCnt)) { return iHkmSet1; }
	}
	if(pBuilder->HkmSet1_Size >= ARRAY_SIZE(pBuilder->TBL_HkmSet1)) { DIE(); }
	memcpy(pBuilder->TBL_HkmSet1[pBuilder->HkmSet1_Size], aHkmCnt, (SlotPos_Max+1));
	return pBuilder->HkmSet1_Size++;
}
/*--------------------------------------------------------------------------*/
/* 引込セット2を重複無く登録する */
static int UnionHkmSet2(ST_Slot_StpCtl_Builder* pBuilder, const unsigned char aHkmSet1[(SlotPos_Max+1)]) {
	int iHkmSet2;
	for(iHkmSet2 = 0; iHkmSet2 < pBuilder->HkmSet2_Size; iHkmSet2++) {
		if(!memcmp21(pBuilder->TBL_HkmSet2[iHkmSet2], aHkmSet1)) { return iHkmSet2; }
	}
	if(pBuilder->HkmSet2_Size >= ARRAY_SIZE(pBuilder->TBL_HkmSet2)) { DIE(); }
	memcpy(pBuilder->TBL_HkmSet2[pBuilder->HkmSet2_Size], aHkmSet1, (SlotPos_Max+1));
	return pBuilder->HkmSet2_Size++;
}
/*--------------------------------------------------------------------------*/
/* 引込セット3を重複無く登録する */
static int UnionHkmSet3(ST_Slot_StpCtl_Builder* pBuilder, const unsigned char aHkmSet2[(SlotPos_Max+1)]) {
	int iHkmSet3;
	for(iHkmSet3 = 0; iHkmSet3 < pBuilder->HkmSet3_Size; iHkmSet3++) {
		if(!memcmp21(pBuilder->TBL_HkmSet3[iHkmSet3], aHkmSet2)) { return iHkmSet3; }
	}
	if(pBuilder->HkmSet3_Size >= ARRAY_SIZE(pBuilder->TBL_HkmSet3)) { DIE(); }
	memcpy(pBuilder->TBL_HkmSet3[pBuilder->HkmSet3_Size], aHkmSet2, (SlotPos_Max+1));
	return pBuilder->HkmSet3_Size++;
}
/*--------------------------------------------------------------------------*/
ST_Slot_StpCtl* Slot_BuildStpCtl(const ST_Slot_StpCtl_BuilderInfo* pInfo) {
	ST_Slot_StpCtl* pStpCtl;
	ST_Slot_StpCtl_Builder* pBuilder;
	int iHitCd, iOrder, iReel1, iReel2, iReel3, iPos1, iPos2, iPos3, i, j, n;
	unsigned char aHkmCnt[(SlotPos_Max+1)], aHkmSet1[(SlotPos_Max+1)], aHkmSet2[(SlotPos_Max+1)];
	unsigned char* p;
	/* 圧縮単位を取得する。0が指定された場合、推奨値を使用する。 */
	int HkmSet1_CompUnit = pInfo->HkmSet1_CompUnit ? pInfo->HkmSet1_CompUnit : 16/*推奨値*/;
	int HkmSet2_CompUnit = pInfo->HkmSet2_CompUnit ? pInfo->HkmSet2_CompUnit : 16/*推奨値*/;
	int HkmSet3_CompUnit = pInfo->HkmSet3_CompUnit ? pInfo->HkmSet3_CompUnit : 16/*推奨値*/;
	/* 停止制御データビルダのメモリを確保する。(1個のメモリブロックとして確保する。解放時も1個のメモリブロックとして開放せよ。) */
	p = calloc(1, sizeof(ST_Slot_StpCtl_Builder) +
		(pInfo->HitCd_Size * 3) +					/* TBL_StpCtl1 */
		(pInfo->HitCd_Size * 6) +					/* TBL_StpCtl2 */
		(pInfo->HitCd_Size * 6) +					/* TBL_StpCtl3 */
		(pInfo->HitCd_Size * (SlotPos_Max+1)) +				/* TBL_StpFlg1 */
		(pInfo->HitCd_Size * (SlotPos_Max+1) * (SlotPos_Max+1)));	/* TBL_StpFlg2 */
	if(!p) { DIE(); }
	pBuilder              = (void*)p;   p += sizeof(ST_Slot_StpCtl_Builder);
	pBuilder->TBL_StpCtl1 = (void*)p;   p += (pInfo->HitCd_Size * 3);
	pBuilder->TBL_StpCtl2 = (void*)p;   p += (pInfo->HitCd_Size * 6);
	pBuilder->TBL_StpCtl3 = (void*)p;   p += (pInfo->HitCd_Size * 6);
	pBuilder->TBL_StpFlg1 = (void*)p;   p += (pInfo->HitCd_Size * (SlotPos_Max+1));
	pBuilder->TBL_StpFlg2 = (void*)p; //p += (pInfo->HitCd_Size * (SlotPos_Max+1) * (SlotPos_Max+1));
	/*--- 引込セット1を重複無く登録する ---*/
	/* 1リール停止制御 */
	for(iHitCd = 0; iHitCd < pInfo->HitCd_Size; iHitCd++) {
		for(iOrder = 0; iOrder < 3; iOrder++) {
			iReel1 = Slot_GetOrderReel(iOrder, 0);		/* 停止中リール */
			for(iPos1 = 0; iPos1 < (SlotPos_Max+1); iPos1++) {
				n = (*pInfo->fnGetStpCtl1)(pInfo->pParam, iHitCd, iReel1, iPos1);
				if((unsigned)n > 4) { DIE(); }
				pBuilder->TBL_StpFlg1[iHitCd][(iPos1 - n + (SlotPos_Max+1)) % (SlotPos_Max+1)] |= (((1<<0)|(1<<3))<<iOrder);		//1リール停止フラグをセットする。第2停止で可能性の有る2種類の押順に対してセットする。
				aHkmCnt[iPos1] = n;
			}
			UnionHkmSet1(pBuilder, aHkmCnt);												//ソートするまで、引込セット1番号は未確定。ここでは、登録のみ行う。
		}
	}
	/* 2リール停止制御 */
	for(iHitCd = 0; iHitCd < pInfo->HitCd_Size; iHitCd++) {
		for(iOrder = 0; iOrder < 6; iOrder++) {
			iReel1 = Slot_GetOrderReel(iOrder, 0);		/* 停止済リール */
			iReel2 = Slot_GetOrderReel(iOrder, 1);		/* 停止中リール */
			for(iPos1 = 0; iPos1 < (SlotPos_Max+1); iPos1++) {
				for(iPos2 = 0; iPos2 < (SlotPos_Max+1); iPos2++) {
					if(pBuilder->TBL_StpFlg1[iHitCd][iPos1] & (1<<iOrder)) {
						n = (*pInfo->fnGetStpCtl2)(pInfo->pParam, iHitCd, iReel1, iReel2, iPos1, iPos2);
						if((unsigned)n > 4) { DIE(); }
						pBuilder->TBL_StpFlg2[iHitCd][iPos1][(iPos2 - n + (SlotPos_Max+1)) % (SlotPos_Max+1)] |= (1<<iOrder);	//2リール停止フラグをセットする。
					} else {
						n = 5;
					}
					aHkmCnt[iPos2] = n;
				}
				UnionHkmSet1(pBuilder, aHkmCnt);											//ソートするまで、引込セット1番号は未確定。ここでは、登録のみ行う。
			}
		}
	}
	/* 3リール停止制御 */
	for(iHitCd = 0; iHitCd < pInfo->HitCd_Size; iHitCd++) {
		for(iOrder = 0; iOrder < 6; iOrder++) {
			iReel1 = Slot_GetOrderReel(iOrder, 0);		/* 停止済リール1 */
			iReel2 = Slot_GetOrderReel(iOrder, 1);		/* 停止済リール2 */
			iReel3 = Slot_GetOrderReel(iOrder, 2);		/* 停止中リール  */
			for(iPos1 = 0; iPos1 < (SlotPos_Max+1); iPos1++) {
				for(iPos2 = 0; iPos2 < (SlotPos_Max+1); iPos2++) {
					for(iPos3 = 0; iPos3 < (SlotPos_Max+1); iPos3++) {
						if(pBuilder->TBL_StpFlg2[iHitCd][iPos1][iPos2] & (1<<iOrder)) {
							n = (*pInfo->fnGetStpCtl3)(pInfo->pParam, iHitCd, iReel1, iReel2, iReel3, iPos1, iPos2, iPos3);
							if((unsigned)n > 4) { DIE(); }
						} else {
							n = 5;
						}
						aHkmCnt[iPos3] = n;
					}
					UnionHkmSet1(pBuilder, aHkmCnt);										//ソートするまで、引込セット1番号は未確定。ここでは、登録のみ行う。
				}
			}
		}
	}
	/* 引込セット1をソートする。ソートすると、圧縮率が多少良くなる。 */
	qsort(pBuilder->TBL_HkmSet1, pBuilder->HkmSet1_Size, (SlotPos_Max+1), memcmp21);								//これで、引込セット1番号が確定する。
	/*--- 引込セット2を重複無く登録する ---*/
	/* 2リール停止制御 */
	for(iHitCd = 0; iHitCd < pInfo->HitCd_Size; iHitCd++) {
		for(iOrder = 0; iOrder < 6; iOrder++) {
			iReel1 = Slot_GetOrderReel(iOrder, 0);		/* 停止済リール */
			iReel2 = Slot_GetOrderReel(iOrder, 1);		/* 停止中リール */
			for(iPos1 = 0; iPos1 < (SlotPos_Max+1); iPos1++) {
				for(iPos2 = 0; iPos2 < (SlotPos_Max+1); iPos2++) {
					if(pBuilder->TBL_StpFlg1[iHitCd][iPos1] & (1<<iOrder)) {
						n = (*pInfo->fnGetStpCtl2)(pInfo->pParam, iHitCd, iReel1, iReel2, iPos1, iPos2);
						if((unsigned)n > 4) { DIE(); }
					} else {
						n = 5;
					}
					aHkmCnt[iPos2] = n;
				}
				aHkmSet1[iPos1] = UnionHkmSet1(pBuilder, aHkmCnt);
			}
			UnionHkmSet2(pBuilder, aHkmSet1);			//ソートするまで、引込セット2番号は未確定。ここでは、登録のみ行う。
		}
	}
	/* 3リール停止制御 */
	for(iHitCd = 0; iHitCd < pInfo->HitCd_Size; iHitCd++) {
		for(iOrder = 0; iOrder < 6; iOrder++) {
			iReel1 = Slot_GetOrderReel(iOrder, 0);		/* 停止済リール1 */
			iReel2 = Slot_GetOrderReel(iOrder, 1);		/* 停止済リール2 */
			iReel3 = Slot_GetOrderReel(iOrder, 2);		/* 停止中リール  */
			for(iPos1 = 0; iPos1 < (SlotPos_Max+1); iPos1++) {
				for(iPos2 = 0; iPos2 < (SlotPos_Max+1); iPos2++) {
					for(iPos3 = 0; iPos3 < (SlotPos_Max+1); iPos3++) {
						if(pBuilder->TBL_StpFlg2[iHitCd][iPos1][iPos2] & (1<<iOrder)) {
							n = (*pInfo->fnGetStpCtl3)(pInfo->pParam, iHitCd, iReel1, iReel2, iReel3, iPos1, iPos2, iPos3);
							if((unsigned)n > 4) { DIE(); }
						} else {
							n = 5;
						}
						aHkmCnt[iPos3] = n;
					}
					aHkmSet1[iPos2] = UnionHkmSet1(pBuilder, aHkmCnt);
				}
				UnionHkmSet2(pBuilder, aHkmSet1);		//ソートするまで、引込セット2番号は未確定。ここでは、登録のみ行う。
			}
		}
	}
	/* 引込セット2をソートする。ソートすると、圧縮率が多少良くなる。 */
	qsort(pBuilder->TBL_HkmSet2, pBuilder->HkmSet2_Size, (SlotPos_Max+1), memcmp21);	//これで、引込セット2番号が確定する。
	/*--- 引込セット3を重複無く登録する ---*/
	/* 3リール停止制御 */
	for(iHitCd = 0; iHitCd < pInfo->HitCd_Size; iHitCd++) {
		for(iOrder = 0; iOrder < 6; iOrder++) {
			iReel1 = Slot_GetOrderReel(iOrder, 0);		/* 停止済リール1 */
			iReel2 = Slot_GetOrderReel(iOrder, 1);		/* 停止済リール2 */
			iReel3 = Slot_GetOrderReel(iOrder, 2);		/* 停止中リール  */
			for(iPos1 = 0; iPos1 < (SlotPos_Max+1); iPos1++) {
				for(iPos2 = 0; iPos2 < (SlotPos_Max+1); iPos2++) {
					for(iPos3 = 0; iPos3 < (SlotPos_Max+1); iPos3++) {
						if(pBuilder->TBL_StpFlg2[iHitCd][iPos1][iPos2] & (1<<iOrder)) {
							n = (*pInfo->fnGetStpCtl3)(pInfo->pParam, iHitCd, iReel1, iReel2, iReel3, iPos1, iPos2, iPos3);
							if((unsigned)n > 4) { DIE(); }
						} else {
							n = 5;
						}
						aHkmCnt[iPos3] = n;
					}
					aHkmSet1[iPos2] = UnionHkmSet1(pBuilder, aHkmCnt);
				}
				aHkmSet2[iPos1] = UnionHkmSet2(pBuilder, aHkmSet1);
			}
			UnionHkmSet3(pBuilder, aHkmSet2);			//ソートするまで、引込セット3番号は未確定。ここでは、登録のみ行う。
		}
	}
	/* 引込セット3をソートする。ソートすると、圧縮率が多少良くなる。 */
	qsort(pBuilder->TBL_HkmSet2, pBuilder->HkmSet2_Size, (SlotPos_Max+1), memcmp21);	//これで、引込セット3番号が確定する。
	/*--- 1リール停止制御データ,2リール停止制御データ,3リール停止制御データを作成する ---*/
	/* 1リール停止制御 */
	for(iHitCd = 0; iHitCd < pInfo->HitCd_Size; iHitCd++) {
		for(iOrder = 0; iOrder < 3; iOrder++) {
			iReel1 = Slot_GetOrderReel(iOrder, 0);		/* 停止中リール */
			for(iPos1 = 0; iPos1 < (SlotPos_Max+1); iPos1++) {
				n = (*pInfo->fnGetStpCtl1)(pInfo->pParam, iHitCd, iReel1, iPos1);
				if((unsigned)n > 4) { DIE(); }
				aHkmCnt[iPos1] = n;
			}
			pBuilder->TBL_StpCtl1[iHitCd][iOrder] = UnionHkmSet1(pBuilder, aHkmCnt);
		}
	}
	for(i = 0; i < pBuilder->HkmSet1_Size; i++) {
		for(j = 0; j < (((SlotPos_Max+1) + 2) / 3); j++) {
			pBuilder->TBL_HkmSet1_Pack[i][j] = (pBuilder->TBL_HkmSet1[i][(j * 3) + 0]     ) +
			                                   (pBuilder->TBL_HkmSet1[i][(j * 3) + 1] *  6) +
			                                   (pBuilder->TBL_HkmSet1[i][(j * 3) + 2] * 36);
		}
	}
	for(i = 0; i < pBuilder->HkmSet1_Size; i += HkmSet1_CompUnit) {
		n = pBuilder->HkmSet1_Size - i;
		if(n > HkmSet1_CompUnit) { n = HkmSet1_CompUnit; }
		n = TinyLZ_compress(
			&pBuilder->TBL_HkmSet1_CompData[pBuilder->HkmSet1_CompData_Size],
			ARRAY_SIZE(pBuilder->TBL_HkmSet1_CompData) - pBuilder->HkmSet1_CompData_Size,
			&pBuilder->TBL_HkmSet1_Pack[i], n * (((SlotPos_Max+1) + 2) / 3));
		pBuilder->TBL_HkmSet1_CompSize[i / HkmSet1_CompUnit] = n;
//{{2016/07/24追加:Slot_BuildStpCtl()にて、TinyLZ_compress()の結果が256以上になった時に、正しくはエラー停止すべき所、そのまま(unsigned char)配列に格納してしまい、間違ったデータが生成されていたバグを修正しました。修正方法としては、格納する前に(n<256)を検査しても良かったのですが、もし今後(unsigned char)配列を(unsigned short)配列に変更する場合に備えて、格納後に元の値と同じかを比較して検査する事にしました。
		if(pBuilder->TBL_HkmSet1_CompSize[i / HkmSet1_CompUnit] != n) { DIE(); }	//ここで停止した場合は、HkmSet1_CompUnitを減らして下さい。
//}}2016/07/24追加:Slot_BuildStpCtl()にて、TinyLZ_compress()の結果が256以上になった時に、正しくはエラー停止すべき所、そのまま(unsigned char)配列に格納してしまい、間違ったデータが生成されていたバグを修正しました。修正方法としては、格納する前に(n<256)を検査しても良かったのですが、もし今後(unsigned char)配列を(unsigned short)配列に変更する場合に備えて、格納後に元の値と同じかを比較して検査する事にしました。
		if((pBuilder->HkmSet1_CompData_Size += n) > ARRAY_SIZE(pBuilder->TBL_HkmSet1_CompData)) { DIE(); }
	}
	/* 2リール停止制御 */
	for(iHitCd = 0; iHitCd < pInfo->HitCd_Size; iHitCd++) {
		for(iOrder = 0; iOrder < 6; iOrder++) {
			iReel1 = Slot_GetOrderReel(iOrder, 0);		/* 停止済リール */
			iReel2 = Slot_GetOrderReel(iOrder, 1);		/* 停止中リール */
			for(iPos1 = 0; iPos1 < (SlotPos_Max+1); iPos1++) {
				for(iPos2 = 0; iPos2 < (SlotPos_Max+1); iPos2++) {
					if(pBuilder->TBL_StpFlg1[iHitCd][iPos1] & (1<<iOrder)) {
						n = (*pInfo->fnGetStpCtl2)(pInfo->pParam, iHitCd, iReel1, iReel2, iPos1, iPos2);
						if((unsigned)n > 4) { DIE(); }
					} else {
						n = 5;
					}
					aHkmCnt[iPos2] = n;
				}
				aHkmSet1[iPos1] = UnionHkmSet1(pBuilder, aHkmCnt);
			}
			pBuilder->TBL_StpCtl2[iHitCd][iOrder] = UnionHkmSet2(pBuilder, aHkmSet1);
		}
	}
	for(i = 0; i < pBuilder->HkmSet2_Size; i += HkmSet2_CompUnit) {
		n = pBuilder->HkmSet2_Size - i;
		if(n > HkmSet2_CompUnit) { n = HkmSet2_CompUnit; }
		n = TinyLZ_compress(
			&pBuilder->TBL_HkmSet2_CompData[pBuilder->HkmSet2_CompData_Size],
			ARRAY_SIZE(pBuilder->TBL_HkmSet2_CompData) - pBuilder->HkmSet2_CompData_Size,
			&pBuilder->TBL_HkmSet2[i], n * (SlotPos_Max+1));
		pBuilder->TBL_HkmSet2_CompSize[i / HkmSet2_CompUnit] = n;
//{{2016/07/24追加:Slot_BuildStpCtl()にて、TinyLZ_compress()の結果が256以上になった時に、正しくはエラー停止すべき所、そのまま(unsigned char)配列に格納してしまい、間違ったデータが生成されていたバグを修正しました。修正方法としては、格納する前に(n<256)を検査しても良かったのですが、もし今後(unsigned char)配列を(unsigned short)配列に変更する場合に備えて、格納後に元の値と同じかを比較して検査する事にしました。
		if(pBuilder->TBL_HkmSet2_CompSize[i / HkmSet2_CompUnit] != n) { DIE(); }	//ここで停止した場合は、HkmSet2_CompUnitを減らして下さい。
//}}2016/07/24追加:Slot_BuildStpCtl()にて、TinyLZ_compress()の結果が256以上になった時に、正しくはエラー停止すべき所、そのまま(unsigned char)配列に格納してしまい、間違ったデータが生成されていたバグを修正しました。修正方法としては、格納する前に(n<256)を検査しても良かったのですが、もし今後(unsigned char)配列を(unsigned short)配列に変更する場合に備えて、格納後に元の値と同じかを比較して検査する事にしました。
		if((pBuilder->HkmSet2_CompData_Size += n) > ARRAY_SIZE(pBuilder->TBL_HkmSet2_CompData)) { DIE(); }
	}
	/* 3リール停止制御 */
	for(iHitCd = 0; iHitCd < pInfo->HitCd_Size; iHitCd++) {
		for(iOrder = 0; iOrder < 6; iOrder++) {
			iReel1 = Slot_GetOrderReel(iOrder, 0);		/* 停止済リール1 */
			iReel2 = Slot_GetOrderReel(iOrder, 1);		/* 停止済リール2 */
			iReel3 = Slot_GetOrderReel(iOrder, 2);		/* 停止中リール  */
			for(iPos1 = 0; iPos1 < (SlotPos_Max+1); iPos1++) {
				for(iPos2 = 0; iPos2 < (SlotPos_Max+1); iPos2++) {
					for(iPos3 = 0; iPos3 < (SlotPos_Max+1); iPos3++) {
						if(pBuilder->TBL_StpFlg2[iHitCd][iPos1][iPos2] & (1<<iOrder)) {
							n = (*pInfo->fnGetStpCtl3)(pInfo->pParam, iHitCd, iReel1, iReel2, iReel3, iPos1, iPos2, iPos3);
							if((unsigned)n > 4) { DIE(); }
						} else {
							n = 5;
						}
						aHkmCnt[iPos3] = n;
					}
					aHkmSet1[iPos2] = UnionHkmSet1(pBuilder, aHkmCnt);
				}
				aHkmSet2[iPos1] = UnionHkmSet2(pBuilder, aHkmSet1);
			}
			pBuilder->TBL_StpCtl3[iHitCd][iOrder] = UnionHkmSet3(pBuilder, aHkmSet2);
		}
	}
	for(i = 0; i < pBuilder->HkmSet3_Size; i += HkmSet3_CompUnit) {
		n = pBuilder->HkmSet3_Size - i;
		if(n > HkmSet3_CompUnit) { n = HkmSet3_CompUnit; }
		n = TinyLZ_compress(
			&pBuilder->TBL_HkmSet3_CompData[pBuilder->HkmSet3_CompData_Size],
			ARRAY_SIZE(pBuilder->TBL_HkmSet3_CompData) - pBuilder->HkmSet3_CompData_Size,
			&pBuilder->TBL_HkmSet3[i], n * (SlotPos_Max+1));
		pBuilder->TBL_HkmSet3_CompSize[i / HkmSet3_CompUnit] = n;
//{{2016/07/24追加:Slot_BuildStpCtl()にて、TinyLZ_compress()の結果が256以上になった時に、正しくはエラー停止すべき所、そのまま(unsigned char)配列に格納してしまい、間違ったデータが生成されていたバグを修正しました。修正方法としては、格納する前に(n<256)を検査しても良かったのですが、もし今後(unsigned char)配列を(unsigned short)配列に変更する場合に備えて、格納後に元の値と同じかを比較して検査する事にしました。
		if(pBuilder->TBL_HkmSet3_CompSize[i / HkmSet3_CompUnit] != n) { DIE(); }	//ここで停止した場合は、HkmSet3_CompUnitを減らして下さい。
//}}2016/07/24追加:Slot_BuildStpCtl()にて、TinyLZ_compress()の結果が256以上になった時に、正しくはエラー停止すべき所、そのまま(unsigned char)配列に格納してしまい、間違ったデータが生成されていたバグを修正しました。修正方法としては、格納する前に(n<256)を検査しても良かったのですが、もし今後(unsigned char)配列を(unsigned short)配列に変更する場合に備えて、格納後に元の値と同じかを比較して検査する事にしました。
		if((pBuilder->HkmSet3_CompData_Size += n) > ARRAY_SIZE(pBuilder->TBL_HkmSet3_CompData)) { DIE(); }
	}
	/* 停止制御データのメモリを確保する。(1個のメモリブロックとして確保する。解放時も1個のメモリブロックとして開放せよ。) */
	p = calloc(1, sizeof(ST_Slot_StpCtl) +
		(pInfo->HitCd_Size * 3) +						/* TBL_StpCtl1 */
		(pInfo->HitCd_Size * 6) +						/* TBL_StpCtl2 */
		(pInfo->HitCd_Size * 6) +						/* TBL_StpCtl3 */
		((pBuilder->HkmSet1_Size + HkmSet1_CompUnit - 1) / HkmSet1_CompUnit) +	/* TBL_HkmSet1_CompSize */
		((pBuilder->HkmSet2_Size + HkmSet2_CompUnit - 1) / HkmSet2_CompUnit) +	/* TBL_HkmSet2_CompSize */
		((pBuilder->HkmSet3_Size + HkmSet3_CompUnit - 1) / HkmSet3_CompUnit) +	/* TBL_HkmSet3_CompSize */
		pBuilder->HkmSet1_CompData_Size +					/* TBL_HkmSet1_CompData */
		pBuilder->HkmSet2_CompData_Size +					/* TBL_HkmSet2_CompData */
		pBuilder->HkmSet3_CompData_Size);					/* TBL_HkmSet3_CompData */
	if(!p) { DIE(); }
	pStpCtl                       = (void*)p;   p += sizeof(ST_Slot_StpCtl);
	pStpCtl->TBL_StpCtl1          = (void*)p;   p += (pInfo->HitCd_Size * 3);
	pStpCtl->TBL_StpCtl2          = (void*)p;   p += (pInfo->HitCd_Size * 6);
	pStpCtl->TBL_StpCtl3          = (void*)p;   p += (pInfo->HitCd_Size * 6);
	pStpCtl->TBL_HkmSet1_CompSize = (void*)p;   p += ((pBuilder->HkmSet1_Size + HkmSet1_CompUnit - 1) / HkmSet1_CompUnit);
	pStpCtl->TBL_HkmSet2_CompSize = (void*)p;   p += ((pBuilder->HkmSet2_Size + HkmSet2_CompUnit - 1) / HkmSet2_CompUnit);
	pStpCtl->TBL_HkmSet3_CompSize = (void*)p;   p += ((pBuilder->HkmSet3_Size + HkmSet3_CompUnit - 1) / HkmSet3_CompUnit);
	pStpCtl->TBL_HkmSet1_CompData = (void*)p;   p += pBuilder->HkmSet1_CompData_Size;
	pStpCtl->TBL_HkmSet2_CompData = (void*)p;   p += pBuilder->HkmSet2_CompData_Size;
	pStpCtl->TBL_HkmSet3_CompData = (void*)p; //p += pBuilder->HkmSet3_CompData_Size;
	/* 停止制御データを格納する。 */
	pStpCtl->HitCd_Size            =    pInfo->HitCd_Size;
	pStpCtl->HkmSet1_CompUnit      =           HkmSet1_CompUnit;
	pStpCtl->HkmSet2_CompUnit      =           HkmSet2_CompUnit;
	pStpCtl->HkmSet3_CompUnit      =           HkmSet3_CompUnit;
	pStpCtl->HkmSet1_Size          = pBuilder->HkmSet1_Size;
	pStpCtl->HkmSet2_Size          = pBuilder->HkmSet2_Size;
	pStpCtl->HkmSet3_Size          = pBuilder->HkmSet3_Size;
	pStpCtl->HkmSet1_CompData_Size = pBuilder->HkmSet1_CompData_Size;
	pStpCtl->HkmSet2_CompData_Size = pBuilder->HkmSet2_CompData_Size;
	pStpCtl->HkmSet3_CompData_Size = pBuilder->HkmSet3_CompData_Size;
	memcpy((void*)pStpCtl->TBL_StpCtl1, pBuilder->TBL_StpCtl1, (pInfo->HitCd_Size * 3));									//キャストはconst警告抑制のため
	memcpy((void*)pStpCtl->TBL_StpCtl2, pBuilder->TBL_StpCtl2, (pInfo->HitCd_Size * 6));									//キャストはconst警告抑制のため
	memcpy((void*)pStpCtl->TBL_StpCtl3, pBuilder->TBL_StpCtl3, (pInfo->HitCd_Size * 6));									//キャストはconst警告抑制のため
	memcpy((void*)pStpCtl->TBL_HkmSet1_CompSize, pBuilder->TBL_HkmSet1_CompSize, ((pBuilder->HkmSet1_Size + HkmSet1_CompUnit - 1) / HkmSet1_CompUnit));	//キャストはconst警告抑制のため
	memcpy((void*)pStpCtl->TBL_HkmSet2_CompSize, pBuilder->TBL_HkmSet2_CompSize, ((pBuilder->HkmSet2_Size + HkmSet2_CompUnit - 1) / HkmSet2_CompUnit));	//キャストはconst警告抑制のため
	memcpy((void*)pStpCtl->TBL_HkmSet3_CompSize, pBuilder->TBL_HkmSet3_CompSize, ((pBuilder->HkmSet3_Size + HkmSet3_CompUnit - 1) / HkmSet3_CompUnit));	//キャストはconst警告抑制のため
	memcpy((void*)pStpCtl->TBL_HkmSet1_CompData, pBuilder->TBL_HkmSet1_CompData, pBuilder->HkmSet1_CompData_Size);						//キャストはconst警告抑制のため
	memcpy((void*)pStpCtl->TBL_HkmSet2_CompData, pBuilder->TBL_HkmSet2_CompData, pBuilder->HkmSet2_CompData_Size);						//キャストはconst警告抑制のため
	memcpy((void*)pStpCtl->TBL_HkmSet3_CompData, pBuilder->TBL_HkmSet3_CompData, pBuilder->HkmSet3_CompData_Size);						//キャストはconst警告抑制のため
	/* 停止制御データビルダのメモリを開放する。 */
	free(pBuilder);
	/* 停止制御データのメモリを返す。呼出側で開放せよ。 */
	return pStpCtl;
}
/*--------------------------------------------------------------------------*/
void Slot_PrintStpCtl(const ST_Slot_StpCtl* pStpCtl, FILE* fpH, FILE* fpC) {
	int iHitCd, iOrder, i;
	//1リール停止制御データを出力する。
	fprintf(fpC, "static const unsigned char TBL_StpCtl1[/*HitCd_Size*/][3]/*[(SlotPos_Max+1)]*/={//⇒(TBL_HkmSet1_CompSize,TBL_HkmSet1_CompData)\n");
	for(iHitCd = 0; iHitCd < pStpCtl->HitCd_Size; iHitCd++) {
		fprintf(fpC, "{");
		for(iOrder = 0; iOrder < 3; iOrder++) {
			if(iOrder) { fprintf(fpC, ","); }
			fprintf(fpC, "%3d", pStpCtl->TBL_StpCtl1[iHitCd][iOrder]);
		}
		fprintf(fpC, "},//%2d\n", iHitCd);
	}
	fprintf(fpC, "};\n");
	//2リール停止制御データを出力する。
	fprintf(fpC, "static const unsigned char TBL_StpCtl2[/*HitCd_Size*/][6]/*[(SlotPos_Max+1)][(SlotPos_Max+1)]*/={//⇒{TBL_HkmSet2_CompSize,TBL_HkmSet2_CompData}⇒(TBL_HkmSet1_CompSize,TBL_HkmSet1_CompData)\n");
	for(iHitCd = 0; iHitCd < pStpCtl->HitCd_Size; iHitCd++) {
		fprintf(fpC, "{");
		for(iOrder = 0; iOrder < 6; iOrder++) {
			if(iOrder) { fprintf(fpC, ","); }
			fprintf(fpC, "%3d", pStpCtl->TBL_StpCtl2[iHitCd][iOrder]);
		}
		fprintf(fpC, "},//%2d\n", iHitCd);
	}
	fprintf(fpC, "};\n");
	//3リール停止制御データを出力する。
	fprintf(fpC, "static const unsigned char TBL_StpCtl3[/*HitCd_Size*/][6]/*[(SlotPos_Max+1)][(SlotPos_Max+1)][(SlotPos_Max+1)]*/={//⇒(TBL_HkmSet3_CompSize,TBL_HkmSet3_CompData)⇒(TBL_HkmSet2_CompSize,TBL_HkmSet2_CompData)⇒(TBL_HkmSet1_CompSize,TBL_HkmSet1_CompData)\n");
	for(iHitCd = 0; iHitCd < pStpCtl->HitCd_Size; iHitCd++) {
		fprintf(fpC, "{");
		for(iOrder = 0; iOrder < 6; iOrder++) {
			if(iOrder) { fprintf(fpC, ","); }
			fprintf(fpC, "%3d", pStpCtl->TBL_StpCtl3[iHitCd][iOrder]);
		}
		fprintf(fpC, "},//%2d\n", iHitCd);
	}
	fprintf(fpC, "};\n");
	//引込セット1を出力する。
	fprintf(fpC, "static const unsigned char TBL_HkmSet1_CompSize[/*(HkmSet1_Size+HkmSet1_CompUnit-1)/HkmSet1_CompUnit*/]={\n");
	for(i = 0; i < pStpCtl->HkmSet1_Size; i += pStpCtl->HkmSet1_CompUnit) {
		fprintf(fpC, "%3d,//%2d %3d-%3d\n",
			pStpCtl->TBL_HkmSet1_CompSize[i/pStpCtl->HkmSet1_CompUnit],
			                             (i/pStpCtl->HkmSet1_CompUnit),
			i, (((i+pStpCtl->HkmSet1_CompUnit)<pStpCtl->HkmSet1_Size)?(i+pStpCtl->HkmSet1_CompUnit):pStpCtl->HkmSet1_Size)-1);
	}
	fprintf(fpC, "};\n");
	fprintf(fpC, "static const unsigned char TBL_HkmSet1_CompData[/*HkmSet1_CompData_Size*/]={");
	for(i = 0; i < pStpCtl->HkmSet1_CompData_Size; i++) {
		if(!(i&15)) { fprintf(fpC, "\n"); }
		fprintf(fpC, "%3d,", pStpCtl->TBL_HkmSet1_CompData[i]);
		if(((i&15)==15) || (i==(pStpCtl->HkmSet1_CompData_Size-1))) { fprintf(fpC, "//%4d-%4d", (i&~15), i); }
	}
	fprintf(fpC, "\n};\n");
	//引込セット2を出力する。
	fprintf(fpC, "static const unsigned char TBL_HkmSet2_CompSize[/*(HkmSet2_Size+HkmSet2_CompUnit-1)/HkmSet2_CompUnit*/]={\n");
	for(i = 0; i < pStpCtl->HkmSet2_Size; i += pStpCtl->HkmSet2_CompUnit) {
		fprintf(fpC, "%3d,//%2d %3d-%3d\n",
			pStpCtl->TBL_HkmSet2_CompSize[i/pStpCtl->HkmSet2_CompUnit],
			                             (i/pStpCtl->HkmSet2_CompUnit),
			i, (((i+pStpCtl->HkmSet2_CompUnit)<pStpCtl->HkmSet2_Size)?(i+pStpCtl->HkmSet2_CompUnit):pStpCtl->HkmSet2_Size)-1);
	}
	fprintf(fpC, "};\n");
	fprintf(fpC, "static const unsigned char TBL_HkmSet2_CompData[/*HkmSet2_CompData_Size*/]={");
	for(i = 0; i < pStpCtl->HkmSet2_CompData_Size; i++) {
		if(!(i&15)) { fprintf(fpC, "\n"); }
		fprintf(fpC, "%3d,", pStpCtl->TBL_HkmSet2_CompData[i]);
		if(((i&15)==15) || (i==(pStpCtl->HkmSet2_CompData_Size-1))) { fprintf(fpC, "//%4d-%4d", (i&~15), i); }
	}
	fprintf(fpC, "\n};\n");
	//引込セット3を出力する。
	fprintf(fpC, "static const unsigned char TBL_HkmSet3_CompSize[/*(HkmSet3_Size+HkmSet3_CompUnit-1)/HkmSet3_CompUnit*/]={\n");
	for(i = 0; i < pStpCtl->HkmSet3_Size; i += pStpCtl->HkmSet3_CompUnit) {
		fprintf(fpC, "%3d,//%2d %3d-%3d\n",
			pStpCtl->TBL_HkmSet3_CompSize[i/pStpCtl->HkmSet3_CompUnit],
			                             (i/pStpCtl->HkmSet3_CompUnit),
			i, (((i+pStpCtl->HkmSet3_CompUnit)<pStpCtl->HkmSet3_Size)?(i+pStpCtl->HkmSet3_CompUnit):pStpCtl->HkmSet3_Size)-1);
	}
	fprintf(fpC, "};\n");
	fprintf(fpC, "static const unsigned char TBL_HkmSet3_CompData[/*HkmSet3_CompData_Size*/]={");
	for(i = 0; i < pStpCtl->HkmSet3_CompData_Size; i++) {
		if(!(i&15)) { fprintf(fpC, "\n"); }
		fprintf(fpC, "%3d,", pStpCtl->TBL_HkmSet3_CompData[i]);
		if(((i&15)==15) || (i==(pStpCtl->HkmSet3_CompData_Size-1))) { fprintf(fpC, "//%4d-%4d", (i&~15), i); }
	}
	fprintf(fpC, "\n};\n");
	//停止制御データを出力する。
	fprintf(fpH, "extern const ST_Slot_StpCtl stStpCtl;\n");
	fprintf(fpC,        "const ST_Slot_StpCtl stStpCtl={\n");
	fprintf(fpC, "%4d,//HitCd_Size\n",            pStpCtl->HitCd_Size);
	fprintf(fpC, "%4d,//HkmSet1_CompUnit\n",      pStpCtl->HkmSet1_CompUnit);
	fprintf(fpC, "%4d,//HkmSet2_CompUnit\n",      pStpCtl->HkmSet2_CompUnit);
	fprintf(fpC, "%4d,//HkmSet3_CompUnit\n",      pStpCtl->HkmSet3_CompUnit);
	fprintf(fpC, "%4d,//HkmSet1_Size\n",          pStpCtl->HkmSet1_Size);
	fprintf(fpC, "%4d,//HkmSet2_Size\n",          pStpCtl->HkmSet2_Size);
	fprintf(fpC, "%4d,//HkmSet3_Size\n",          pStpCtl->HkmSet3_Size);
	fprintf(fpC, "%4d,//HkmSet1_CompData_Size\n", pStpCtl->HkmSet1_CompData_Size);
	fprintf(fpC, "%4d,//HkmSet2_CompData_Size\n", pStpCtl->HkmSet2_CompData_Size);
	fprintf(fpC, "%4d,//HkmSet3_CompData_Size\n", pStpCtl->HkmSet3_CompData_Size);
	fprintf(fpC, "TBL_StpCtl1,\n");
	fprintf(fpC, "TBL_StpCtl2,\n");
	fprintf(fpC, "TBL_StpCtl3,\n");
	fprintf(fpC, "TBL_HkmSet1_CompSize,\n");
	fprintf(fpC, "TBL_HkmSet2_CompSize,\n");
	fprintf(fpC, "TBL_HkmSet3_CompSize,\n");
	fprintf(fpC, "TBL_HkmSet1_CompData,\n");
	fprintf(fpC, "TBL_HkmSet2_CompData,\n");
	fprintf(fpC, "TBL_HkmSet3_CompData,\n");
	fprintf(fpC, "};\n");
}
#endif//WIN32	//PC上で停止制御データを作成する時に使用します。P/ECE上では使用しません。

/****************************************************************************
 *	順序番号付き8byte形式コマンド
 ****************************************************************************/

//□テストスイート
//│void TestSuite(){
//│  unsigned char Buf[8+1];
//│  int sType,sData,rType,rData;
//│  for(;;){
//│    sType=(unsigned char)rand();
//│    sData=(unsigned char)rand()|(unsigned char)rand()<<8|(unsigned char)rand()<<16|(unsigned char)rand()<<24;
//│    Buf[8]=0x77;SlotCmd58_Encode(sType,sData,Buf);if(Buf[8]!=0x77){DIE();}
//│    if(!SlotCmd58_Decode(&rType,&rData,Buf)||rType!=sType||rData!=sData){DIE();}//正常ﾃｽﾄ
//│    Buf[rand()&7]^=0x80>>(rand()%3);if(SlotCmd58_Decode(&rType,&rData,Buf)){DIE();}//異常検出ﾃｽﾄ
//│} }

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

//┏━━格納━━┓
//Ｏｒｄ　　　　┃
//２１０　　　　┃
//●●●　　　　┃
//│││┏━Ｔｙｐｅ━┓┏━━━━━━━━━━━━━Ｄａｔａ━━━━━━━━━━━━━┓
//│││７６５４３２１０31302928272625242322212019181716151413121110９８７６５４３２１０
//●●●■■■■■□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
//　　　　　　　／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／
//　　　　　　／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／
//　　　　　／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／
//　　　　／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／
//　　　□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
#ifndef PIECE
void SlotCmd58_Encode(/*[in]*/int Type, /*[in]*/int Data, /*[out]*/void* _pBuf/*[8]*/) {
	unsigned char* pBuf = _pBuf;
	int Order;
	for(Order = 0; Order < 8; Order++) {
		*pBuf++ = (Order << 5) | ((unsigned char)Type >>  3);
		Type    = (Type  << 5) | ((unsigned     )Data >> 27);
		Data  <<=           5;
	}
}
#else //PIECE
void SlotCmd58_Encode(/*[in]*/int Type, /*[in]*/int Data, /*[out]*/void* _pBuf/*[8]*/);
asm("
		.code
		.align		1
		.global		SlotCmd58_Encode
SlotCmd58_Encode:
		ld.w		%r4, 0			;//%r4    :=    Order<<5  = 0<<5
		ld.ub		%r9, %r12		;//  %r9  :=               (unsigned char)Type			←┐
SlotCmd58_Encode_LOOP:					;//do {								　│
	;//	ld.ub		%r9, %r12		;//  %r9  :=               (unsigned char)Type			─┤
		sra		%r9, 3			;//  %r9  :=               (unsigned char)Type>>3		　│
		or		%r9, %r4		;//  %r9  :=   (Order<<5)|((unsigned char)Type>>3)		　│
		ld.b		[%r14]+, %r9		;//  *pBuf++ = (Order<<5)|((unsigned char)Type>>3)		　│
		ld.w		%r9, 16			;//  %r9  := i = 1<<4						　│	←┐
		 add		%r13, %r13		;//  do {    %r13 := Data<<=1, %psr(C) := Data[31]		─│┐	　│
		 sra		%r9, 1			;//          %psr(Z) := !(i>>=1)				　││	←┼%psr(C)を変化させないために、ループカウンタにシフトを用いた。
		jrne.d		-2			;//  } while(%psr(Z))						　││	←┘
		adc		%r12, %r12		;//          %r12 := (Type<<1)|%psr(C)				←│┘	*delay*
		add		%r4, 32			;//  %r4  :=    Order<<5 += 1<<5				　│
		xcmp		%r4, 224		;//} while(     Order<<5 <= 7<<5)				　│
		jrle.d		SlotCmd58_Encode_LOOP	;//  								　│
		ld.ub		%r9, %r12		;//  %r9  :=               (unsigned char)Type			←┘	*delay*
		ret
");
#endif//PIECE

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

//　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　┏━━取得━━┓
//　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　Ｏｒｄ　　　　┃
//　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　２１０　　　　┃
//　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　●●●■■■■■
//　　　　　□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□／／／／／
//　　　　／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／
//　　　／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／
//　　／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／
//　／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／／
//□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□■■■■■
//７６５４３２１０31302928272625242322212019181716151413121110９８７６５４３２１０
//┗━Ｔｙｐｅ━┛┗━━━━━━━━━━━━━Ｄａｔａ━━━━━━━━━━━━━┛
#ifndef PIECE
int SlotCmd58_Decode(/*[out]*/int* pType, /*[out]*/int* pData, /*[in]*/const void* _pBuf/*[8]*/) {
	const unsigned char* pBuf = _pBuf;
	int Order, Type = 0, Data = 0;				//実際にはType[7:0],Data[31:0]は取得したビットが入るので初期化不要である。結果を格納する前にType[31:8]のみクリアすれば良い。Asm版は左記の方法で最適化した。
	for(Order = 0; Order < 8; Order++) {
		int c = *pBuf++;
		if((c >> 5) != Order) { return 0; }		//異常検出
		Type = (Type << 5) | ((unsigned)Data >> 27);
		Data = (Data << 5) | (          c    &  31);
	}
	*pType = Type;
	*pData = Data;
	return 1;						//正常
}
#else //PIECE
int SlotCmd58_Decode(/*[out]*/int* pType, /*[out]*/int* pData, /*[in]*/const void* _pBuf/*[8]*/);
asm("
		.code
		.align		1
		.global		SlotCmd58_Decode
SlotCmd58_Decode:
		ld.w		%r10, 0			;//%r10   := result = 0
		ld.w		%r4, 0			;//%r4    := Order =  0
SlotCmd58_Decode_LOOP:					;//do {
		ld.ub		%r5, [%r14]+		;//  %r5      := c = *pBuf++
		rr		%r5, 5			;//  %r5[2:0] := c[7:5], %r5[31:27] := c[4:0]
		ld.ub		%r9, %r5		;//  %r9      := c[7:5]
		cmp		%r9, %r4		;//  if(c[7:5] != Order) { return 0 }
		jrne		SlotCmd58_Decode_RET	;//  
		ld.w		%r9, 16			;//  %r9  := i = 1<<4						─┐
		 add		%r5, %r5		;//  do {    %r5  :=    c<<=1,          %psr(C) :=    c[31]	　│
		 adc		%r6, %r6		;//          %r6  := (Data<<1)|%psr(C), %psr(C) := Data[31]	　│
		 sra		%r9, 1			;//          %psr(Z) := !(i>>=1)				←┼%psr(C)を変化させないために、ループカウンタにシフトを用いた。
		jrne.d		-3			;//  } while(%psr(Z))						←┘
		adc		%r7, %r7		;//          %r7  := (Type<<1)|%psr(C)				*delay*
		cmp		%r4, 6			;//} while(  Order <= 6)
		jrle.d		SlotCmd58_Decode_LOOP	;//  
		add		%r4, 1			;//  %r4  := Order++						*delay*
		ld.ub		%r7, %r7		;//%r7    := Type = (unsigned char)Type
		ld.w		[%r12], %r7		;//*pType  = Type
		ld.w		[%r13], %r6		;//*pData  = Data
		ld.w		%r10, 1			;//%r10   := result = 1
SlotCmd58_Decode_RET:
		ret					;//return    result
");
#endif//PIECE
