/*	
 *	clipreg.c
 *
 *	レジストリテーブル
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2015-2016 Naoyuki Sawa
 *
 *	* Tue Mar 24 02:10:47 JST 2015 Naoyuki Sawa
 *	- 1st リリース。
 *	* Tue Mar 24 21:45:37 JST 2015 Naoyuki Sawa
 *	- REG_open_key(),及び,REG_get_value()に、(keyBody=NULL)を指定しても安全にしました。
 *	  REG_open_key_v()とREG_get_value_v()の処理の大部分を共通化してコード削減しました。
 *	* Thu Mar 26 21:28:16 JST 2015 Naoyuki Sawa
 *	- dRegTblC.exeの出力データ構造を変更した事に伴い、当モジュールも大幅に変更しました。
 *	  前回まではキー配列をリニアサーチしていましたが、今後はバイナリサーチになりました。
 *	  詳細は、「clip/tool/dRegTblC/winapp.h」の同日のコメントを参照してください。
 *	* Sat Apr 11 13:20:40 JST 2015 Naoyuki Sawa
 *	 - 文字列のデータタイプを追加し、大幅な変更を行いました。
 *	   変更前のコードを参照するには、前回のアーカイブを参照してください。
 *	* Mon Jul 27 21:32:15 JST 2015 Naoyuki Sawa
 *	- REG_open_key_v()の処理を修正しました。修正内容は、以下の通りです:
 *	  'REG_open_key_l(keyBody,-1)'に対して、これまではNULLを返していました。(keyBody)自身を返すのが自然であると思うので、そのように修正しました。
 *	- 既に、clipfsm.c の FsmObj_GetTransKey() にて、'REG_open_key_l(keyBody,-1)'が(keyBody)自身を返す事を期待したコードを書いてしまっていました。
 *	  これまでは、'REG_open_key_l(keyBody,-1)'がNULLを返していたので、FsmObj_GetTransKey() が正しく動作していませんでした。
 *	  今回、'REG_open_key_l(keyBody,-1)'が(keyBody)自身を返すように修正したので、FsmObj_GetTransKey() が正しく動作するようになりました。
 *	- 上記の修正を、REG_open_get_v()やREG_open_key()ではなく、REG_open_key_v()で行った理由は、影響範囲を小さく留めるためです。
 *	  REG_open_get_v()やREG_open_key()は、他の関数との共通性のために、(keyName=-1)を終端と見なす特例処理を行いたくありません。
 *	  特例処理は、呼び出し階層の浅い部分で行う方が安全だと考えて、REG_open_key_v()で行う事にしました。
 *	* Tue Sep 22 12:15:09 JST 2015 Naoyuki Sawa
 *	- 「インデクスアクセス型,及び,イテレーション用の関数」を追加しました。
 *	- インデクスアクセス型の関数を使用して、イテレーションを行う例を示します。
 *	  □TBL_RegTbl->RegKey_X->RegKey_Yに属する値をｲﾃﾚｰﾄする｡TBL_RegTbl->RegKey_X->RegKey_Yが存在しなくても安全です｡
 *	  │for(index=0;
 *	  │    (valueData=REG_get_nth_value_l(TBL_RegTbl,index,&valueName,RegKey_X,RegKey_Y,-1))!=-1;
 *	  │    index++){
 *	  │      printf("%d:%d=>%d\n",index,valueName,valueData);
 *	  │}
 *	* Sun Oct 04 21:01:44 JST 2015 Naoyuki Sawa
 *	- 大幅な変更を行いました。
 *	  変更前のコードはソースの中に残していないので、必要ならば前回までのソースを参照してください。
 *	  変更前のソースとツールを'keep/17_レジストリテーブル形式変更前保存/'に保存しておきました。
 *	- 変更点は以下の通りです。
 *	  ①'値'データが24ビット符号無しの値を返せるようにしました。これまでは16ビット符号無しの値しか返せませんでした。
 *	  ②'BLOB'タイプを追加しました。これまでは'BLOB'タイプが無く、複数の値に分割して格納していました。
 *	  ③配列の要素数の上限が65536になりました。これまでは配列の要素数の上限が65535でした。
 *	- 既存の関数仕様には変更有りません。'BLOB'タイプの関数を追加しました。
 *	  レジストリテーブルのバイナリフォーマットは互換性は有りません。
 *	- 今回の変更により、全てのタイプのデータが24ビットに統一されました。新しいタイプを追加する事も容易だと思います。
 *	  マスクのビットも4ビット残っているので、あと4種類は容易に増やせます。詳細はREG_op()のmask変数を参照して下さい。
 *	* Wed Oct 07 21:27:19 JST 2015 Naoyuki Sawa
 *	- REG_get_blob_size()を追加しました。
 *	* Thu Oct 08 21:52:46 JST 2015 Naoyuki Sawa
 *	- BLOBのデータ構造を少し変更しました。
 *	  これまでは、BLOBのサイズに(データ本体のバイト数)を格納していましたが、今後は、(データ本体のバイト数-1)を格納します。
 *	  他のフィールドには(要素数-1)を格納しているので、BLOBのサイズもそれらに合わせて統一する方が判り易いと思ったからです。
 *	* Fri Oct 09 22:14:58 JST 2015 Naoyuki Sawa
 *	- REG_op()を高速化しました。
 *	  これまでは汎用のbsearch()を利用していましたが、REG_op()からの利用に特化して高速化したREG_bsearch()を作成してそれを呼び出すようにしました。
 *	  厳密な計測ではありませんが、REG_op()を呼び出す関数の動作が、3倍ぐらい早くなったみたいです。
 *	* Wed Oct 14 21:21:55 JST 2015 Naoyuki Sawa
 *	- 警告抑制のためにREG_bsearch()のC言語版の実装を修正しました。
 *	  動作内容は変わっていません。
 *	* Thu Oct 29 21:30:16 JST 2015 Naoyuki Sawa
 *	- REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
 *	- 上記のREG_op()のバグの影響で、clipfsm.cのFsmObj_ApplyTrans()が正しく動作していませんでした。
 *	  FsmObj_ApplyTrans()の処理で、(pKey=NULL)に対してiFnGrd,iFnAct,iStNexを取得しようとした時に、正しくは(-1)を返すべきところ、NULLアドレス付近のメモリが偶然キーに一致すると、値が取得できたと見なしてしまい間違った値を返してしまうからです。
 *	  今回の修正によって、FsmObj_ApplyTrans()が正しく動作するようになりました。
 *	* Thu May 12 22:56:34 JST 2016 Naoyuki Sawa
 *	- 「要素数を取得する関数」を追加しました。理由は以下の通りです。
 *	  要素数を取得する方法は、既存の「インデクスアクセス型,及び,イテレーション用の関数」を使って、NULL,又は,-1が返されるまでindexを増やしながらループする方法も有るのですが、その方法では要素数が多いと時間が掛かってしまうという問題が有ります。
 *	  要素数が多くても高速に要素数を取得したいケースが生じたので、明示的に要素数を取得する関数群を追加する事にしました。
 *	* Mon Sep 05 21:24:05 JST 2016 Naoyuki Sawa
 *	- 64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
 *	  主な変更点は、REG_op(),及び,REG_nth()が返す値のビット数が32ビット版と64ビット版で異なる点を、REG_data_addr型の定義によって吸収した事です。
 *	  尚、ソース内のコメントが、32ビット版のビット数だけで説明していて、64ビット版のビット数では説明していない箇所が多いままですが(REG_get_value()等)、
 *	  64ビット版での動作も自明であり、64ビット版の説明を追記すると却って判りづらくなりそうだったので、64ビット版のビット数での説明は追記していません。
 *	- 既存の32ビット版の動作には、影響有りません。
 *	  従って、P/ECEのアセンブラ版のコードも、一切変更していません。
 */
#include "clip.h"
//{{2016/09/05追加:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
/****************************************************************************
 *	32ビット版と64ビット版のソースを共通化するための型定義
 ****************************************************************************/
//32ビット版
// - 32ビット版と64ビット版のソースを共通化するために、dataとaddrをパックする型を定義しました。
//   これまでは各関数内で個別に行っていた処理をマクロ化しただけで、処理内容は変わっていません。
#ifndef _WIN64
typedef uint64_t REG_data_addr;		//[63:32]=data,[31:0]=addr
#define REG_unpack_data(data_addr)	((int)((data_addr)>>32))
#define REG_unpack_addr(data_addr)	((const void*)(int)(data_addr))
#define REG_pack_data_addr(data,addr)	(((uint64_t)(unsigned)(data))<<32)|((uint64_t)(unsigned)(addr))
#else //_WIN64				//          ~~~~~~~~~~このキャストを行わなくても結果は同じになるのだが、無駄な符号拡張を行うコードが生成されないように明示的に符号無しにキャストした。
/*--------------------------------------------------------------------------*/
//64ビット版
// - 64ビット版では、dataとaddrをパックして64ビットを超える値に出来ないので、構造体にしました。
//   これまでと処理内容は異なりますが、マクロ定義によって32ビット版と共通のソースにしています。
typedef struct _REG_data_addr {
	int		data;
	const void*	addr;
} REG_data_addr;
#define REG_unpack_data(data_addr)	((data_addr).data)
#define REG_unpack_addr(data_addr)	((data_addr).addr)
#define REG_pack_data_addr(data,addr)	((REG_data_addr){(data),(addr)})	//VS2015では、Cソース内で左記のGCC拡張構文と同じ書き方が、出来るようになった。
#endif//_WIN64
/*--------------------------------------------------------------------------*/
//ソースを簡潔にするため、頻繁に使用する値を、マクロ定義しました。
#define REG_pack_data_0			REG_pack_data_addr(0,NULL)
//}}2016/09/05追加:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
/****************************************************************************
 *	辞書アクセス型の関数
 ****************************************************************************/
/*==========================================================================*
 *	基本的な関数
 *==========================================================================*/
#ifndef PIECE
//REG_op()からの利用に特化して高速化したバイナリサーチ関数です。
//アルゴリズムや最適化の工夫はcliplibc.cのbsearch()の実装と同じです。
//{{2015/10/14修正:警告抑制のためにREG_bsearch()のC言語版の実装を修正しました。動作内容は変わっていません。
//static const uint8_t* REG_bsearch(const uint8_t* addr, int name, int n/*>=0*/) {
//	int nameL, nameH;
//	nameL  = (uint8_t)name;
//	name >>= 8;
//	nameH  = (uint8_t)name;
//	name >>= 8;
//	if(!name) {	//名前は符号無し16ビットである。範囲外の名前が指定された場合に下位16bitが偶然一致しないように、上位16ビットが0でなければ先に除外する。
//		goto L_START;
//		do {
//			const uint8_t* mid = addr + ((n >> 1) * (2/*name*/+3/*data*/));
//			int diff = mid[0/*nameH*/] - nameH;
//			if(!diff) {
//				diff = mid[1/*nameL*/] - nameL;
//				if(!diff) { return &mid[2/*data*/]; }	//見つかったらdataへのポインタを返す。
//			}
//			if(diff < 0) {
//				addr = mid + (2/*name*/+3/*data*/);
//				n--;
//			}
//			n >>= 1;
//L_START:		;
//		} while(n);
//	}
//	return NULL;	//見つからなければNULLを返す。
//}
//↓2015/10/14修正:警告抑制のためにREG_bsearch()のC言語版の実装を修正しました。動作内容は変わっていません。
// * Wed Oct 14 21:21:55 JST 2015 Naoyuki Sawa
// - 警告抑制のためにREG_bsearch()のC言語版の実装を修正しました。
//   動作内容は変わっていません。
// - C言語の仕様では、変数宣言を含むブロックの途中へ、そのブロック外からgotoで飛び込む事は禁止されていました。
//   □参照資料
//   │『ISO/IEC 9899:TC2 Programming languages - C』(http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf)
//   │「6.8.6.1 The goto statement - 4 EXAMPLE 2」(p.138)
//   上記の変更前のREG_bsearch()の実装は、その仕様に違反していました。
//   実際には、GCCやVC++6.0ではエラーも警告も出ずに、正しく動作します。
//   しかし、一部のコンパイラ(Hew)では警告が出ます。(動作は正しいです。)
//   いずれにしても動作上は問題無かったのですが、C言語の仕様に違反しているのは良くないので、修正する事にしました。
static const uint8_t* REG_bsearch(const uint8_t* addr, int name, int n/*>=0*/) {
	int nameL, nameH, diff;
	const uint8_t* mid;
	nameL  = (uint8_t)name;
	name >>= 8;
	nameH  = (uint8_t)name;
	name >>= 8;
	if(!name) {	//名前は符号無し16ビットである。範囲外の名前が指定された場合に下位16bitが偶然一致しないように、上位16ビットが0でなければ先に除外する。
		goto L_START;
		do {
			mid = addr + ((n >> 1) * (2/*name*/+3/*data*/));
			diff = mid[0/*nameH*/] - nameH;
			if(!diff) {
				diff = mid[1/*nameL*/] - nameL;
				if(!diff) { return &mid[2/*data*/]; }	//見つかったらdataへのポインタを返す。
			}
			if(diff < 0) {
				addr = mid + (2/*name*/+3/*data*/);
				n--;
			}
			n >>= 1;
L_START:		;
		} while(n);
	}
	return NULL;	//見つからなければNULLを返す。
}
//}}2015/10/14修正:警告抑制のためにREG_bsearch()のC言語版の実装を修正しました。動作内容は変わっていません。
//{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
//static uint64_t REG_op(const uint8_t* addr, int name, int type) {
//↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
static REG_data_addr REG_op(const uint8_t* addr, int name, int type) {
//}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	int mask, n, data;
    //{{2015/10/29追加:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
	//NULLアドレスに対する呼び出しならば要素が無いのと同じと見なして帰る。
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	if(!addr) { return 0; }
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	if(!addr) { return REG_pack_data_0; }
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //}}2015/10/29追加:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
	//このキーボディが持っている配列タイプのマスクを取得する。
	// - bit31=キー,bit30=値,bit29=文字列,bit28=BLOB,bit27～24=0(未使用),bit27～0=0
	mask = *addr++ << 24;								//アセンブラでは'rr 8'と出来る。
	for(;;) {
		//このキーボディがこのタイプの配列を持っていたら…
		if(mask < 0) {								//←┐
			mask <<= 1;							//←┤
			//配列の(要素数-1)を取得する。					//　│
			n   = *addr++;	//┐						//　│
			n <<= 8;	//├符号無し16ビット,ビッグエンディアン		//　│
			n  |= *addr++;	//┘						//　│
			//(要素数-1)⇒要素数に変換する。				//　│アセンブラでは'add %r(mask),%r(mask); jrult 2; jreq RET'と出来る。	{{2015/10/05追記:実際には他の処理との兼ね合いで左記のとおりのコードにはならなかった。REG_op_LOOPの下あたりのコードを参照せよ。}}
			n++;								//　│'(mask<0)'と2箇所の'mask<<=1'はアセンブラでは1命令にまとめられる。
		//このキーボディがこのタイプの配列を持っていなければ…			//　│
		} else {								//　│
			mask <<= 1;							//←┤
			//このキーボディが持っている配列タイプが残っていなければ帰る。	//　│
			// - アセンブラでは戻り値のbit63～32は不定値で構いません。	//　│
		    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
		    //	if(!mask) { return 0; }						//←┘
		    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
			if(!mask) { return REG_pack_data_0; }				//←┘
		    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
			//配列の要素数を0とする。
			n = 0;
		}
		//この配列が指定されたタイプの配列ならば抜ける。
		if(--type < 0) { break; }
		//この配列をスキップする。
		addr += n * (2/*name*/+3/*data*/);
	}
    {{//--- REG_op()とREG_nth()とで処理の違いはこの範囲だけです。 ---
	//この配列から指定された名前に一致する要素を検索する。
	addr = REG_bsearch(addr, name, n);	//見つかったらdataへのポインタが返される。見つからなければNULLが返される。
	//指定された名前に一致する要素が見つからなければ帰る。
	// - アセンブラでは戻り値のbit63～32は不定値で構いません。
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	if(!addr) { return 0; }
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	if(!addr) { return REG_pack_data_0; }
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    }}//--- REG_op()とREG_nth()とで処理の違いはこの範囲だけです。 ---
	data   = (int8_t)*addr++;		//┐
	data <<= 8;				//│
	data  |=         *addr++;		//├符号付き24ビット,ビッグエンディアン		符号付き24ビットでアドレスに加算した後、符号無し24ビットに変換する。
	data <<= 8;				//│
	data  |=         *addr++;		//┘
	addr  += data;				//アドレス					REG_get_value()から呼び出された場合は使用しない。
	data   = (unsigned)(data << 8) >> 8;	//データ					符号無し24ビット
	//戻り値 bit63～32 = データ(符号無し24ビット)	REG_get_value()から呼び出された場合はこっちを使う。
	//       bit31～ 0 = アドレス			REG_get_value()以外から呼び出された場合はこっちを使う。
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	return (((uint64_t)(unsigned)data) << 32) | ((uint64_t)(unsigned)addr);
    //	//                 ~~~~~~~~~~このキャストを行わなくても結果は同じになるのだが、無駄な符号拡張を行うコードが生成されないように明示的に符号無しにキャストした。
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	return REG_pack_data_addr(data, addr);
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
/*--------------------------------------------------------------------------*/
const uint8_t* REG_open_key(const uint8_t* keyBody, int keyName) {
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	return (const uint8_t*)(int)REG_op(keyBody, keyName, 0/*キー*/);		//REG_op()の戻り値のbit31～0を返す。
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	REG_data_addr data_addr = REG_op(keyBody, keyName, 0/*キー*/);
	return REG_unpack_addr(data_addr);						//REG_op()の戻り値のbit31～0を返す。
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
int REG_get_value(const uint8_t* keyBody, int valueName) {
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	uint64_t data_addr = REG_op(keyBody, valueName, 1/*値*/);
    //	if(!(int)data_addr) { return -1; }						//REG_op()の戻り値のbit31～0が0ならば(-1)を返す。	//アセンブラでは'sub %r10,1; jrult RET'と出来る。
    //	return (int)(data_addr >> 32);							//REG_op()の戻り値のbit55～32を返す。			//アセンブラでは'ld.w %r10,%r11'と出来る。
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	REG_data_addr data_addr = REG_op(keyBody, valueName, 1/*値*/);
	if(!REG_unpack_addr(data_addr)) { return -1; }					//REG_op()の戻り値のbit31～0が0ならば(-1)を返す。	//アセンブラでは'sub %r10,1; jrult RET'と出来る。
	return REG_unpack_data(data_addr);						//REG_op()の戻り値のbit55～32を返す。			//アセンブラでは'ld.w %r10,%r11'と出来る。
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
const char* REG_get_string(const uint8_t* keyBody, int stringName) {
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	return (const char*)(int)REG_op(keyBody, stringName, 2/*文字列*/);		//REG_op()の戻り値のbit31～0を返す。
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	REG_data_addr data_addr = REG_op(keyBody, stringName, 2/*文字列*/);
	return REG_unpack_addr(data_addr);						//REG_op()の戻り値のbit31～0を返す。
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
const void* REG_get_blob(const uint8_t* keyBody, int  blobName) {
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	return (const void*)(int)REG_op(keyBody, blobName, 3/*BLOB*/);			//REG_op()の戻り値のbit31～0を返す。
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	REG_data_addr data_addr = REG_op(keyBody, blobName, 3/*BLOB*/);
	return REG_unpack_addr(data_addr);						//REG_op()の戻り値のbit31～0を返す。
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
#else //PIECE
const uint8_t* REG_open_key(const uint8_t* keyBody, int keyName);
int REG_get_value(const uint8_t* keyBody, int valueName);
const char* REG_get_string(const uint8_t* keyBody, int stringName);
const void* REG_get_blob(const uint8_t* keyBody, int  blobName);
asm("
		.code
		.align		1
		.global		REG_open_key
		.global		REG_get_value
		.global		REG_get_string
		.global		REG_get_blob
REG_open_key:
		;//%r12 := keyBody
		;//%r13 := keyName
		jp.d		REG_op					;//%r10 := addr
		ld.w		%r14, 0					;//%r14 := type = 0/*キー*/								*delay*
REG_get_value:
		;//%r12 := keyBody
		;//%r13 := valueName
		call.d		REG_op					;//%r11:%r10 := data:addr
		ld.w		%r14, 1					;//%r14 := type = 1/*値*/								*delay*
		sub		%r10, 1					;//if(--addr == -1) { return -1 }
		jrult		2					;//else {
		 ld.w		%r10, %r11				;//  %r10 := data
		ret							;//  return  data }
REG_get_string:
		;//%r12 := keyBody
		;//%r13 := stringName
		jp.d		REG_op					;//%r10 := addr
		ld.w		%r14, 2					;//%r14 := type = 2/*文字列*/								*delay*
REG_get_blob:
		;//%r12 := keyBody
		;//%r13 := blobName
		ld.w		%r14, 3					;//%r14 := type = 3/*BLOB*/
		;//-----------------------------------------------------;//
REG_op:
		;//%r12 := addr
		;//%r13 := name
		;//%r14 := type
	    ;//{{2015/10/29変更:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
	    ;//	ld.w		%r10, 0					;//%r10 := 0
	    ;//↓2015/10/29変更:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
		cmp		%r12, 0					;//if(!addr) { return 0 }
		jreq.d		REG_op_RET				;//
		ld.w		%r10, 0					;//%r10 := 0										*delay*
	    ;//}}2015/10/29変更:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
		ld.ub		%r4, [%r12]+				;//%r4  := mask = *addr++
		rr		%r4, 8					;//%r4[31:24] := mask
REG_op_LOOP:								;//for(;;) {
		add		%r4, %r4				;//  %psr(C) := mask[31], %r4  := mask <<= 1
		jruge		7					;//  if(%psr(C)) {
		 ld.ub		%r5, [%r12]+				;//    %r5  :=      nH
		 ld.ub		%r6, [%r12]+				;//    %r6  :=             nL
		 sla		%r5, 8					;//    %r5  :=      nH<<8
		 or		%r5, %r6				;//    %r5  := n = (nH<<8)|nL
		 jp.d		4					;//    %r5  := n++
		 add		%r5, 1					;//  } else {										*delay*
		  jreq		REG_op_RET				;//    if(!mask) { return 0 }
		  ld.w		%r5, 0					;//    %r5  := n = 0 }
		sub		%r14, 1					;//  %r14 := type--
		jrult		REG_op_BREAK				;//  if(type == -1) { break }
		add		%r12, %r5				;//  %r12 := addr + n * 1
		sla		%r5, 2					;//  %r5  :=        n * 4
		jp.d		REG_op_LOOP				;//}
		add		%r12, %r5				;//  %r12 := addr + n * 5 = addr + n * (2/*name*/+3/*data*/)				*delay*
REG_op_BREAK:
	    ;//{{---
		call.d		REG_bsearch				;//%r10    := addr = REG_bsearch(name, addr, n)
		ld.w		%r14, %r5				;//%r14    :=                                n						*delay*
		cmp		%r10, 0					;//if(!addr) {
		jreq		REG_op_RET				;//  return 0 }
	    ;//}}---
		ld.b		%r11, [%r10]+				;//%r11 :=            (int8_t)dataH
		ld.ub		%r12, [%r10]+				;//%r12 :=                              dataM
		ld.ub		%r13, [%r10]+				;//%r13 :=                                         dataL
		sla		%r11, 8					;//%r11 :=            (int8_t)dataH<<8
		or		%r11, %r12				;//%r11 :=           ((int8_t)dataH<<8)|dataM
		sla		%r11, 8					;//%r11 :=          (((int8_t)dataH<<8)|dataM)<<8
		or		%r11, %r13				;//%r11 := data  = ((((int8_t)dataH<<8)|dataM)<<8)|dataL
		add		%r10, %r11				;//%r10 := addr += data
		sll		%r11, 8					;//%r11 :=                  (data << 8)
REG_op_RET:								;//
		ret.d							;//%r11:%r10 := data:addr			(addr=0)の場合は(data=不定値)です
		srl		%r11, 8					;//%r11 := data = (unsigned)(data << 8) >> 8	途中でRETへjpした場合はダミー処理	*delay*
		;//-----------------------------------------------------;//
REG_bsearch:
		;//%r12 := addr
		;//%r13 := name
		;//%r14 := n
		ld.ub		%r4, %r13				;//%r4  := nameL  = (uint8_t)name
		sra		%r13, 8					;//%r13 := name >>= 8
		ld.ub		%r5, %r13				;//%r5  := nameH  = (uint8_t)name
		sra		%r13, 8					;//%r13 := name >>= 8
		jrne		REG_bsearch_RET0			;//if(!name) {
		jp.d		REG_bsearch_START			;//  goto L_START
		cmp		%r14, 0					;//  %psr(Z) := !n	────────────────────────────────┐	*delay*
REG_bsearch_LOOP:							;//  do {										│
		ld.w		%r6, %r14				;//    %r6  :=                n								│
		sra		%r6, 1					;//    %r6  :=                n >> 1							│
		add		%r10, %r6				;//    %r10 :=       addr + ((n >> 1) * 1)						│
		sla		%r6, 2					;//    %r6  :=               (n >> 1) * 4						│
		add		%r10, %r6				;//    %r10 := mid = addr + ((n >> 1) * 5) = addr + ((n >> 1) * (2/*name*/+3/*data*/))	│
		ld.ub		%r6, [%r10]+				;//    %r6  :=        mid[0/*nameH*/]				, %r10 := mid + 1	│
		sub		%r6, %r5				;//    %r6  := diff = mid[0/*nameH*/] - nameH				│		│	ここではインターロックしません。
		jrne		4					;//    if(!diff) {							│		│
		 ld.ub		%r6, [%r10]				;//      %r6  :=        mid[1/*nameL*/]		←───────────┤		│
		 sub		%r6, %r4				;//      %r6  := diff = mid[1/*nameL*/] - nameL				│		│	!INTERLOCK!
		 jreq		REG_bsearch_RET				;//      if(!diff) { return &mid[2/*data*/] } }				│		│
		jrge		4					;//    if(diff < 0) {							│		│
		 ld.w		%r12, %r10				;//      %r12 :=        mid + 1			←───────────┤		│
		 add		%r12, 4					;//      %r12 := addr = mid + 5 = mid + (2/*name*/+3/*data*/)		│		│
		 sub		%r14, 1					;//      %r14 := n-- }							│		│
		sra		%r14, 1					;//    %r14 := n >>= 1							│		│
REG_bsearch_START:							;//    									│		│
		jrne.d		REG_bsearch_LOOP			;//  } while(n)		←───────────────────────│───────┘
		ld.w		%r10, %r12				;//    %r10 := addr							│			*delay*
REG_bsearch_RET0:							;//}									│
		ld.w		%r10, -1				;//return  (-1+1)/*=NULL*/						│
REG_bsearch_RET:							;//									│
		ret.d							;//return  &mid[2/*data*/]						│
		add		%r10, 1					;//%r10 := &mid[2/*data*/]	←───────────────────┘			*delay*
");
#endif//PIECE
/*==========================================================================*
 *	ユーティリティ関数
 *==========================================================================*/
#ifndef PIECE
//{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
//static int REG_open_get_v(const uint8_t* keyBody, const int* names, int (*fn)(const uint8_t*, int)) {
//↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
static intptr_t REG_open_get_v(const uint8_t* keyBody, const int* names, intptr_t (*fn)(const uint8_t*, int)) {
//}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	int name = *names++;
	if(name != -1) {
		goto L_START;
		do {
			keyBody = REG_open_key(keyBody, name);	//(keyBody=NULL)が指定されたり、REG_open_key()がNULLを返して(keyBody=NULL)になっても、継続して安全です。
			name = *names++;
L_START:		;
		} while(*names != -1);
	}
	return (*fn)(keyBody, name);	//(keyBody=NULL)や(name=-1)の場合でも、この処理を実行して安全です。
}
/*--------------------------------------------------------------------------*/
const uint8_t* REG_open_key_l(const uint8_t* keyBody, ...) {
	va_list ap;
	va_start(ap, keyBody);
	keyBody = REG_open_key_a(keyBody, ap);
	va_end(ap);
	return keyBody;
}
const uint8_t* REG_open_key_a(const uint8_t* keyBody, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_open_key_v(keyBody, names);
}
const uint8_t* REG_open_key_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/) {
    //{{特例処理
	//「REG_open_key_l(keyBody,-1)」の形で呼び出された場合は、エラーとしてNULLを返すのではなく、keyBody自身を返す方が自然です。
	// - REG_open_get_v()を呼び出すと、REG_open_get_v()が誤ってエラーと判断してしまう。
	//   REG_open_get_v()に特例処理を追加するよりも、ここで判断する方が適切だと思うので、ここに特例処理を追加する事にしました。
	// - clipfsm.cのFsmObj_GetTransKey()が、この動作に依存しています。
	if(names[0] == -1) { return keyBody; }
    //}}特例処理
//{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
//	return (const uint8_t*)REG_open_get_v(keyBody, names, (int (*)(const uint8_t*, int))REG_open_key);
//↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	return (const uint8_t*)REG_open_get_v(keyBody, names, (intptr_t (*)(const uint8_t*, int))REG_open_key);
//}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
/*--------------------------------------------------------------------------*/
int REG_get_value_l(const uint8_t* keyBody, ...) {
	int valueData;
	va_list ap;
	va_start(ap, keyBody);
	valueData = REG_get_value_a(keyBody, ap);
	va_end(ap);
	return valueData;
}
int REG_get_value_a(const uint8_t* keyBody, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_get_value_v(keyBody, names);
}
//{{2016/09/05追加:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
#ifdef  _WIN64
//64ビット版では、REG_open_get_v()に指定する関数は常に64ビット値を返すと見なすために、
//REG_get_value()の戻り値(64ビット版でも32ビット値を返す)を、64ビット整数に符号拡張して返すだけの中継関数です。
static intptr_t REG_get_value_x64(const uint8_t* keyBody, int valueName) { return REG_get_value(keyBody, valueName); }
#endif//_WIN64
//}}2016/09/05追加:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
int REG_get_value_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]valueName,]-1*/) {
//{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
//	return REG_open_get_v(keyBody, names, REG_get_value);
//↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
#ifndef _WIN64
	return REG_open_get_v(keyBody, names, REG_get_value);
#else //_WIN64
	return REG_open_get_v(keyBody, names, REG_get_value_x64);
#endif//_WIN64
//}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
/*--------------------------------------------------------------------------*/
const char* REG_get_string_l(const uint8_t* keyBody, ...) {
	const char* stringData;
	va_list ap;
	va_start(ap, keyBody);
	stringData = REG_get_string_a(keyBody, ap);
	va_end(ap);
	return stringData;
}
const char* REG_get_string_a(const uint8_t* keyBody, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_get_string_v(keyBody, names);
}
const char* REG_get_string_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]stringName,]-1*/) {
//{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
//	return (const char*)REG_open_get_v(keyBody, names, (int (*)(const uint8_t*, int))REG_get_string);
//↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	return (const char*)REG_open_get_v(keyBody, names, (intptr_t (*)(const uint8_t*, int))REG_get_string);
//}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
/*--------------------------------------------------------------------------*/
const void* REG_get_blob_l(const uint8_t* keyBody, ...) {
	const void* blobData;
	va_list ap;
	va_start(ap, keyBody);
	blobData = REG_get_blob_a(keyBody, ap);
	va_end(ap);
	return blobData;
}
const void* REG_get_blob_a(const uint8_t* keyBody, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_get_blob_v(keyBody, names);
}
const void* REG_get_blob_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]blobName,]-1*/) {
//{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
//	return (const void*)REG_open_get_v(keyBody, names, (int (*)(const uint8_t*, int))REG_get_blob);
//↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	return (const void*)REG_open_get_v(keyBody, names, (intptr_t (*)(const uint8_t*, int))REG_get_blob);
//}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
#else //PIECE
const uint8_t* REG_open_key_l(const uint8_t* keyBody, ...);
const uint8_t* REG_open_key_a(const uint8_t* keyBody, va_list ap);
const uint8_t* REG_open_key_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
int REG_get_value_l(const uint8_t* keyBody, ...);
int REG_get_value_a(const uint8_t* keyBody, va_list ap);
int REG_get_value_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]valueName,]-1*/);
const char* REG_get_string_l(const uint8_t* keyBody, ...);
const char* REG_get_string_a(const uint8_t* keyBody, va_list ap);
const char* REG_get_string_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]stringName,]-1*/);
const void* REG_get_blob_l(const uint8_t* keyBody, ...);
const void* REG_get_blob_a(const uint8_t* keyBody, va_list ap);
const void* REG_get_blob_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]blobName,]-1*/);
asm("
		.code
		.align		1
		.global		REG_open_key_l
		.global		REG_open_key_a
		.global		REG_open_key_v
		.global		REG_get_value_l
		.global		REG_get_value_a
		.global		REG_get_value_v
		.global		REG_get_string_l
		.global		REG_get_string_a
		.global		REG_get_string_v
		.global		REG_get_blob_l
		.global		REG_get_blob_a
		.global		REG_get_blob_v
REG_open_key_l:
		;//[%sp+0] := retp
		;//[%sp+4] := keyBody
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12 := keyBody
		xadd		%r13, %sp, 8				;//%r13 := ap = &...
REG_open_key_a:
		;//%r12 := keyBody
		;//%r13 := ap
REG_open_key_v:
		;//%r12 := keyBody
		;//%r13 := names
	    ;//{{特例処理
		;//「REG_open_key_l(keyBody,-1)」の形で呼び出された場合は、エラーとしてNULLを返すのではなく、keyBody自身を返す方が自然です。
		;// - REG_open_get_v()を呼び出すと、REG_open_get_v()が誤ってエラーと判断してしまう。
		;//   REG_open_get_v()に特例処理を追加するよりも、ここで判断する方が適切だと思うので、ここに特例処理を追加する事にしました。
		;// - clipfsm.cのFsmObj_GetTransKey()が、この動作に依存しています。
		ld.w		%r9, [%r13]				;//%r9  := names[0]
		xld.w		%r14, REG_open_key			;//%r14 := fn = REG_open_key								*anti-interlock*
		cmp		%r9, -1					;//if(names[0] != -1) {
		jrne		REG_open_get_v				;//  goto REG_open_get_v }
		ret.d							;//return  keyBody
		ld.w		%r10, %r12				;//%r10 := keyBody									*delay*
	    ;//}}特例処理
		;//-----------------------------------------------------;//
REG_get_value_l:
		;//[%sp+0] := retp
		;//[%sp+4] := keyBody
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12 := keyBody
		xadd		%r13, %sp, 8				;//%r13 := ap = &...
REG_get_value_a:
		;//%r12 := keyBody
		;//%r13 := ap
REG_get_value_v:
		;//%r12 := keyBody
		;//%r13 := names
		xld.w		%r14, REG_get_value			;//%r14 := fn = REG_get_value
		jp		REG_open_get_v				;//
		;//-----------------------------------------------------;//
REG_get_string_l:
		;//[%sp+0] := retp
		;//[%sp+4] := keyBody
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12 := keyBody
		xadd		%r13, %sp, 8				;//%r13 := ap = &...
REG_get_string_a:
		;//%r12 := keyBody
		;//%r13 := ap
REG_get_string_v:
		;//%r12 := keyBody
		;//%r13 := names
		xld.w		%r14, REG_get_string			;//%r14 := fn = REG_get_string
		jp		REG_open_get_v				;//
		;//-----------------------------------------------------;//
REG_get_blob_l:
		;//[%sp+0] := retp
		;//[%sp+4] := keyBody
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12 := keyBody
		xadd		%r13, %sp, 8				;//%r13 := ap = &...
REG_get_blob_a:
		;//%r12 := keyBody
		;//%r13 := ap
REG_get_blob_v:
		;//%r12 := keyBody
		;//%r13 := names
		xld.w		%r14, REG_get_blob			;//%r14 := fn = REG_get_blob
		;//-----------------------------------------------------;//
REG_open_get_v:
		;//%r12 := keyBody
		;//%r13 := names
		;//%r14 := fn
		pushn		%r1					;//
		ld.w		%r0, %r13				;//%r0  :=         names
		ld.w		%r1, %r14				;//%r1  :=         fn
		ld.w		%r13, [%r0]+				;//%r13 := name = *names++
		cmp		%r13, -1				;//if(name != -1)
		jreq		REG_open_get_v_NAMES_EMPTY		;//  
		jp		REG_open_get_v_START			;//  goto L_START
REG_open_get_v_LOOP:							;//  do {
		xcall		REG_open_key				;//    %r10 := keyBody = REG_open_key(keyBody, name)
		ld.w		%r12, %r10				;//    %r12 := keyBody
		ld.w		%r13, [%r0]+				;//    %r13 := name = *names++
REG_open_get_v_START:							;//    
		ld.w		%r14, [%r0]				;//    %r14 := *names
		cmp		%r14, -1				;//    											!INTERLOCK!
		jrne		REG_open_get_v_LOOP			;//  } while(*names != -1)
REG_open_get_v_NAMES_EMPTY:						;//}
		ld.w		%r14, %r1				;//%r14 :=  fn
		popn		%r1					;//
		jp		%r14					;//return (*fn)(keyBody, name)
");
#endif//PIECE
/****************************************************************************
 *	インデクスアクセス型,及び,イテレーション用の関数
 ****************************************************************************/
/*==========================================================================*
 *	基本的な関数
 *==========================================================================*/
#ifndef PIECE
//{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
//static uint64_t REG_nth(const uint8_t* addr, int index, int* p_name/*NULL可*/, int type) {
//↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
static REG_data_addr REG_nth(const uint8_t* addr, int index, int* p_name/*NULL可*/, int type) {
//}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	int mask, n, data;
    //{{2015/10/29追加:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
	//NULLアドレスに対する呼び出しならば要素が無いのと同じと見なして帰る。
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	if(!addr) { return 0; }
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	if(!addr) { return REG_pack_data_0; }
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //}}2015/10/29追加:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
	//このキーボディが持っている配列タイプのマスクを取得する。
	// - bit31=キー,bit30=値,bit29=文字列,bit28=BLOB,bit27～24=0(未使用),bit27～0=0
	mask = *addr++ << 24;								//アセンブラでは'rr 8'と出来る。
	for(;;) {
		//このキーボディがこのタイプの配列を持っていたら…
		if(mask < 0) {								//←┐
			mask <<= 1;							//←┤
			//配列の(要素数-1)を取得する。					//　│
			n   = *addr++;	//┐						//　│
			n <<= 8;	//├符号無し16ビット,ビッグエンディアン		//　│
			n  |= *addr++;	//┘						//　│
			//(要素数-1)⇒要素数に変換する。				//　│アセンブラでは'add %r(mask),%r(mask); jrult 2; jreq RET'と出来る。	{{2015/10/05追記:実際には他の処理との兼ね合いで左記のとおりのコードにはならなかった。REG_op_LOOPの下あたりのコードを参照せよ。}}
			n++;								//　│'(mask<0)'と2箇所の'mask<<=1'はアセンブラでは1命令にまとめられる。
		//このキーボディがこのタイプの配列を持っていなければ…			//　│
		} else {								//　│
			mask <<= 1;							//←┤
			//このキーボディが持っている配列タイプが残っていなければ帰る。	//　│
			// - アセンブラでは戻り値のbit63～32は不定値で構いません。	//　│
		    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
		    //	if(!mask) { return 0; }						//←┘
		    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
			if(!mask) { return REG_pack_data_0; }				//←┘
		    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
			//配列の要素数を0とする。
			n = 0;
		}
		//この配列が指定されたタイプの配列ならば抜ける。
		if(--type < 0) { break; }
		//この配列をスキップする。
		addr += n * (2/*name*/+3/*data*/);
	}
    {{//--- REG_op()とREG_nth()とで処理の違いはこの範囲だけです。 ---
	int name;
	//指定されたインデクスが配列の要素数以上ならば帰る。
	// - アセンブラでは戻り値のbit63～32は不定値で構いません。
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	if((unsigned)index >= (unsigned)n) { return 0; }
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	if((unsigned)index >= (unsigned)n) { return REG_pack_data_0; }
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	//指定されたインデクスの要素のアドレスを求める。
	addr  += index * (2/*keyName*/+3/*keyBodyDist*/);
	//要素の名前を取得(,格納)する。
	name   = *addr++;	//┐
	name <<= 8;		//├符号無し16ビット,ビッグエンディアン
	name  |= *addr++;	//┘
	if(p_name) { *p_name = name; }
    }}//--- REG_op()とREG_nth()とで処理の違いはこの範囲だけです。 ---
	data   = (int8_t)*addr++;		//┐
	data <<= 8;				//│
	data  |=         *addr++;		//├符号付き24ビット,ビッグエンディアン		符号付き24ビットでアドレスに加算した後、符号無し24ビットに変換する。
	data <<= 8;				//│
	data  |=         *addr++;		//┘
	addr  += data;				//アドレス					REG_get_value()から呼び出された場合は使用しない。
	data   = (unsigned)(data << 8) >> 8;	//データ					符号無し24ビット
	//戻り値 bit63～32 = データ(符号無し24ビット)	REG_get_value()から呼び出された場合はこっちを使う。
	//       bit31～ 0 = アドレス			REG_get_value()以外から呼び出された場合はこっちを使う。
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	return (((uint64_t)(unsigned)data) << 32) | ((uint64_t)(unsigned)addr);
    //	//                 ~~~~~~~~~~このキャストを行わなくても結果は同じになるのだが、無駄な符号拡張を行うコードが生成されないように明示的に符号無しにキャストした。
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	return REG_pack_data_addr(data, addr);
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
/*--------------------------------------------------------------------------*/
const uint8_t* REG_open_nth_key(const uint8_t* keyBody, int index, int* p_keyName/*NULL可*/) {
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	return (const uint8_t*)(int)REG_nth(keyBody, index, p_keyName, 0/*キー*/);	//REG_nth()の戻り値のbit31～0をそのまま返す。
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	REG_data_addr data_addr = REG_nth(keyBody, index, p_keyName, 0/*キー*/);
	return REG_unpack_addr(data_addr);						//REG_nth()の戻り値のbit31～0をそのまま返す。
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
int REG_get_nth_value(const uint8_t* keyBody, int index, int* p_valueName/*NULL可*/) {
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	uint64_t data_addr = REG_nth(keyBody, index, p_valueName, 1/*値*/);
    //	if(!(int)data_addr) { return -1; }						//REG_nth()の戻り値のbit31～0が0ならば(-1)を返す。	//アセンブラでは'sub %r10,1; jrult RET'と出来る。
    //	return (int)(data_addr >> 32);							//REG_nth()の戻り値のbit55～32を返す。			//アセンブラでは'ld.w %r10,%r11'と出来る。
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	REG_data_addr data_addr = REG_nth(keyBody, index, p_valueName, 1/*値*/);
	if(!REG_unpack_addr(data_addr)) { return -1; }					//REG_nth()の戻り値のbit31～0が0ならば(-1)を返す。	//アセンブラでは'sub %r10,1; jrult RET'と出来る。
	return REG_unpack_data(data_addr);						//REG_nth()の戻り値のbit55～32を返す。			//アセンブラでは'ld.w %r10,%r11'と出来る。
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
const char* REG_get_nth_string(const uint8_t* keyBody, int index, int* p_stringName/*NULL可*/) {
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	return (const char*)(int)REG_nth(keyBody, index, p_stringName, 2/*文字列*/);	//REG_nth()の戻り値のbit31～0をそのまま返す。
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	REG_data_addr data_addr = REG_nth(keyBody, index, p_stringName, 2/*文字列*/);
	return REG_unpack_addr(data_addr);						//REG_nth()の戻り値のbit31～0をそのまま返す。
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
const void* REG_get_nth_blob(const uint8_t* keyBody, int index, int* p_blobName/*NULL可*/) {
    //{{2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
    //	return (const void*)(int)REG_nth(keyBody, index, p_blobName, 3/*BLOB*/);	//REG_nth()の戻り値のbit31～0をそのまま返す。
    //↓2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
	REG_data_addr data_addr = REG_nth(keyBody, index, p_blobName, 3/*BLOB*/);
	return REG_unpack_addr(data_addr);						//REG_nth()の戻り値のbit31～0をそのまま返す。
    //}}2016/09/05変更:64ビット対応を行い、32ビット版と64ビット版のソースを共通化しました。
}
#else //PIECE
const uint8_t* REG_open_nth_key(const uint8_t* keyBody, int index, int* p_keyName/*NULL可*/);
int REG_get_nth_value(const uint8_t* keyBody, int index, int* p_valueName/*NULL可*/);
const char* REG_get_nth_string(const uint8_t* keyBody, int index, int* p_stringName/*NULL可*/);
const void* REG_get_nth_blob(const uint8_t* keyBody, int index, int* p_blobName/*NULL可*/);
asm("
		.code
		.align		1
		.global		REG_open_nth_key
		.global		REG_get_nth_value
		.global		REG_get_nth_string
		.global		REG_get_nth_blob
REG_open_nth_key:
		;//%r12 := keyBody
		;//%r13 := index
		;//%r14 := p_keyName
		jp.d		REG_nth					;//%r10 := addr
		ld.w		%r15, 0					;//%r15 := type = 0/*キー*/								*delay*
REG_get_nth_value:
		;//%r12 := keyBody
		;//%r13 := index
		;//%r14 := p_valueName
		call.d		REG_nth					;//%r11:%r10 := data:addr
		ld.w		%r15, 1					;//%r15 := type = 1/*値*/								*delay*
		sub		%r10, 1					;//if(--addr == -1) { return -1 }
		jrult		2					;//else {
		 ld.w		%r10, %r11				;//  %r10 := data
		ret							;//  return  data }
REG_get_nth_string:
		;//%r12 := keyBody
		;//%r13 := index
		;//%r14 := p_stringName
		jp.d		REG_nth					;//%r10 := addr
		ld.w		%r15, 2					;//%r15 := type = 2/*文字列*/								*delay*
REG_get_nth_blob:
		;//%r12 := keyBody
		;//%r13 := index
		;//%r14 := p_blobName
		ld.w		%r15, 3					;//%r15 := type = 3/*BLOB*/
		;//-----------------------------------------------------;//
REG_nth:
		;//%r12 := addr
		;//%r13 := index
		;//%r14 := p_name
		;//%r15 := type
	    ;//{{2015/10/29変更:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
	    ;//	ld.w		%r10, 0					;//%r10 := 0
	    ;//↓2015/10/29変更:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
		cmp		%r12, 0					;//if(!addr) { return 0 }
		jreq.d		REG_nth_RET				;//
		ld.w		%r10, 0					;//%r10 := 0										*delay*
	    ;//}}2015/10/29変更:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
		ld.ub		%r4, [%r12]+				;//%r4  := mask = *addr++
		rr		%r4, 8					;//%r4[31:24] := mask
REG_nth_LOOP:								;//for(;;) {
		add		%r4, %r4				;//  %psr(C) := mask[31], %r4  := mask <<= 1
		jruge		7					;//  if(%psr(C)) {
		 ld.ub		%r5, [%r12]+				;//    %r5  :=      nH
		 ld.ub		%r6, [%r12]+				;//    %r6  :=             nL
		 sla		%r5, 8					;//    %r5  :=      nH<<8
		 or		%r5, %r6				;//    %r5  := n = (nH<<8)|nL
		 jp.d		4					;//    %r5  := n++
		 add		%r5, 1					;//  } else {										*delay*
		  jreq		REG_nth_RET				;//    if(!mask) { return 0 }
		  ld.w		%r5, 0					;//    %r5  := n = 0 }
		sub		%r15, 1					;//  %r15 := type--
		jrult		REG_nth_BREAK				;//  if(type == -1) { break }
		add		%r12, %r5				;//  %r12 := addr + n * 1
		sla		%r5, 2					;//  %r5  :=        n * 4
		jp.d		REG_nth_LOOP				;//}
		add		%r12, %r5				;//  %r12 := addr + n * 5 = addr + n * (2/*name*/+3/*data*/)				*delay*
REG_nth_BREAK:
	    ;//{{---
		cmp		%r13, %r5				;//if((unsigned)index >= (unsigned)n) {
		jruge		REG_nth_RET				;//  return 0 }
		ld.w		%r10, %r12				;//%r10 := addr
		add		%r10, %r13				;//%r10 := addr + index * 1
		sla		%r13, 2					;//%r13 :=        index * 4
		add		%r10, %r13				;//%r10 := addr + index * 5 = addr + index * (2/*name*/+3/*data*/)
		ld.ub		%r4, [%r10]+				;//%r4  :=           nameH
		ld.ub		%r5, [%r10]+				;//%r5  :=                     nameL
		cmp		%r14, 0					;//if(p_name) {
		jreq		4					;//  
		 sla		%r4, 8					;//  %r4  :=         nameH<<8
		 or		%r4, %r5				;//  %r4  := name = (nameH<<8)|nameL
		 ld.w		[%r14], %r4				;//  *p_name = name }
	    ;//}}---
		ld.b		%r11, [%r10]+				;//%r11 :=            (int8_t)dataH
		ld.ub		%r12, [%r10]+				;//%r12 :=                              dataM
		ld.ub		%r13, [%r10]+				;//%r13 :=                                         dataL
		sla		%r11, 8					;//%r11 :=            (int8_t)dataH<<8
		or		%r11, %r12				;//%r11 :=           ((int8_t)dataH<<8)|dataM
		sla		%r11, 8					;//%r11 :=          (((int8_t)dataH<<8)|dataM)<<8
		or		%r11, %r13				;//%r11 := data  = ((((int8_t)dataH<<8)|dataM)<<8)|dataL
		add		%r10, %r11				;//%r10 := addr += data
		sll		%r11, 8					;//%r11 :=                  (data << 8)
REG_nth_RET:								;//
		ret.d							;//%r11:%r10 := data:addr			(addr=0)の場合は(data=不定値)です
		srl		%r11, 8					;//%r11 := data = (unsigned)(data << 8) >> 8	途中でRETへjpした場合はダミー処理	*delay*
");
#endif//PIECE
/*==========================================================================*
 *	ユーティリティ関数
 *==========================================================================*/
#ifndef PIECE
const uint8_t* REG_open_nth_key_l(const uint8_t* keyBody, int index, int* p_keyName/*NULL可*/, ...) {
	va_list ap;
	va_start(ap, p_keyName);
	keyBody = REG_open_nth_key_a(keyBody, index, p_keyName, ap);
	va_end(ap);
	return keyBody;
}
const uint8_t* REG_open_nth_key_a(const uint8_t* keyBody, int index, int* p_keyName/*NULL可*/, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_open_nth_key_v(keyBody, index, p_keyName, names);
}
const uint8_t* REG_open_nth_key_v(const uint8_t* keyBody, int index, int* p_keyName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/) {
	return REG_open_nth_key(REG_open_key_v(keyBody, names), index, p_keyName);
}
/*--------------------------------------------------------------------------*/
int REG_get_nth_value_l(const uint8_t* keyBody, int index, int* p_valueName/*NULL可*/, ...) {
	int valueData;
	va_list ap;
	va_start(ap, p_valueName);
	valueData = REG_get_nth_value_a(keyBody, index, p_valueName, ap);
	va_end(ap);
	return valueData;
}
int REG_get_nth_value_a(const uint8_t* keyBody, int index, int* p_valueName/*NULL可*/, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_get_nth_value_v(keyBody, index, p_valueName, names);
}
int REG_get_nth_value_v(const uint8_t* keyBody, int index, int* p_valueName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/) {
	return REG_get_nth_value(REG_open_key_v(keyBody, names), index, p_valueName);
}
/*--------------------------------------------------------------------------*/
const char* REG_get_nth_string_l(const uint8_t* keyBody, int index, int* p_stringName/*NULL可*/, ...) {
	const char* stringData;
	va_list ap;
	va_start(ap, p_stringName);
	stringData = REG_get_nth_string_a(keyBody, index, p_stringName, ap);
	va_end(ap);
	return stringData;
}
const char* REG_get_nth_string_a(const uint8_t* keyBody, int index, int* p_stringName/*NULL可*/, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_get_nth_string_v(keyBody, index, p_stringName, names);
}
const char* REG_get_nth_string_v(const uint8_t* keyBody, int index, int* p_stringName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/) {
	return REG_get_nth_string(REG_open_key_v(keyBody, names), index, p_stringName);
}
/*--------------------------------------------------------------------------*/
const void* REG_get_nth_blob_l(const uint8_t* keyBody, int index, int* p_blobName/*NULL可*/, ...) {
	const void* blobData;
	va_list ap;
	va_start(ap, p_blobName);
	blobData = REG_get_nth_blob_a(keyBody, index, p_blobName, ap);
	va_end(ap);
	return blobData;
}
const void* REG_get_nth_blob_a(const uint8_t* keyBody, int index, int* p_blobName/*NULL可*/, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_get_nth_blob_v(keyBody, index, p_blobName, names);
}
const void* REG_get_nth_blob_v(const uint8_t* keyBody, int index, int* p_blobName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/) {
	return REG_get_nth_blob(REG_open_key_v(keyBody, names), index, p_blobName);
}
#else //PIECE
const uint8_t* REG_open_nth_key_l(const uint8_t* keyBody, int index, int* p_keyName/*NULL可*/, ...);
const uint8_t* REG_open_nth_key_a(const uint8_t* keyBody, int index, int* p_keyName/*NULL可*/, va_list ap);
const uint8_t* REG_open_nth_key_v(const uint8_t* keyBody, int index, int* p_keyName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
int REG_get_nth_value_l(const uint8_t* keyBody, int index, int* p_valueName/*NULL可*/, ...);
int REG_get_nth_value_a(const uint8_t* keyBody, int index, int* p_valueName/*NULL可*/, va_list ap);
int REG_get_nth_value_v(const uint8_t* keyBody, int index, int* p_valueName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
const char* REG_get_nth_string_l(const uint8_t* keyBody, int index, int* p_stringName/*NULL可*/, ...);
const char* REG_get_nth_string_a(const uint8_t* keyBody, int index, int* p_stringName/*NULL可*/, va_list ap);
const char* REG_get_nth_string_v(const uint8_t* keyBody, int index, int* p_stringName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
const void* REG_get_nth_blob_l(const uint8_t* keyBody, int index, int* p_blobName/*NULL可*/, ...);
const void* REG_get_nth_blob_a(const uint8_t* keyBody, int index, int* p_blobName/*NULL可*/, va_list ap);
const void* REG_get_nth_blob_v(const uint8_t* keyBody, int index, int* p_blobName/*NULL可*/, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/);
asm("
		.code
		.align		1
		.global		REG_open_nth_key_l
		.global		REG_open_nth_key_a
		.global		REG_open_nth_key_v
		.global		REG_get_nth_value_l
		.global		REG_get_nth_value_a
		.global		REG_get_nth_value_v
		.global		REG_get_nth_string_l
		.global		REG_get_nth_string_a
		.global		REG_get_nth_string_v
		.global		REG_get_nth_blob_l
		.global		REG_get_nth_blob_a
		.global		REG_get_nth_blob_v
REG_open_nth_key_l:
		;//%r12    := keyBody
		;//%r13    := index
		;//[%sp+0] := retp
		;//[%sp+4] := p_keyName
		;//[%sp+8] := ...
		xld.w		%r14, [%sp+4]				;//%r14 := p_keyName
		xadd		%r15, %sp, 8				;//%r15 := ap = &...
REG_open_nth_key_a:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_keyName
		;//%r15    := ap
REG_open_nth_key_v:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_keyName
		;//%r15    := names
		xld.w		%r10, REG_open_nth_key			;//%r10 := fn = REG_open_nth_key
		jp		REG_open_get_nth_v
		;//-----------------------------------------------------;//
REG_get_nth_value_l:
		;//%r12    := keyBody
		;//%r13    := index
		;//[%sp+0] := retp
		;//[%sp+4] := p_valueName
		;//[%sp+8] := ...
		xld.w		%r14, [%sp+4]				;//%r14 := p_valueName
		xadd		%r15, %sp, 8				;//%r15 := ap = &...
REG_get_nth_value_a:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_valueName
		;//%r15    := ap
REG_get_nth_value_v:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_valueName
		;//%r15    := names
		xld.w		%r10, REG_get_nth_value			;//%r10 := fn = REG_get_nth_value
		jp		REG_open_get_nth_v
		;//-----------------------------------------------------;//
REG_get_nth_string_l:
		;//%r12    := keyBody
		;//%r13    := index
		;//[%sp+0] := retp
		;//[%sp+4] := p_stringName
		;//[%sp+8] := ...
		xld.w		%r14, [%sp+4]				;//%r14 := p_stringName
		xadd		%r15, %sp, 8				;//%r15 := ap = &...
REG_get_nth_string_a:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_stringName
		;//%r15    := ap
REG_get_nth_string_v:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_stringName
		;//%r15    := names
		xld.w		%r10, REG_get_nth_string		;//%r10 := fn = REG_get_nth_string
		jp		REG_open_get_nth_v
		;//-----------------------------------------------------;//
REG_get_nth_blob_l:
		;//%r12    := keyBody
		;//%r13    := index
		;//[%sp+0] := retp
		;//[%sp+4] := p_blobName
		;//[%sp+8] := ...
		xld.w		%r14, [%sp+4]				;//%r14 := p_blobName
		xadd		%r15, %sp, 8				;//%r15 := ap = &...
REG_get_nth_blob_a:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_blobName
		;//%r15    := ap
REG_get_nth_blob_v:
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_blobName
		;//%r15    := names
		xld.w		%r10, REG_get_nth_blob			;//%r10 := fn = REG_get_nth_blob
		;//-----------------------------------------------------;//
REG_open_get_nth_v:
		;//%r10    := fn
		;//%r12    := keyBody
		;//%r13    := index
		;//%r14    := p_name
		;//%r15    := names
		xsub		%sp, %sp, 12
		xld.w		[%sp+0], %r13				;//[%sp+0] := index
		xld.w		[%sp+4], %r14				;//[%sp+4] := p_name
		xld.w		[%sp+8], %r10				;//[%sp+8] := fn
		xcall.d		REG_open_key_v				;//%r10 := keyBody = REG_open_key_v(keyBody, names)
		ld.w		%r13, %r15				;//%r13 :=                                   names					*delay*
		xld.w		%r13, [%sp+0]				;//%r13 :=                 index
		xld.w		%r14, [%sp+4]				;//%r14 :=                        p_name
		xadd		%sp, %sp, 8				;//[%sp+0] := fn
		ret.d							;//return   (*fn)(keyBody, index, p_name)
		ld.w		%r12, %r10				;//%r12 :=        keyBody								*delay*
");
#endif//PIECE
/****************************************************************************
 *	要素数を取得する関数
 ****************************************************************************/
/*==========================================================================*
 *	基本的な関数
 *==========================================================================*/
#ifndef PIECE
static int REG_num(const uint8_t* addr, int type) {
	int mask, n;
    //{{2015/10/29追加:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
	//NULLアドレスに対する呼び出しならば要素が無いのと同じと見なして帰る。
	if(!addr) { return 0; }
    //}}2015/10/29追加:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
	//このキーボディが持っている配列タイプのマスクを取得する。
	// - bit31=キー,bit30=値,bit29=文字列,bit28=BLOB,bit27～24=0(未使用),bit27～0=0
	mask = *addr++ << 24;								//アセンブラでは'rr 8'と出来る。
	for(;;) {
		//このキーボディがこのタイプの配列を持っていたら…
		if(mask < 0) {								//←┐
			mask <<= 1;							//←┤
			//配列の(要素数-1)を取得する。					//　│
			n   = *addr++;	//┐						//　│
			n <<= 8;	//├符号無し16ビット,ビッグエンディアン		//　│
			n  |= *addr++;	//┘						//　│
			//(要素数-1)⇒要素数に変換する。				//　│アセンブラでは'add %r(mask),%r(mask); jrult 2; jreq RET'と出来る。	{{2015/10/05追記:実際には他の処理との兼ね合いで左記のとおりのコードにはならなかった。REG_op_LOOPの下あたりのコードを参照せよ。}}
			n++;								//　│'(mask<0)'と2箇所の'mask<<=1'はアセンブラでは1命令にまとめられる。
		//このキーボディがこのタイプの配列を持っていなければ…			//　│
		} else {								//　│
			mask <<= 1;							//←┤
			//このキーボディが持っている配列タイプが残っていなければ帰る。	//　│
			// - アセンブラでは戻り値のbit63～32は不定値で構いません。	//　│
			if(!mask) { return 0; }						//←┘
			//配列の要素数を0とする。
			n = 0;
		}
		//この配列が指定されたタイプの配列ならば抜ける。
		if(--type < 0) { break; }
		//この配列をスキップする。
		addr += n * (2/*name*/+3/*data*/);
	}
    //↑↑↑ここまではREG_op(),REG_nth()と全く同じ処理です。↑↑↑
	return n;
}
/*--------------------------------------------------------------------------*/
int REG_num_key(const uint8_t* keyBody) {
	return REG_num(keyBody, 0/*キー*/);
}
int REG_num_value(const uint8_t* keyBody) {
	return REG_num(keyBody, 1/*値*/);
}
int REG_num_string(const uint8_t* keyBody) {
	return REG_num(keyBody, 2/*文字列*/);
}
int REG_num_blob(const uint8_t* keyBody) {
	return REG_num(keyBody, 3/*BLOB*/);
}
#else //PIECE
int REG_num_key(const uint8_t* keyBody);
int REG_num_value(const uint8_t* keyBody);
int REG_num_string(const uint8_t* keyBody);
int REG_num_blob(const uint8_t* keyBody);
asm("
		.code
		.align		1
		.global		REG_num_key
		.global		REG_num_value
		.global		REG_num_string
		.global		REG_num_blob
REG_num_key:
		;//%r12 := keyBody
		jp.d		REG_num					;//%r10 := n
		ld.w		%r13, 0					;//%r13 := type = 0/*キー*/								*delay*
REG_num_value:
		;//%r12 := keyBody
		jp.d		REG_num					;//%r10 := n
		ld.w		%r13, 1					;//%r13 := type = 1/*値*/								*delay*
REG_num_string:
		;//%r12 := keyBody
		jp.d		REG_num					;//%r10 := n
		ld.w		%r13, 2					;//%r13 := type = 2/*文字列*/								*delay*
REG_num_blob:
		;//%r12 := keyBody
		ld.w		%r13, 3					;//%r13 := type = 3/*BLOB*/
		;//-----------------------------------------------------;//
REG_num:
		;//%r12 := addr
		;//%r13 := type
	    ;//{{2015/10/29変更:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
	    ;//	ld.w		%r10, 0					;//%r10 := 0
	    ;//↓2015/10/29変更:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
		cmp		%r12, 0					;//if(!addr) { return 0 }
		jreq.d		REG_num_RET				;//
		ld.w		%r10, 0					;//%r10 := 0										*delay*
	    ;//}}2015/10/29変更:REG_op()とREG_nth()のaddrにNULLが渡された場合の判定が抜けていたのを修正しました。
		ld.ub		%r4, [%r12]+				;//%r4  := mask = *addr++
		rr		%r4, 8					;//%r4[31:24] := mask
REG_num_LOOP:								;//for(;;) {
		add		%r4, %r4				;//  %psr(C) := mask[31], %r4  := mask <<= 1
		jruge		7					;//  if(%psr(C)) {
		 ld.ub		%r5, [%r12]+				;//    %r5  :=      nH
		 ld.ub		%r6, [%r12]+				;//    %r6  :=             nL
		 sla		%r5, 8					;//    %r5  :=      nH<<8
		 or		%r5, %r6				;//    %r5  := n = (nH<<8)|nL
		 jp.d		4					;//    %r5  := n++
		 add		%r5, 1					;//  } else {										*delay*
		  jreq		REG_num_RET				;//    if(!mask) { return 0 }
		  ld.w		%r5, 0					;//    %r5  := n = 0 }
		sub		%r13, 1					;//  %r13 := type--
		jrult		REG_num_BREAK				;//  if(type == -1) { break }
		add		%r12, %r5				;//  %r12 := addr + n * 1
		sla		%r5, 2					;//  %r5  :=        n * 4
		jp.d		REG_num_LOOP				;//}
		add		%r12, %r5				;//  %r12 := addr + n * 5 = addr + n * (2/*name*/+3/*data*/)				*delay*
REG_num_BREAK:
	    ;//↑↑↑ここまではREG_op(),REG_nth()と全く同じ処理です。↑↑↑
		ld.w		%r10, %r5				;//%r10 := n
REG_num_RET:								;//
		ret							;//return  n
");
#endif//PIECE
/*==========================================================================*
 *	ユーティリティ関数
 *==========================================================================*/
#ifndef PIECE
int REG_num_key_l(const uint8_t* keyBody, ...) {
	int n;
	va_list ap;
	va_start(ap, keyBody);
	n = REG_num_key_a(keyBody, ap);
	va_end(ap);
	return n;
}
int REG_num_key_a(const uint8_t* keyBody, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_num_key_v(keyBody, names);
}
int REG_num_key_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/) {
	return REG_num_key(REG_open_key_v(keyBody, names));
}
/*--------------------------------------------------------------------------*/
int REG_num_value_l(const uint8_t* keyBody, ...) {
	int n;
	va_list ap;
	va_start(ap, keyBody);
	n = REG_num_value_a(keyBody, ap);
	va_end(ap);
	return n;
}
int REG_num_value_a(const uint8_t* keyBody, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_num_value_v(keyBody, names);
}
int REG_num_value_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/) {
	return REG_num_value(REG_open_key_v(keyBody, names));
}
/*--------------------------------------------------------------------------*/
int REG_num_string_l(const uint8_t* keyBody, ...) {
	int n;
	va_list ap;
	va_start(ap, keyBody);
	n = REG_num_string_a(keyBody, ap);
	va_end(ap);
	return n;
}
int REG_num_string_a(const uint8_t* keyBody, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_num_string_v(keyBody, names);
}
int REG_num_string_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/) {
	return REG_num_string(REG_open_key_v(keyBody, names));
}
/*--------------------------------------------------------------------------*/
int REG_num_blob_l(const uint8_t* keyBody, ...) {
	int n;
	va_list ap;
	va_start(ap, keyBody);
	n = REG_num_blob_a(keyBody, ap);
	va_end(ap);
	return n;
}
int REG_num_blob_a(const uint8_t* keyBody, va_list ap) {
	int names[(7+1)/*調整可*/], i = 0;	//実用上、キーと値の階層が7以下(終端(-1)を含めて8以下)と考えて充分だろう。不足した場合は増やせ。
	for(;;) {
		if((names[i] = va_arg(ap, int)) == -1) { break; }
		if(++i >= ARRAY_SIZE(names)) { DIE(); }	//ここで停止した場合は、names[]不足か,又は,呼出し側が終端を忘れている。おそらく後者だろう。
	}
	return REG_num_blob_v(keyBody, names);
}
int REG_num_blob_v(const uint8_t* keyBody, const int* names/*[[[[keyName,]keyName],…,]keyName,]-1*/) {
	return REG_num_blob(REG_open_key_v(keyBody, names));
}
#else //PIECE
asm("
		.code
		.align		1
		.global		REG_num_key_l
		.global		REG_num_key_a
		.global		REG_num_key_v
		.global		REG_num_value_l
		.global		REG_num_value_a
		.global		REG_num_value_v
		.global		REG_num_string_l
		.global		REG_num_string_a
		.global		REG_num_string_v
		.global		REG_num_blob_l
		.global		REG_num_blob_a
		.global		REG_num_blob_v
REG_num_key_l:
		;//[%sp+0] := retp
		;//[%sp+4] := keyBody
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12 := keyBody
		xadd		%r13, %sp, 8				;//%r13 := ap = &...
REG_num_key_a:
		;//%r12    := keyBody
		;//%r13    := ap
REG_num_key_v:
		;//%r12    := keyBody
		;//%r13    := names
		xld.w		%r10, REG_num_key			;//%r10 := fn = REG_num_key
		jp		REG_num_v
		;//-----------------------------------------------------;//
REG_num_value_l:
		;//[%sp+0] := retp
		;//[%sp+4] := keyBody
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12 := keyBody
		xadd		%r13, %sp, 8				;//%r13 := ap = &...
REG_num_value_a:
		;//%r12    := keyBody
		;//%r13    := ap
REG_num_value_v:
		;//%r12    := keyBody
		;//%r13    := names
		xld.w		%r10, REG_num_value			;//%r10 := fn = REG_num_value
		jp		REG_num_v
		;//-----------------------------------------------------;//
REG_num_string_l:
		;//[%sp+0] := retp
		;//[%sp+4] := keyBody
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12 := keyBody
		xadd		%r13, %sp, 8				;//%r13 := ap = &...
REG_num_string_a:
		;//%r12    := keyBody
		;//%r13    := ap
REG_num_string_v:
		;//%r12    := keyBody
		;//%r13    := names
		xld.w		%r10, REG_num_string			;//%r10 := fn = REG_num_string
		jp		REG_num_v
		;//-----------------------------------------------------;//
REG_num_blob_l:
		;//[%sp+0] := retp
		;//[%sp+4] := keyBody
		;//[%sp+8] := ...
		xld.w		%r12, [%sp+4]				;//%r12 := keyBody
		xadd		%r13, %sp, 8				;//%r13 := ap = &...
REG_num_blob_a:
		;//%r12    := keyBody
		;//%r13    := ap
REG_num_blob_v:
		;//%r12    := keyBody
		;//%r13    := names
		xld.w		%r10, REG_num_blob			;//%r10 := fn = REG_num_blob
		;//-----------------------------------------------------;//
REG_num_v:
		;//%r10    := fn
		;//%r12    := keyBody
		;//%r13    := names
		xsub		%sp, %sp, 4
		xld.w		[%sp+0], %r10				;//[%sp+0] := fn
		xcall		REG_open_key_v				;//%r10    := keyBody = REG_open_key_v(keyBody, names)
		ret.d							;//return   (*fn)(keyBody)
		ld.w		%r12, %r10				;//%r12    :=     keyBody								*delay*
");
#endif//PIECE
/****************************************************************************
 *	BLOBのデータ構造について
 ****************************************************************************/
#ifndef PIECE
int REG_get_blob_size(const void* _blob/*NULL可*/) {
	const uint8_t* blob = _blob;
	int size;
	if(!blob) { return 0; }	//NULLポインタが渡された場合は(size=0)を返します。REG_get_blob()の結果がNULLかどうかを確認せずにREG_get_blob_size()に渡しても安全です。
	blob  -= 3;
	size   = *blob++;	//┐
	size <<= 8;		//│
	size  |= *blob++;	//├符号無し24ビットBE
	size <<= 8;		//│
	size  |= *blob++;	//┘
	size++;			//(バイト数-1)⇒バイト数に変換する。
	return size;
}
#else //PIECE
int REG_get_blob_size(const void* _blob/*NULL可*/);
asm("
		.code
		.align		1
		.global		REG_get_blob_size
REG_get_blob_size:
		;//%r12 := blob
		cmp		%r12, 0					;//if(!blob) { goto RET }
		jreq		REG_get_blob_size_RET			;//
		sub		%r12, 4					;//%r12        := blob -= 4											┐
		ld.w		%r12, [%r12]				;//%r12[31:24] := sizeL,    %r12[23:16] := sizeM, %r12[15:8] := sizeH, %r12[7:0] := (不定値)			│レジストリ内でBLOBデータ本体がワードアライメントされている事を利用して最適化しました。
		swap		%r12, %r12				;//%r12[31:24] := (不定値), %r12[23:16] := sizeH, %r12[15:8] := sizeM, %r12[7:0] := sizeL	!INTERLOCK!	│渡されたblobポインタは４の倍数であるはずなので、(blob-4)の位置からワード読み出ししても安全です。
		sll		%r12, 8					;//%r12[31:24] := sizeH,    %r12[23:16] := sizeM, %r12[15:8] := sizeL, %r12[7:0] := 0				│(blob-4)に格納されている値は不定値ですが、(blob-4)もレジストリ内でありアクセス可能である事は保証出来ます。
		srl		%r12, 8					;//%r12[31:24] := 0,        %r12[23:16] := sizeH, %r12[15:8] := sizeM, %r12[7:0] := sizeL			┘
		add		%r12, 1					;//%r12        := size++	(バイト数-1)⇒バイト数に変換する。
REG_get_blob_size_RET:							;//
		ret.d							;//return         size,又は,0
		ld.w		%r10, %r12				;//%r10        := size,又は,0									*delay*
");
#endif//PIECE
