/*	
 *	clippce.h
 *
 *	P/ECE専用ルーチンを集めました。
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2017 Naoyuki Sawa
 *
 *	* Wed Apr 24 09:26:00 JST 2002 Naoyuki Sawa
 *	- 作成開始。
 *	* Sun Jul 28 11:16:00 JST 2002 Naoyuki Sawa
 *	- PAD_AB/TRG_ABの定義を追加。
 *	* Thu May  1 05:20:00 JST 2003 Naoyuki Sawa
 *	- APPSYSVERの再定義を追加。
 *	* Mon Nov 24 06:00:00 JST 2003 Naoyuki Sawa
 *	- SPEAKER_FREQUENCYの定義を追加。
 *	* Thu Nov 27 06:00:00 JST 2003 Naoyuki Sawa
 *	- my_unzip()にufi_out引数を追加。
 *	* Mon Mar  8 12:30:00 JST 2004 Naoyuki Sawa
 *	- stream_play()にfram4引数を追加。
 *	* Mon Mar 15 12:30:00 JST 2004 Naoyuki Sawa
 *	- mmap()関数を追加しました。
 *	* Mon Apr 19 20:17:00 JST 2004 Naoyuki Sawa
 *	- LEBYTE()/LEHALF()/LEWORD()/BEBYTE()/BEHALF()/BEWORD()マクロを追加しました。
 *	  各ファイル毎に定義していた同機能のマクロは、いずれこれに置き換える予定です。
 *	* Mon May 17 19:00:00 JST 2004 Naoyuki Sawa
 *	- /usr/PIECE/sysdev/pcekn/pcekn.hより、ENTER_CS/LEAVE_CS等の宣言をコピー。
 *	* Sun Jun 6 05:37:00 JST 2004 Naoyuki Sawa
 *	- /usr/PIECE/sysdev/pcekn/pcekn.hより、SET_SIL0等の宣言をコピー。
 *	* Thu Jun 17 06:44:00 JST 2004 Naoyuki Sawa
 *	- pceHeapRealloc()の宣言を追加しました。
 *	  PieceSystem 1.20 現在の /usr/PIECE/include/piece.h は、pceHeapRealloc()の宣言が抜けています。
 *	* Thu Jun 17 07:27:00 JST 2004 Naoyuki Sawa
 *	  PieceSystem 1.20 現在のpceHeapRealloc()にはバグがあることがわかったので、やっぱり宣言を取りやめました。
 *	* Sun Oct 31 13:19:00 JST 2004 Naoyuki Sawa
 *	- LEBYTE()/LEHALF()/LEWORD()/BEBYTE()/BEHALF()/BEWORD()マクロをclipmisc.hへ移動しました。
 *	* Sun Dec 12 09:59:00 JST 2004 Naoyuki Sawa
 *	- BLOCKSIZE、SPEAKER_FREQUENCYはP/ECE特有の定数ですが、Win32版テストプログラムからも参照するために、
 *	  clippce.hからclipmisc.hへ移動しました。
 *	* Sat Jan 22 20:57:00 JST 2005 Naoyuki Sawa
 *	- PAD_CD/TRG_CDの定義を追加。
 *	* Mon Mar  7 04:09:00 JST 2005 Naoyuki Sawa
 *	- turbo()関数に、FLASHとSRAMの出力ディセーブル時間変更機能を追加しました。
 *	  P/ECE Kernelは、FLASHとSRAMの出力ディセーブル時間を1.5サイクルに設定しますが、0.5サイクルで大丈夫です。
 *	  FLASHの出力ディセーブル時間は、仕様上20ns必要で、0.5サイクル(21ns)で充分です。
 *	  SRAMの出力ディセーブル時間は、仕様上25ns必要で、0.5サイクル(21ns)ではオーバークロックなのですけれど、
 *	  実際のプログラムで試してみた限りでは、動作するようです。(そもそも48MHzだってオーバークロックですし…)
 *	- なお、今回の変更により、turbo()関数の引数のmodeビット割り当てを変更しています。
 *	  これまでのビット割り当ては、
 *		D0: 24/48MHz
 *		D1: SRAM Wait
 *		D2: FLASH Wait
 *	  でしたが、変更後のビット割り当ては、
 *		D0: SRAM Wait
 *		D1: SRAM OutputDisable
 *		D2: FLASH Wait
 *		D3: FLASH OutputDisable
 *		D4: 24/48MHz
 *	  となりました。注意してください。
 *	* Tue Aug 23 18:31:00 JST 2005 Naoyuki Sawa
 *	- get_psr(),set_psr()を追加しました。
 *	- ENABLED,DISABLEDマクロを追加しました。
 *	* Sat Sep 03 21:40:00 JST 2005 Naoyuki Sawa
 *	- mmap()関数をマクロ化しました。
 *	  これまでは、mmap()関数がfile_defrag()を参照していたため、デフラグ機能が不要なアプリケーションにもclipdfrg.oがリンクされていました。
 *	  mmap()関数のマクロ化により、デフラグ機能が不要なアプリケーションにはclipdfrg.oがリンクされなくなり、2KB弱のメモリ節約となりました。
 *	* Sat Sep 10 05:56:00 JST 2005 Naoyuki Sawa
 *	- timer_start()の戻り値を、0～31 → 1～32 に変更しました。
 *	* Sat Sep 17 06:09:00 JST 2005 Naoyuki Sawa
 *	- timer_start()に、コールバック引数の指定を追加しました。
 *	- 拡張タイマの同時使用数を、32個→16個に減らしました。
 *	* Fri Sep 23 19:57:00 JST 2005 Naoyuki Sawa
 *	- ユーティリティ：タイムアウト処理を追加しました。
 *	* Sun Sep 25 13:40:00 JST 2005 Naoyuki Sawa
 *	- ユーティリティ：タイムアウト処理に、CONTINUE_TIMEOUT、RESTART_TIMEOUTを追加しました。
 *	* Thu Jul 13 07:19:22 JST 2006 Naoyuki Sawa
 *	- snprintf(),vsnprintf()の宣言を追加しました。(実装はclipprnt.cにあります)
 *	* Tue Dec 05 14:59:42 JST 2006 Naoyuki Sawa
 *	- オブジェクトを単一色で描くための、DRW_MASKフラグを定義しました。
 *	  キャラクタのドロップシャドウや、ダメージ時のフラッシュ等に利用できます。
 *	- render_object()をDRW_MASKに対応しました。
 *	  sprite_draw()もrender_object()を利用しているので、sprite_draw()にもDRW_MASK指定可能です。
 *	* Tue Dec 05 16:05:22 JST 2006 Naoyuki Sawa
 *	- draw_object()は使用頻度が低いので、メモリ節約のために削除しました。
 *	* Sun Dec 10 21:40:13 JST 2006 Naoyuki Sawa
 *	- resource_address()を追加しました。
 *	* Wed Dec 20 18:08:11 JST 2006 Naoyuki Sawa
 *	- sound_play()のdata引数を、(const unsigned char*)→(void*)に変更しました。
 *	  処理内容は変化ありません。
 *	* Thu Mar 01 01:53:43 JST 2007 Naoyuki Sawa
 *	- sound_stat()を追加しました。
 *	* Mon Dec 10 14:36:46 JST 2007 Naoyuki Sawa
 *	- atexit()に複数の関数を登録できるよう変更しました。
 *	* Mon Dec 31 16:36:08 JST 2007 Naoyuki Sawa
 *	- アプリケーションパッドセンシングを追加しました。
 *	* Thu Mar 12 22:15:08 JST 2009 Naoyuki Sawa
 *	- PAD_LR,PAD_UD,PAD_LRUD,PAD_ABCDの定義を追加しました。
 *	  TRG_LR,TRG_UD,TRG_LRUD,TRG_ABCDの定義を追加しました。
 *	* Mon Mar 30 19:21:12 JST 2009 Naoyuki Sawa
 *	- PieceSystem1.20現在のpceHeapRealloc()バグ修正パッチを適用しました。
 *	  アプリケーションからpceHeapRealloc()が正常に利用できるようになったので、pceHeapRealloc()の宣言コメントアウトを解除しました。
 *	* Sun Jun 21 21:42:18 JST 2009 Naoyuki Sawa
 *	- 今回のpceAppProc()の開始時刻を記録する、apptm_wk変数を追加しました。
 *	  変数名は、/usr/PIECE/sysdev/pcekn/runapp.cで使われている、同じ名前・同じ用途のカーネル変数に由来しています。
 *	- 2009/06/21現在、clipidle.cモジュールで、残りタイムスライスを算出するために利用しています。
 *	* Sat Jul 04 21:25:58 JST 2009 Naoyuki Sawa
 *	- lfind()、lsearch()を追加しました。
 *	* Mon Jul 06 23:33:17 JST 2009 Naoyuki Sawa
 *	- strupr()、strlwr()を追加しました。
 *	* Thu Jul 09 14:23:04 JST 2009 Naoyuki Sawa
 *	- splitpath()、makepath()を追加しました。
 *	* Wed Jul 15 14:39:47 JST 2009 Naoyuki Sawa
 *	- render_font_framed_param[]を追加しました。
 *	* Wed Oct 03 23:51:13 JST 2012 Naoyuki Sawa
 *	- isblank()を追加しました｡
 *	* Sat Oct 20 20:15:27 JST 2012 Naoyuki Sawa
 *	- ffs()を追加しました。
 *	* Tue Oct 30 00:38:57 JST 2012 Naoyuki Sawa
 *	- STDIN_FILENO,STDOUT_FILENO,STDERR_FILENOの定義を追加しました。
 *	- fileno(),isatty()を追加しました。実装は、clipio.c にあります。
 *	* Sun Nov 18 13:59:36 JST 2012 Naoyuki Sawa
 *	- strnlen()とstrndup()を追加しました。
 *	* Mon Jul 15 20:32:11 JST 2013 Naoyuki Sawa
 *	- sound_att()を追加しました。
 *	* Thu Jul 25 22:42:07 JST 2013 Naoyuki Sawa
 *	- SOUND_MAXCHの定義を追加しました。
 *	* Mon Jan 13 19:05:18 JST 2014 Naoyuki Sawa
 *	- lfind()とlsearch()の宣言を、clippce.h⇒include/search.hへ分離しました。
 *	- lfind()とlsearch()の実装を、clippce.c⇒clipsrch.cへ分離しました。
 *	* Sun Mar 09 14:07:14 JST 2014 Naoyuki Sawa
 *	- stdin_read()を追加しました。
 *	  この機能追加に伴い、tool/dstderr にも機能追加を行いました。
 *	  詳細は、tool/dstderr/dstderr.c の同日のコメントを参照してください。
 *	* Tue Jul 01 22:19:13 JST 2014 Naoyuki Sawa
 *	- ppd_playback_time()を追加しました。
 *	* Sat Aug 16 15:46:20 JST 2014 Naoyuki Sawa
 *	- get_psr(),set_psr()をmachine.hで実装し、当モジュールの実装は削除しました。
 *	- ストリームコールバック処理中にタイマ割り込みが発生しないよう修正しました。
 *	* Sat Sep 20 08:44:17 JST 2014 Naoyuki Sawa
 *	- FRAM4領域退避用メモリを1個にし、全体から共用できるようになりました。
 *	  詳細は、clippce.cの「ファイル書き込み系関数の排他制御」のコメントと「FRAM4領域の退避復元」を参照してください。
 *	* Mon Sep 22 00:22:24 JST 2014 Naoyuki Sawa
 *	- ストリームフィルタを追加しました。
 *	- 使用目的は、clipaudi.cモジュールの機能と組合せて、展開したサウンドデータをUSB Audio Deviceへ送り込むことです。
 *	  ただし、上記の使用目的に限らず、展開したサウンドデータをさらに変更したり、別の処理に送る用途にも使えそうです。
 *	* Mon Sep 29 23:30:57 JST 2014 Naoyuki Sawa
 *	- malloc_usable_size()を追加しました。
 *	* Thu Oct 02 01:02:39 JST 2014 Naoyuki Sawa
 *	- snprintf(),vsnprintf()の宣言をclippce.h⇒include/stdio.hへ移しました。
 *	* Tue Nov 04 23:07:44 JST 2014 Naoyuki Sawa
 *	- pdwait()を追加しました。
 *	* Fri Dec 19 21:35:23 JST 2014 Naoyuki Sawa
 *	- stream_play(),stream_stop()の中のDISABLE/ENABLEをENTER_CS/LEAVE_CSに変更しました。
 *	  ここでは実質どちらでも問題ありませんが、万一割り込み禁止状態で呼ばれた場合にENTER_CS/LEAVE_CSの方が安全です。
 *	  なぜDISABLE/ENABLEにしていたのか覚えていないのですが、多分ENTER_CS/LEAVE_CSを作る前に書いた処理だと思います。
 *	* Fri Dec 19 22:06:53 JST 2014 Naoyuki Sawa
 *	- 割り込みレベル設定を追加しました。
 *	- stream_fill()が、割り込みレベル設定の関数を利用するように変更しました。動作内容はこれまでと変わりません。
 *	* Fri Dec 19 22:30:18 JST 2014 Naoyuki Sawa
 *	- ヒープマネージャAPIの排他制御を、ENTER_CS/LEAVE_CS⇒ENTER_IL(1)/LEAVE_ILに変更しました。
 *	- ファイル書き込み系関数の排他制御を、ENTER_CS/LEAVE_CS⇒ENTER_IL(1)/LEAVE_ILに変更しました。
 *	* Mon Dec 22 21:06:44 JST 2014 Naoyuki Sawa
 *	- 「ヒープマネージャAPIが排他制御されない問題」(Fri Dec 19 22:30:18 JST 2014)を回避するために、STREAMINFO.busyを廃止し、擬似的な割り込みレベル1を用いてstream_fill()を実行するように変更しました。
 *	- stream_fill()内の割り込みレベル設定処理を削除しました。
 *	  stream_fill()は、stream_play()内のENTER_CS～LEAVE_CS区間,及び,hdm0_isr()内の(IL=1,IE=1)区間からしか呼ばれなくなったので、割り込みレベルを設定しなくても既に(IL≧1)の要件を満たしているからです。
 *	* Tue Dec 23 15:42:08 JST 2014 Naoyuki Sawa
 *	- 高速RAMにコードを転送する処理を、clippce.cのapp_init()⇒cstart.cのpceAppInit00()へ移動しました。
 *	  app_init()で行っても問題無いですが、より早くpceAppInit00()で行う方がより確実だと思ったからです。
 *	* Wed Dec 24 19:14:00 JST 2014 Naoyuki Sawa
 *	- 「タイマ割り込み処理中の多重割り込み許可」を追加しました。
 *	* Wed Dec 24 20:09:42 JST 2014 Naoyuki Sawa
 *	 - stream_isr:を3命令節約しました。
 *	* Thu Dec 25 00:13:22 JST 2014 Naoyuki Sawa
 *	- stream_play()の第3引数をfram4⇒flagsに変更しました。
 *	* Fri Dec 26 21:45:54 JST 2014 Naoyuki Sawa
 *	- 「8ビットプログラマブルタイマ割り込みの一元管理」を追加しました。
 *	* Sat Dec 27 14:10:18 JST 2014 Naoyuki Sawa
 *	- 高精度パッドセンシングが「8ビットプログラマブルタイマ割り込みの一元管理」を使用するように変更しました。
 *	* Sat Dec 27 17:13:55 JST 2014 Naoyuki Sawa
 *	- internal_8tu_isr()と_internal_8tu_isr()を統合して、internal_8tu_isr()一関数にし、最適化しました。
 *	* Sat Dec 27 21:06:26 JST 2014 Naoyuki Sawa
 *	- 割り込みサービスルーチンの無駄なレジスタ保存を削除しました。
 *	* Sun Dec 28 13:06:59 JST 2014 Naoyuki Sawa
 *	- 拡張タイマテーブルを、固定割り当て⇒動的割り当てに変更しました。
 *	  拡張タイマを少ししか使わないアプリケーションにとっては、メモリを節約できるメリットが有ります。
 *	  拡張タイマをたくさん使うアプリケーションにとっては、使用数の制限が無くなるメリットが有ります。
 *	- 拡張タイマを使っている、既存アプリケーションに対する影響は無いので、修正する必要は有りません。
 *	* Wed Dec 31 00:00:35 JST 2014 Naoyuki Sawa
 *	- P/ECEカーネルのNMIサービスルーチンをフックして高速化するルーチンを作成しました。
 *	  効果が薄いのでこの方法は使わないことにしましたが、コメントとして残しておきます。
 *	* Sun Jan 04 13:35:55 JST 2015 Naoyuki Sawa
 *	- 「割り込みサービスルーチンを定義するマクロ」を追加しました。
 *	- ISR_DEF()マクロを使って割り込みサービスルーチンを定義すると、以下の利点が有ります。
 *	  1. C関数だけで割り込みサービスルーチンを定義できます。明示的にasmブロックを書く必要が有りません。
 *	  2. レジスタ退避処理が共通処理になり、コードサイズを節約できます。
 *	* Sun Jan 04 13:57:08 JST 2015 Naoyuki Sawa
 *	- '割り込み禁止(NMIも)'のマクロ名を、DI/EI⇒DISABLE2/ENABLE2に変更しました。
 *	  変更した理由は、DI/EIでは単純過ぎて、他のライブラリのヘッダファイルの定義と衝突する恐れがあると思ったからです。
 *	  また、これまでに作ったCPUエミュレーションモジュールのソースの中でも、DI/EIの名称を使用している箇所が有ります。
 *	  動作上は問題無いのですが、DI/EIを検索した時に検索結果にそれらが含まれてしまって、紛らわしい問題が有りました。
 *	  以上のような問題を回避するため、'割り込み禁止(NMIも)'のマクロ名を、他と混同し辛い名称に変更することにしました。
 *	  DISABLE2/ENABLE2も単純な名称ではあるのですが、P/ECE開発環境の標準インクルードファイル'\usr\PIECE\include\s1c33cpu.h'が、DISABLE/ENABLEという名称を定義しているので、それに準じることにしました。
 *	* Wed Jan 07 21:18:08 JST 2015 Naoyuki Sawa
 *	- strdup(),strcasecmp(),strncasecmp()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
 *	  strcasecmp(),strncasecmp()は本当はstrings.hで宣言すべきなのですが、P/ECEにはstrings.hが無いのでinclude/string.hで宣言することにしました。
 *	- strnlen(),strndup()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
 *	- ismbblead(),ismbbtrail(),iscsym(),iscsymf(),isblank()の宣言をclippce.h⇒include/ctype.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
 *	  ismbblead(),ismbbtrail()は本当はmbctype.hで宣言すべきなのですが、P/ECEにはmbctype.hが無いのでinclude/ctype.hで宣言することにしました。
 *	- strupr(),strlwr()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
 *	- splitpath(),makepath()の宣言をclippce.h⇒include/stdlib.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
 *	- ffs()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
 *	  ffs()は本当はstrings.hで宣言すべきなのですが、P/ECEにはstrings.hが無いのでinclude/string.hで宣言することにしました。
 *	- fileno(),isatty()の宣言を、clippce.h⇒include/stdio.hへ移動しました。実装はclipio.cにあります。
 *	  isatty()は本当はio.hかunistd.hで宣言すべきなのですが、P/ECEにはio.hもunistd.hも無いのでinclude/stdio.hで宣言することにしました。
 *	* Tue May 26 21:15:26 JST 2015 Naoyuki Sawa
 *	- 4x5ピクセルフォントを追加しました。
 *	- P/ECEのフォントは2番までですが、pceFontGetAdrs()とpceFontSetType()をフックする事により、3番に4x5ピクセルフォントを追加しました。
 *	  主にrender_printf()等で使用する事を想定していますが、上記のAPIをフックしているので、pceFontPrintf()等の標準APIでも使用可能です。
 *	- 4x5ピクセルフォントには、「Version 0」(http://ver0.sakura.ne.jp/)さんの『極小フォント』(http://ver0.sakura.ne.jp/illust/extra-small-font.html)を使用させて頂きました。
 *	  それに伴い、4x6ピクセルフォントも『極小フォント』を使うように変更しました。これまで4x6ピクセルフォントは「WentWayUp: WebLog (http://wentwayup.tamaliver.jp/)」さんの、
 *	  『KanaFive(http://wentwayup.tamaliver.jp/e59624.html)』を使用させて頂いていたのですが、4x5ピクセルフォントと4x6ピクセルフォントの書体を統一するためです。
 *	- 今回使用させて頂いた『極小フォント』を、/clip/keep/極小フォント.7zに保存しておきました。
 *	- これまでは、USE_KANAFIVE_ASCIIとUSE_VOLATILE_FONTで機能の有効,無効を切り替えてコンパイルするようにしていましたが、今回の変更と同時にこれらの機能を有効に固定しました。
 *	  これまで使って来て、これらの機能も有用で、今後、無効にする必要は無いと判断したからです。
 *	* Tue Nov 17 21:10:26 JST 2015 Naoyuki Sawa
 *	- ENTER_CS,LEAVE_CSの定義をclippce.h⇒clipmisc.hへ移動しました。
 *	  clipmisc.hにVC++6.0プロジェクト用のENTER_CS,LEAVE_CSの定義を追加した事に伴い、P/ECE用のENTER_CS,LEAVE_CSもclipmisc.hの同じ場所で定義する方が管理し易いと思うからです。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'～'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 *	- 「ユーティリティ：拡張タイマ」を、(clippce.h,clippce.c)⇒(cliptimr.h,cliptimr.c)へ移動しました。
 *	  移動する事にした理由は、timer_start()とtimer_stop()を、Win32にも対応したからです。
 *	  (clippce.h,clippce.c)はP/ECE専用でありWin32プロジェクトには含められないので、別のファイルへ分離しました。
 *	* Tue Nov 24 21:41:25 JST 2015 Naoyuki Sawa
 *	- unistd.h,cliplibc.cにてPOSIX仕様のusleep()を実装した事に伴い、既存のclippce.h,clippce.cの独自仕様のusleep()を削除しました。
 *	* Thu Mar 03 21:33:11 JST 2016 Naoyuki Sawa
 *	- pad_get()内の無駄な処理を削除しました。
 *	  これまで、'if(trg&mask){'が否定された時しか通らない処理の中で'trg&=~mask'を行っていました。
 *	  'if(trg&mask){'が否定されたという事は必ず'!(trg&mask)'ですから、'trg&=~mask'を行う事は(害はないが)無駄でした。
 *	* Thu Jun 02 21:20:46 JST 2016 Naoyuki Sawa
 *	- 「main()を呼び出す前に初期化関数を実行する仕組み」を追加しました。
 *	* Fri Jun 03 21:47:06 JST 2016 Naoyuki Sawa
 *	- 「main()が終了した後に終了時関数を実行する仕組み」を追加しました。
 *	* Fri Jul 15 21:06:38 JST 2016 Naoyuki Sawa
 *	- ヌルレンダラーの定数データ「null_render」を定義しました。
 *	  実際の描画を行わずに、描画関数の戻り値だけを取得したい場合に、空の描画対象として指定するために、汎用的に利用出来ます。
 *	  現在の所、ヌルレンダラーを指定する意味が有ると思う関数は、文字列描画関数だけです。
 *	  文字列描画関数は、戻り値として描画した文字列のサイズを返すので、実際に描画せずに、文字列のサイズだけを取得するために、ヌルレンダラーを指定すると便利です。
 *	  具体的には、下記の関数に対して、ヌルレンダラーを指定する意味が有ると思います。
 *	  ・render_font(),render_string(),render_printf(),render_font_framed(),render_string_framed(),render_printf_framed()
 *	  ・render_font7(),render_string7(),render_printf7(),render_font7_framed(),render_string7_framed(),render_printf7_framed()
 *	  ・render_font8(),render_string8(),render_printf8(),render_font8_framed(),render_string8_framed(),render_printf8_framed()	下記のrender_object()に関する説明を参照せよ。
 *	  ・render_fontx(),render_stringx(),render_printfx(),render_fontx_framed(),render_stringx_framed(),render_printfx_framed()	下記のrender_object()に関する説明を参照せよ。
 *	- RENDER構造体のフィールドを変更する関数には、null_renderを引き渡さないように注意して下さい。
 *	  例えば、render_save(),render_restore()等には、null_renderを引き渡さないように注意して下さい。
 *	  (もとより、render_save(),render_restore()は戻り値が無いので、ヌルレンダラーを指定する事自体が無意味であり、これらの関数にヌルレンダラーを引き渡す事は無いと思いまずが。)
 *	  ただし特例として、render_object()に対してヌルレンダラーを指定する事は、(厳密には良くないのですが)、動作上は問題ありません。
 *	  render_object()は、一時的にnull_render.context->textureを書き換えますが、元に戻すからです。
 *	  例えば、render_printf8()等にnull_renderを指定した場合、間接的にrender_object()が呼び出され、render_object()に対してnull_renderが引き渡されますが、正常に動作します。
 *	- ヌルレンダラーの使用例は、以下の通りです。
 *	  <例>
 *	  │//文字列の中心が目標位置になるように、文字列を描画するサンプル
 *	  │void test() {
 *	  │  int xy, x, y;
 *	  │  //目標位置を示すためのクロスハッチを描画する。
 *	  │  x = DISP_X / 2;
 *	  │  y = DISP_Y / 2;
 *	  │  render_line(&render, 0, y, DISP_X, y, 1);
 *	  │  render_line(&render, x, 0, x, DISP_Y, 1);
 *	  │  //文字列の描画サイズを取得するために、ヌルレンダラーへのダミー描画を行う。
 *	  │  xy = render_printf(&null_render, 0, 0, 0, 0, "日本語\n数値 %'d\nAB12", (now * now));
 *	  │  //                               ~~~~     ~ null_renderへ描画する時の、x,y,colorは何でも構いません。
 *	  │  //文字列の描画サイズから、文字列の中心を目標位置として描画するための、描画原点座標を求める。
 *	  │  //ここの計算式を変えれば、文字列の右下を目標位置としたり、文字列の左下を目標位置とする事も可能です。
 *	  │  x -= LOHALF(xy) / 2;
 *	  │  y -= HIHALF(xy) / 2;
 *	  │  //文字列を描画する。
 *	  │  render_printf(&render, x, y, 0, 3, "日本語\n数値 %'d\nAB12", (now * now));
 *	  │}
 *	  或いは、ヌルレンダラーを使わなくても、クリッピング領域を狭めたり、サーフェイス外を指定する事で、実際に描画せずに、文字列のサイズだけを取得する事は可能ではあるのですが、
 *	  ヌルレンダラーを指定する方が、意図が明確に判り、見た目に判り易いソースコードになると思います。
 *	- ヌルレンダラーの定義においては、極力、メモリを節約するように工夫しました。
 *	  もし工夫せずに、RENDER構造体とSURFACE構造体を定義すると、(24+52*8)+12=452バイトも消費してしまいます。
 *	  今回は、以下の工夫を行って、28バイトしか消費しないようにしました。
 *	  工夫1. RENDER.context_stack[]は1要素分しか使用しないので、定数データに含めませんでした。
 *	  工夫2. 1要素分のコンテキストは、RENDER.context_stack[0]を指すのではなく、下記の工夫3で重複させた領域を指すようにしました。
 *	  工夫3. RENDER構造体と、SURFACE構造体の、値が共通な部分を重複させて定義しました。
 *	  工夫4. 1要素分のコンテキストスタックの行列部分の値は不定値で構わないので、別のコード領域に重複させて、textureフィールドだけが確実にNULLの値を指すようにしました。
 *	  詳細は、clippce.c内のnull_renderを定義しているアセンブラブロックを参照して下さい。
 *	* Sat Feb 04 23:11:25 JST 2017 Naoyuki Sawa
 *	- 4x4ピクセルフォントを追加しました。
 *	- 追加した方法は、2015/05/26に4x5ピクセルフォントを追加た時と同じです。
 *	  詳細は、'Tue May 26 21:15:26 JST 2015'のコメントを参照して下さい。
 *	- 4x4ピクセルフォントには、「mu:die」(http://www2u.biglobe.ne.jp/~nemojun/)さんの、『3dot(font)』(http://www2u.biglobe.ne.jp/~nemojun/download/3dot.TTF)を使用させて頂きました。
 *	- 今回使用させて頂いた『3dot(font)』を、/clip/keep/3dot(font).7zに保存しておきました。
 */
#ifndef __CLIP_PCE_H__
#define __CLIP_PCE_H__

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

/*****************************************************************************
 *	定数・マクロ
 *****************************************************************************/

/* カーネル1.18→1.20 では、piece.h内のAPPSYSVERは1.18のまま変更されませんでした。
 * API仕様に変更がなかったからです。
 * しかし、いくつかのAPIでは、細かなバグフィクスが行われています。
 * 今回、カーネル側でのAPIバグフィクスに合わせて、CLiPライブラリ側での回避コードを削除しました。
 * 従って、カーネル1.20以上が必須です。
 * P/ECE標準ライブラリ内の__version_check()を使うと、カーネル1.18以上を通してしまいます。
 * そこで、カーネル1.20未満を弾く__version_check()を、自前で用意することにしました。
 * P/ECE標準ライブラリのversion_check.cソースを、CLiPライブラリ内に含めてあります。
 * ここで再定義したAPPSYSVERが使われるので、カーネル1.20未満を弾く__version_check()になります。
 * 今後、piece.hのAPPSYSVERが変更されたり、CLiPライブラリで必要なカーネルバージョンが変化したら、
 * APPSYSVERを適切に再定義してください。
 */
#undef  APPSYSVER				/* まずpiece.hでの定義を解除 */
#define APPSYSVER	VERSION(1, 20)		/* Ver 1.20 以上が必要       */

//#define BLOCKSIZE	4096			/* フラッシュメモリのセクタサイズ */
//→2004/12/12 Naoyuki Sawa clipmisc.hへ移動しました。

#define PAD_MASK	0x00ff			/* PAD_LF|RI|UP|DN|A|B|START|SELECT */
#define TRG_MASK	0xff00			/* TRG_LF|RI|UP|DN|A|B|START|SELECT */
#define PAD_AB		(PAD_A  | PAD_B )
#define TRG_AB		(TRG_A  | TRG_B )
#define PAD_CD		(PAD_C  | PAD_D )
#define TRG_CD		(TRG_C  | TRG_D )
#define PAD_ABCD	(PAD_AB | PAD_CD)
#define TRG_ABCD	(TRG_AB | TRG_CD)
#define PAD_LR		(PAD_LF | PAD_RI)
#define TRG_LR		(TRG_LF | TRG_RI)
#define PAD_UD		(PAD_UP | PAD_DN)
#define TRG_UD		(TRG_UP | TRG_DN)
#define PAD_LRUD	(PAD_LR | PAD_UD)
#define TRG_LRUD	(TRG_LR | TRG_UD)

//#define SPEAKER_FREQUENCY	16000		/* P/ECEスピーカー出力周波数[Hz] */
//→2004/12/12 Naoyuki Sawa clipmisc.hへ移動しました。

/* * pceUSBCOMGetStat()の戻り値には、USBCOMのOpen状態を示すフラグも含まれているのですが、
 *   piece.hではこれらのフラグに対するマスクが定義されていない(BIOS1.18現在)ので、定義しておきます。
 * * \usr\PIECE\sysdev\pcekn\usbcom.cの56行目あたりの「mystat」と「pcstat」の定義、および、
 *   \usr\PIECE\tools\isd\pieceif.hの47行目あたりの「pistat」と「mystat」の定義に相当します。
 *   「mystat」はP/ECE側を指す場合(usbcom.c)とPC側を指す場合(pieceif.h)があってわかりづらいので、
 *   より明示的な「pistat」「pcstat」の名前に合わせて、「UCS_PISTAT」「UCS_PCSTAT」としました。
 * * UCS_RXWAIT/ING/DONE、UCS_TXWAIG/ING/DONEに対するマスクもあった方が便利なので、定義しておきます。
 */
#define UCS_RXSTAT	0x000000ff	/* UCS_RXWAIT/UCS_RXING/UCS_RXDONEに対するマスク    */
#define UCS_TXSTAT	0x0000ff00	/* UCS_TXWAIT/UCS_TXING/UCS_TXDONEに対するマスク    */
#define UCS_PISTAT	0x00ff0000	/* 0以外なら、P/ECE側でUSBCOMがOpenされている       */
#define UCS_PCSTAT	0xff000000	/* 0以外なら、P/ECE側でOpen後にPC側からもOpenされた */

//{{2015/01/04変更:'割り込み禁止(NMIも)'のマクロ名を、DI/EI⇒DISABLE2/ENABLE2に変更しました。
//#define DI do { DISABLE; bWD_WP_WRWD = 1; bWD_EN_EWD = 0; } while(0) /* 割り込み禁止(NMIも) */
//#define EI do { ENABLE ; bWD_WP_WRWD = 1; bWD_EN_EWD = 1; } while(0) /* 割り込み許可(NMIも) */
//↓2015/01/04変更:'割り込み禁止(NMIも)'のマクロ名を、DI/EI⇒DISABLE2/ENABLE2に変更しました。
//↓割り込み禁止の処理順序は、'INT禁止⇒NMI禁止'の順序にするのが安全です。
//↓割り込み許可の処理順序は、'NMI許可⇒INT許可'の順序にするのが安全です。
//↓INT割り込み処理の中で、pceTimerGetCount()を使って時間待ちをする可能性があるからです。
//↓もし、'NMI禁止⇒INT禁止'の順序にすると、NMI禁止とINT禁止の間にINTが発生し、そのINT割り込み処理の中でpceTimerGetCount()を使って時間待ちを行った場合、時間待ちが終了しなくなります。
//↓もし、'INT許可⇒NMI許可'の順序にすると、INT許可とNMI許可の間にINTが発生し、そのINT割り込み処理の中でpceTimerGetCount()を使って時間待ちを行った場合、時間待ちが終了しなくなります。
//↓そのような問題を避けるために、前述の処理順序にするのが安全です。
#define DISABLE2 do { DISABLE; bWD_WP_WRWD = 1; bWD_EN_EWD = 0; } while(0) /* 割り込み禁止(NMIも) */
#define ENABLE2  do { bWD_WP_WRWD = 1; bWD_EN_EWD = 1; ENABLE ; } while(0) /* 割り込み許可(NMIも) */
//}}2015/01/04変更:'割り込み禁止(NMIも)'のマクロ名を、DI/EI⇒DISABLE2/ENABLE2に変更しました。

//{{2014/08/16削除:get_psr(),set_psr()をmachine.hで実装し、当モジュールの実装は削除しました。
//int  get_psr();			/* %psrレジスタを取得します */
//void set_psr(int psr);		/* %psrレジスタを設定します */
//#define ENABLED  (get_psr()&0x10)	/* 割り込み許可状態ならば真 */
//#define DISABLED (!(ENABLED))		/* 割り込み禁止状態ならば真 */
//}}2014/08/16削除:get_psr(),set_psr()をmachine.hで実装し、当モジュールの実装は削除しました。

extern unsigned char _def_vbuff[DISP_X * DISP_Y]; /* 汎用ワークとして利用(pceapi.lib内にあります) */

//{{2015/11/17削除:ENTER_CS,LEAVE_CSの定義をclippce.h⇒clipmisc.hへ移動しました。
///* /usr/PIECE/sysdev/pcekn/pcekn.hより宣言のみコピー。
// * 実体はpceapi.libに含まれているので、ユーザーアプリケーションからも利用できます。
// * [使い方]
// *	ENTER_CS; // “__cs__ = PSR; PSR(IE) = 0;”に相当
// *	// 割り込み禁止が必要な処理を行う
// *	LEAVE_CS; // “PSR = __cs__;”に相当
// */
//typedef unsigned long CRITICAL_SECTION;
//void pceSyncEnterCriticalSection(CRITICAL_SECTION* pcs); /* 割り込み許可状態を保存→割り込み禁止 */
//void pceSyncLeaveCriticalSection(CRITICAL_SECTION* pcs); /* 割り込み許可状態を復元 */
//#define ENTER_CS do { CRITICAL_SECTION __cs__; pceSyncEnterCriticalSection(&__cs__)
//#define LEAVE_CS pceSyncLeaveCriticalSection(&__cs__); } while(0)
//}}2015/11/17削除:ENTER_CS,LEAVE_CSの定義をclippce.h⇒clipmisc.hへ移動しました。

/* /usr/PIECE/sysdev/pcekn/pcekn.hより宣言のみコピー。
 * 実体はpceapi.libに含まれているので、ユーザーアプリケーションからも利用できます。
 */
typedef signed long SYNCVAR;
SYNCVAR pceSyncSafetyAddition(SYNCVAR* pval, SYNCVAR delta); /* 割り込み許可状態保存→割り込み禁止→変数値増減→割り込み許可状態復元 */
void pceSyncSafetySetIL(int level); /* 割り込みプライオリティ設定→割り込み許可 */
#define SET_SIL0 pceSyncSafetySetIL(0)
#define SET_SIL1 pceSyncSafetySetIL(1)
#define SET_SIL2 pceSyncSafetySetIL(2)
#define SET_SIL3 pceSyncSafetySetIL(3)
#define SET_SIL4 pceSyncSafetySetIL(4)
#define SET_SIL5 pceSyncSafetySetIL(5)
#define SET_SIL6 pceSyncSafetySetIL(6)
#define SET_SIL7 pceSyncSafetySetIL(7)

///* PieceSystem 1.20 現在の /usr/PIECE/include/piece.h は、pceHeapRealloc()の宣言が抜けているので、ここで宣言します。 */
//int pceHeapRealloc(void* memp, unsigned long size);
//→* Thu Jun 17 07:27:00 JST 2004 Naoyuki Sawa
//→  PieceSystem 1.20 現在のpceHeapRealloc()にはバグがあるので、うっかり使ってしまわないよう、やっぱり宣言しないことにしました。
//→  バグの内容については、clippce.cのrealloc()内コメントを参照してください。
//→* Mon Mar 30 19:21:12 JST 2009 Naoyuki Sawa
//→- PieceSystem1.20現在のpceHeapRealloc()バグ修正パッチを適用しました。
//→  アプリケーションからpceHeapRealloc()が正常に利用できるようになったので、pceHeapRealloc()の宣言コメントアウトを解除しました。
int pceHeapRealloc(void* memp, unsigned long size);

/****************************************************************************
 *	スタックレイアウト
 ****************************************************************************/

/* 先頭のシグネチャは、メモリダンプからstack_infoの位置を探すためのものです。
 * PCのツールdmalloc.exeに、スタック情報表示機能を持たせました。(2004/12/29)
 */

/*{{アセンブラコードから参照しているので、レイアウト固定です*/
typedef struct _STACKINFO {
	char signature[8];	/* + 0,8: シグネチャ"STACKINF"固定 */
	/* システムスタック */
	int* sysstack_top;	/* + 8,4: 先頭アドレス */
	int* sysstack_end;	/* +12,4: 終端アドレス */
	/* ユーザースタック */
	int* usrstack_top;	/* +16,4: 先頭アドレス */
	int* usrstack_end;	/* +20,4: 終端アドレス */
	/* スタックポインタ */
	int* ssp;		/* +24,4: システムスタックポインタ */
	int* usp;		/* +28,4: ユーザースタックポインタ */
} STACKINFO;			/* =32 */
/*}}アセンブラコードから参照しているので、レイアウト固定です*/

/* アプリケーションからは参照のみ。書き換えないでください。 */
extern STACKINFO stack_info;

/*****************************************************************************
 *	P/ECE専用・擬似mainフレームワーク
 *****************************************************************************/

//{{2009/06/21:追加
extern int apptm_wk; /* 今回のpceAppProc()の開始時刻 */
//}}2009/06/21:追加

/* アプリケーション定義のエントリポイントです。
 * [out]
 *	戻り値		終了コード。
 * [note]
 *	* アプリケーションを終了するには、二通りの方法があります。
 *	  1. main()が制御を返す。
 *	  2. pceAppReqExit()を呼んだ後、yield()を呼ぶ。
 */
int main();

/* システムに制御を譲ります。
 * [note]
 *	* アプリケーションは、定期的にyield()を呼ばなければいけません。
 */
void yield();

/* プログラム終了時に実行する関数を指定します。
 * [in]
 *	func		関数へのポインタ。
 * [out]
 *	戻り値		正しく登録できたら0を返します。
 *			失敗したら0以外の値を返します。
 *			→デバッグを容易にするために、エラーメッセージを表示して終了するよう変更。
 * [note]
 *	* 現在の実装では、登録できる関数は一つだけです。
 *	  すなわち、atexit()を複数回呼ぶと、二回目以降は失敗します。
 *	  →2007/12/10:atexit()に複数の関数を登録できるよう変更しました。登録数の上限は「4」です。
 */
int atexit(void (*func)());

/* pceAppNotify()が呼ばれたときに実行する関数を指定します。
 * [in]
 *	func		関数へのポインタ。
 * [out]
 *	戻り値		正しく登録できたら0を返します。
 *			失敗したら0以外の値を返します。
 * [note]
 *	* 現在の実装では、登録できる関数は一つだけです。
 *	  すなわち、atnotify()を複数回呼ぶと、二回目以降は失敗します。
 *	* アプリケーション定義のNotify関数がAPPNR_IGNOREを返した場合、
 *	  ライブラリ内のpceAppNotify()にて規定の処理が行われます。
 *	  アプリケーション定義のNotify関数がAPPNR_IGNORE以外の値を返した場合、
 *	  ライブラリ内のpceAppNotify()は何もせず、その値をシステムへ返します。
 */
int atnotify(int (*func)(int type, int param));

/****************************************************************************
 *	24MHz/48Mhzモード切り替え
 ****************************************************************************/

/* 24MHz/48Mhzモード切り替えを行います。
 * [in]
 *	mode[bit0]	0:SRAMアクセスを2WAITに切り替えます。(初期状態)
 *			1:SRAMアクセスを1WAITに切り替えます。
 *	mode[bit1]	0:SRAMの出力ディセーブル時間を1.5サイクルに切り替えます。(初期状態)
 *			1:SRAMの出力ディセーブル時間を0.5サイクルに切り替えます。
 *	mode[bit2]	0:FLASHアクセスを2WAITに切り替えます。(初期状態)
 *			1:FLASHアクセスを1WAITに切り替えます。
 *	mode[bit3]	0:FLASHの出力ディセーブル時間を1.5サイクルに切り替えます。(初期状態)
 *			1:FLASHの出力ディセーブル時間を0.5サイクルに切り替えます。
 *	mode[bit4]	0:24MHzモードに切り替えます。(初期状態)
 *			1:48MHzモードに切り替えます。
 * [out]
 *	戻り値		切り替える前の状態を返します。
 *			既に要求されたモードだった場合は、現在の状態を返します。
 * [note]
 *	* 48MHz動作中に利用できないAPIは、次のとおりです。
 *		pceCPUSetSpeed()
 *		pcePowerEnterStandby()
 *		pceTimerGetPrecisionCount()
 *		pceTimerAdjustPrecisionCount()
 *		pceFileCreate/Delete/WriteSec() ★重要!!★
 *		pceIR系API全て
 *	  これらのAPIを利用する場合は、いったん24MHzに戻してから利用してください。
 *	* CLiPライブラリのスタートアップルーチンは、48MHzへの切り替えを行いません。
 *	  必要に応じて、アプリケーション側で切り替えを行ってください。
 *	* アプリケーション終了時に48MHzになっていた場合、
 *	  CLiPライブラリのクリーンアップルーチンが24MHzに戻してから終了します。
 *	  アプリケーション側で24MHzに戻す必要はありません。
 */
int turbo(int mode);

/****************************************************************************
 *	アプリケーションパッドセンシング
 ****************************************************************************/

/* ボタン情報を取得します。
 * [out]
 *	戻り値		pcePadGet()に互換です。
 * [note]
 *	- pcePadGetProc()とpcePadGet()の両方を併せたような機能を持ちます。
 *	  すなわち、ボタン情報を更新し、ただちにその情報を返します。
 *	  pcePadGet()のような、更新無しで情報を取得する機能は用意していません。
 *	  もし必要ならば、アプリケーション内で変数に保持してください。
 */
int pad_get();

/* ボタンのオートリピート設定を行います。
 * [in]
 *	pad		設定を反映するボタン。(PAD_*の組み合わせ)
 *	delay		リピートが開始するまでの、pad_get()回数。(0 = リピート無し、1 = 最速 ～ 255 = 最遅)
 *	interval	リピート中のトリガ間隔の、pad_get()回数。(0 = リピート無し、1 = 最速 ～ 255 = 最遅)
 * [note]
 *	- delayに0を指定すると、リピート無しとなります。
 *	- delayに0以外、intervalに0を指定すると、一回だけリピートする不正な動作となるので、避けてください。
 *	- delay、または、intervalに、0未満や255超過の値を指定した場合の動作は、未定義です。
 */
void pad_set_repeat(int pad, int delay, int interval);

/*****************************************************************************
 *	FRAM4領域の退避復元
 *****************************************************************************/

/* FRAM4領域を退避,又は,復元する。
 * [in]
 *	flg		1=退避,0=復元
 * [note]
 *	- save_FRAM4(1)とsave_FRAM4(0)の呼び出しは、対でなければなりません。
 *	  save_FRAM4(1)～save_FRAM4(0)の呼び出しは、ネストしてはいけません。
 *	- 割込み許可状態で、当関数を呼び出してはいけません。
 *	  割込み許可状態で当関数を呼び出すと、意図しないネストが発生するおそれがあるからです。
 *	- 当関数は、ライブラリ内部で使用します。
 *	  アプリケーションから利用されることは、想定していません。
 */
void save_FRAM4(int flg/*1=退避,0=復元*/);

/*****************************************************************************
 *	標準Ｃライブラリの補助							//{{2015/01/07削除:各関数の宣言をclippce.h⇒標準ヘッダファイルへ，実装をclippce.c⇒cliplibc.cへ移動しました。今後は'標準Ｃライブラリの補助'をclippce.hやclippce.cで定義しないようにしてください。}}
 *****************************************************************************/

//{{2015/01/07削除:strdup(),strcasecmp(),strncasecmp()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。strcasecmp(),strncasecmp()は本当はstrings.hで宣言すべきなのですが、P/ECEにはstrings.hが無いのでinclude/string.hで宣言することにしました。
///* 以下の関数はANSI規格ではなく、BSDまたはSYSV互換の関数のようです。
// * P/ECEのCライブラリには含まれていませんが、便利なので実装しておきます。 */
//char* strdup(const char* string);
//int strcasecmp(const char* s1, const char* s2);
//int strncasecmp(const char* s1, const char* s2, size_t n);
//}}2015/01/07削除:strdup(),strcasecmp(),strncasecmp()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。strcasecmp(),strncasecmp()は本当はstrings.hで宣言すべきなのですが、P/ECEにはstrings.hが無いのでinclude/string.hで宣言することにしました。

//{{2015/01/07削除:strnlen(),strndup()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
///* strnlen()とstrndup()は、POSIX.1-2008準拠です。 */
//size_t strnlen(const char* string, size_t n);
//char* strndup(const char* string, size_t n);
//}}2015/01/07削除:strnlen(),strndup()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。

//{{2015/01/07削除:ismbblead(),ismbbtrail(),iscsym(),iscsymf(),isblank()の宣言をclippce.h⇒include/ctype.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。ismbblead(),ismbbtrail()は本当はmbctype.hで宣言すべきなのですが、P/ECEにはmbctype.hが無いのでinclude/ctype.hで宣言することにしました。
///* シフトJIS二バイト文字の、第一バイトまたは第二バイト文字か調べます。
// * ANSI規格ではなく、Visual C++の_ismbblead()/_ismbbtrail()の移植です。
// * P/ECEの標準文字セットも、MS-DOS/Windowsと同じく、シフトJISです。 */
//int ismbblead(int c);
//int ismbbtrail(int c);
///* iscsym(c) は、cが英字、アンダースコア、数字のいずれかであると、0以外の値を返します。
// * iscsymf(c)は、cが英字、アンダースコア      のいずれかであると、0以外の値を返します。
// * ANSI規格ではなく、Visual C++の_iscsym()/_iscsymf()の移植です。 */
//int iscsym(int c);
//int iscsymf(int c);
///* 空白文字(スペースかタブ)であるかを調べます。
// * isblank()は、POSIX.1-2001とC99 7.4.1.3に準拠しています。 */
//int isblank(int c);
//}}2015/01/07削除:ismbblead(),ismbbtrail(),iscsym(),iscsymf(),isblank()の宣言をclippce.h⇒include/ctype.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。ismbblead(),ismbbtrail()は本当はmbctype.hで宣言すべきなのですが、P/ECEにはmbctype.hが無いのでinclude/ctype.hで宣言することにしました。

//{{2014/10/02追加:snprintf(),vsnprintf()の宣言をclippce.h⇒include/stdio.hへ移しました。
///* C99で正式に追加された、安全な書式付き文字列出力です。
// * P/ECEのCライブラリには含まれていないので、追加しました。
// * VC++6.0には_snprintf(),vsnprintf()が含まれていますが、C99とは少し挙動が違っています。
// * 今回の実装は、C99仕様に従いました。(clipprnt.cのコメントを参照してください) */
//int snprintf(char* out, int cnt, const char* fmt, ...);
//int vsnprintf(char* out, int cnt, const char* fmt, va_list ap);
//}}2014/10/02追加:snprintf(),vsnprintf()の宣言をclippce.h⇒include/stdio.hへ移しました。

//{{2014/01/13削除:lfind()とlsearch()の宣言を、clippce.h⇒include/search.hへ分離しました。
///* POSIX標準のリニアサーチ関数です。
// * やや新しい標準のようで、P/ECE開発環境のEPSONライブラリには含まれていません。
// * バイナリサーチ関数だけは、P/ECE開発環境のEPSONライブラリにも含まれています。 */
//void* lfind(const void* key, const void* base, size_t* num, size_t width, int (*compare)(const void* elem1, const void* elem2));
//void* lsearch(const void* key, void* base, size_t* num, size_t width, int (*compare)(const void* elem1, const void* elem2));
////void* bsearch(const void* key, const void* base, size_t num, size_t width, int (*compare)(const void* elem1, const void* elem2));
//}}2014/01/13削除:lfind()とlsearch()の宣言を、clippce.h⇒include/search.hへ分離しました。

//{{2015/01/07削除:strupr(),strlwr()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
///* strupr()とstrlwr()は、標準関数かどうかよくわからず、VC++特有なのかも知れません。
// * Web上の資料から推測すると、Unix環境のライブラリには含まれていない(?)ようです。
// * P/ECE開発環境のEPSONライブラリにも、strupr()とstrlwr()は、含まれていません。
// * 便利なので、定義しておくことにしました。 */
//char* strupr(char* string);
//char* strlwr(char* string);
//}}2015/01/07削除:strupr(),strlwr()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。

//{{2015/01/07削除:splitpath(),makepath()の宣言をclippce.h⇒include/stdlib.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。
///* Windowsの、パス名構成要素分解/合成関数です。
// * P/ECEでも、ファイル名と拡張子の分解/合成は便利なので、定義しておくことにしました。
// * - MAX_PATH,MAX_DRIVE,MAX_DIR,MAX_FNAME,MAX_EXTは、Windowsと同じ値としました。
// *   path[MAX_PATH],drive[MAX_DRIVE],dir[MAX_DIR],fname[MAX_FNAME],ext[MAX_EXT]を全てスタック上に確保すると、
// *   合計1KB強必要なので、スタックオーバーフローに注意してください。
// *   P/ECEでは、drive[MAX_DRIVE]とdir[MAX_DIR]は通常必要ないので、これら2つを確保しなければ少し節約できます。 */
//#define MAX_PATH  260
//#define MAX_DRIVE 3
//#define MAX_DIR   256
//#define MAX_FNAME 256
//#define MAX_EXT   256
//void splitpath(const char* path, char drive[/*MAX_DRIVE*/], char dir[/*MAX_DIR*/], char fname[/*MAX_FNAME*/], char ext[/*MAX_EXT*/]);
//void makepath(char path[/*MAX_PATH*/], const char* drive, const char* dir, const char* fname, const char* ext);
//}}2015/01/07削除:splitpath(),makepath()の宣言をclippce.h⇒include/stdlib.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。

//{{2015/01/07削除:ffs()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。ffs()は本当はstrings.hで宣言すべきなのですが、P/ECEにはstrings.hが無いのでinclude/string.hで宣言することにしました。
///* ワードの中で最初にセットされている最下位ビットの位置を返します。(Find first set)
// * 本関数は、ffs(): 4.3BSD, POSIX.1-2001. 準拠です。 */
//int ffs(int i);
//}}2015/01/07削除:ffs()の宣言をclippce.h⇒include/string.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。ffs()は本当はstrings.hで宣言すべきなのですが、P/ECEにはstrings.hが無いのでinclude/string.hで宣言することにしました。

//{{2015/01/07削除:fileno(),isatty()の宣言を、clippce.h⇒include/stdio.hへ移動しました。実装はclipio.cにあります。isatty()は本当はio.hかunistd.hで宣言すべきなのですが、P/ECEにはio.hもunistd.hも無いのでinclude/stdio.hで宣言することにしました。
//#define STDIN_FILENO  0 /* 標準入力のファイル記述子 */
//#define STDOUT_FILENO 1 /* 標準出力のファイル記述子 */
//#define STDERR_FILENO 2 /* 標準エラー出力のファイル記述子 */
///* 指定されたストリームの、ファイル記述子を返します。
// * 指定されたストリームが、有効なストリームでなければ、-1 を返します。 */
//int fileno(FILE* stream); /* -> clipio.c */
///* 指定されたファイル記述子が、端末を参照するファイル記述子ならば、1 を返します。
// * そうでなければ、0 を返します。 */
//int isatty(int fd); /* -> clipio.c */
//}}2015/01/07削除:fileno(),isatty()の宣言を、clippce.h⇒include/stdio.hへ移動しました。実装はclipio.cにあります。isatty()は本当はio.hかunistd.hで宣言すべきなのですが、P/ECEにはio.hもunistd.hも無いのでinclude/stdio.hで宣言することにしました。

//{{2015/01/07削除:malloc_usable_size()の宣言をclippce.h⇒include/stdlib.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。malloc_usable_size()は本当はmalloc.hで宣言すべきなのですが、P/ECEにはmalloc.hが無いのでinclude/stdlib.hで宣言することにしました。
////{{2014/09/29追加:malloc_usable_size()を追加しました。
////ヒープに割り当てられたメモリブロックのサイズを取得します。
//// - この関数は、GNU拡張です。便利なので、P/ECEにも追加することにしました。
//// - Visual C++にも、似た関数として_msize()が有りますが、少し仕様が異なっています。
////   malloc_usable_size()にNULLポインタを渡すと、正常に(0)が返されます。
////   _msize()にNULLポインタを渡すと、不正終了します。
////   malloc_usable_size()の方が安全なので、malloc_usable_size()の仕様に従いました。
////□「Linux Programmer's Manual」より引用
////│MALLOC_USABLE_SIZE(3)      Linux Programmer's Manual     MALLOC_USABLE_SIZE(3)
////│NAME
////│       malloc_usable_size - obtain size of block of memory allocated from heap
////│SYNOPSIS
////│       #include <malloc.h> 
////│       size_t malloc_usable_size (void *ptr);
////│DESCRIPTION
////│       The malloc_usable_size() function returns the number of usable bytes in
////│       the block pointed to by ptr, a pointer to a block of  memory  allocated
////│       by malloc(3) or a related function.
////│RETURN VALUE
////│       malloc_usable_size() returns the number of usable bytes in the block of
////│       allocated memory pointed to by ptr.  If ptr is NULL, 0 is returned.
////│CONFORMING TO
////│       This function is a GNU extension.
////│NOTES
////│       The value returned by malloc_usable_size()  may  be  greater  than  the
////│       requested  size of the allocation because of alignment and minimum size
////│       constraints.  Although the excess  bytes  can  be  overwritten  by  the
////│       application without ill effects, this is not good programming practice:
////│       the number of excess bytes in an allocation depends on  the  underlying
////│       implementation.
////│       The main use of this function is for debugging and introspection.
////│SEE ALSO
////│       malloc(3)
////│COLOPHON
////│       This  page  is  part of release 3.53 of the Linux man-pages project.  A
////│       description of the project, and information about reporting  bugs,  can
////│       be found at http://www.kernel.org/doc/man-pages/.
////│GNU                               2012-03-29             MALLOC_USABLE_SIZE(3)
//size_t malloc_usable_size(void* ptr);
////}}2014/09/29追加:malloc_usable_size()を追加しました。
//}}2015/01/07削除:malloc_usable_size()の宣言をclippce.h⇒include/stdlib.hへ，実装をclippce.c⇒cliplibc.cへ移動しました。malloc_usable_size()は本当はmalloc.hで宣言すべきなのですが、P/ECEにはmalloc.hが無いのでinclude/stdlib.hで宣言することにしました。

/*****************************************************************************
 *	標準エラー出力,標準入力 -> clipio.c
 *****************************************************************************/

/* 標準エラー出力を開きます。
 * [in]
 *	timeout		標準エラー出力モニタの接続待ちを行う時間[秒]。
 *			負値を指定すると、接続されるか明示的にキャンセルするまで待ちます。
 * [note]
 *	// * pceAppInit()から一度だけ呼びます。
 *	//   アプリケーションプログラムからは呼ばないでください。
 *	//↓2003/11/22 変更
 *	* 標準エラー出力を使うアプリケーションは、最初にこの関数を呼んでください。
 *	  stderr_open()を呼ばなかった場合、全ての fprintf(stderr, ...) 出力は捨てられます。
 */
void stderr_open(int timeout);

/* 標準エラー出力を閉じます。
 * [note]
 *	* pceAppExit()から一度だけ呼びます。
 *	  アプリケーションプログラムからは呼ばないでください。
 */
void stderr_close();

/* 標準エラー出力にデータを出力します。
 * [in]
 *	ptr		出力するデータの先頭アドレス。
 *	len		出力するデータのバイト数。
 * [note]
 *	* アプリケーションプログラムは直接この関数を使わずに、
 *	  fwrite(..., stderr) や fprintf(stderr, ...) を使ってください。
 */
void stderr_write(const void* ptr, int len);

/* 標準入力からデータを入力します。
 * [in]
 *	buf		データを格納するバッファの先頭アドレス。
 *	bufsize		バッファのバイト数。
 * [note]
 *	* アプリケーションプログラムは直接この関数を使わずに、
 *	  fread(..., stdin) や fgets(..., stdin) を使ってください。
 */
int stdin_read(void* _buf, int bufsize);

/*****************************************************************************
 *	ユーティリティ：タイマ
 *****************************************************************************/

//{{2015/11/24削除:unistd.h,cliplibc.cにてPOSIX仕様のusleep()を実装した事に伴い、既存のclippce.h,clippce.cの独自仕様のusleep()を削除しました。
///* マイクロ秒単位の時間待ちを行います。
// * [in]
// *	usec		待ち時間[マイクロ秒]
// * [note]
// *	* 超高精度カウント（pceTimerAdjustPrecisionCount()）の値は、
// *	  16bitタイマのカウンタデータとClockTicks値から生成されています。
// *	* どちらの値も割り込み禁止中もカウントアップを継続するので、
// *	  割り込み禁止中でもusleep()を使って時間待ちを行うことができます。
// */
//void usleep(unsigned long usec);
//}}2015/11/24削除:unistd.h,cliplibc.cにてPOSIX仕様のusleep()を実装した事に伴い、既存のclippce.h,clippce.cの独自仕様のusleep()を削除しました。

/* 何も接続されていない、アクセス速度の遅いアドレス空間に対して、ダミーの積和演算を行い、時間を消費します。
 * /usr/PIECE/sysdev/pcekn/critical.cのpdwait()と同等です。
 * [in]
 *	n		待ち時間。
 *			100万あたり、約1.3秒の待ち時間となります。具体的には、以下を参照してください。
 * [note]
 *	- (引数n=1000000)を指定したの時の、消費時間の概算:
 *	  理論値は(1/24000000)*(2+7*4)*1000000=1.25[秒] ⇒ 実測値は約1.335[秒]になりました。NMI処理などの影響と思います。
 *	           ~~~~~~~~~~   ~ ~~~  ~~~~~~~
 *	  外部バスは、通常モードでもTURBOモードでも24MHzである。
 *	  mac命令は(2×N+4)サイクル。'+4'はほぼ無視できる。
 *	  2×Nの毎回に対し、<rs+1>と<rs+2>の読み出しが発生する。
 *	  エリア11～12は、/usr/PIECE/sysdev/pcekn/hard.cのInitHard()にて、7ウェイト,3.5サイクル,8ビットに設定されている。
 *	  mac命令のアクセスパターンでは、出力ディセーブル遅延時間(3.5サイクル)は発生しない。
 *	  デバイスサイズが8ビットに設定されているため、ハーフワードの読み出し毎に2回のアクセスとなる。
 *	  従って、<rs+1>と<rs+2>の読み出しに対して7×4ウェイトが発生する。
 *	- 引数nに、約800万以上の値を指定しないでください。
 *	  エリア11～12は合計16MBであり、n=1あたりハーフワード進むので、約800万でエリア12を超えます。
 *	  エリア13以降は、カーネルによってアクセス速度が設定されていないため、結果が予測できません。
 *	  (n=800万⇒約10秒)相当であり、pdwait()を用いて10秒以上の時間待ちを行うことは無いと思いますが、注意してください。
 */
void pdwait(int n);

/*****************************************************************************
 *	ユーティリティ：描画
 *****************************************************************************/

//{{2003/05/01:BIOS1.20で修正されました。もう不要です。
///* LCDCを再初期化します。
// * [note]
// *	* 現在のP/ECEカーネル(BIOS 1.18)では、アプリケーションを起動するたびに、
// *	  画面の濃度がバラついてしまうことがあります。
// *	* 電源投入後、一度でもリセットボタンを押すと、濃度がバラつきはじめます。
// *	* 濃度のバラつきを防ぐには、RESETB端子を使ってLCDCを再初期化します。
// *	  （P/ECEカーネルは、Resetコマンドを使っていますが、それではダメです）
// *	* この関数を、アプリケーション起動時に呼び出してください。
// *	  RESETB端子を使ってLCDCを再初期化し、確実に濃度のバラつきを修正します。
// *	  →組み込みのpceAppInit()から呼び出すようにしました。
// *	    もう、アプリケーションプログラムから直接呼び出す必要はありません。
// *	* RESETBによるリセットは、画面OFF・VRAMクリアを伴うので、ご注意ください。
// */
//void lcd_init();
//}}2003/05/01:BIOS1.20で修正されました。もう不要です。

//{{2006/12/05:render_object()が定着し、draw_object()は使わなくなったので、削除しました。
///* 現在の仮想画面に、オブジェクトを描きます。
// * [in]
// *	src		転送元ビットマップ。
// *	dx,dy		転送先の左上座標。
// *	sx,sy		転送元の左上座標。
// *	w,h		転送サイズ。
// *	param		パラメータ。
// * [note]
// *	* pceLCDSetObject()/pceLCDDrawObject()のペアを呼び出すだけです。
// *	  引数の意味は、pceLCDSetObject()と同じです。
// */
//void draw_object(PIECE_BMP* src, int dx, int dy, int sx, int sy, int w, int h, int param);
//}}2006/12/05:render_object()が定着し、draw_object()は使わなくなったので、削除しました。

/* レンダラーを指定して、オブジェクトを描きます。
 * [in]
 *	render		レンダラーへのポインタ。
 *	dx,dy		転送先の左上座標。
 *	sx,sy		転送元の左上座標。
 *	w,h		転送サイズ。
 *	param		パラメータ。
 * [note]
 *	* renderは予めrender_init()によって初期化されていなければいけません。
 *	* 描画領域は、renderに設定されたビューポート矩形内にクリッピングされます。
 *	* renderの現在のコンテキストにテクスチャが設定されていなければいけません。
 *	  テクスチャを設定せずにこの関数を呼ぶと、エラーを表示して停止します。
 *	* 通常の横画面ゲームでは、アプリケーション内にサーフェイスは一つしかなく、
 *	  pceLCDSetBuffer()とRENDERは同じサーフェイスを指しているので、この関数を使う必要はありません。
 *	  draw_object()で充分です。
 *	  しかし縦画面ゲームの場合は、メインルーチンが直接縦横変換を意識しながら描画するよりも、
 *	  いったん縦サーフェイスに描画した後、横サーフェイスに変換して転送した方が開発が楽です。
 *	  pceLCDSetBuffer()は128x88の横サーフェイス、RENDERは88x128の縦サーフェイスを指すことになります。
 *	  このようなケースで、pceLCDSetBuffer()に指定したサーフェイス以外にオブジェクトを描画するために、
 *	  render_object()を用意しました。
 *	* この関数はrender_プレフィクスを持っていますが、cliprend.h/cには含めませんでした。
 *	  その理由は、この関数がpceLCDDrawObject()に依存していて、移植性がないからです。
 *	  既にpceLCDDrawObject()の大部分は自前の高速版に置き換えられているのですが、
 *	  まだ1bit描画や特殊なパラメータの処理がオリジナルのpceLCDDrawObject()に依存しています。
 *	  従って、この関数はまだcliprend.h/cには含められないと判断しました。
 */
void render_object(RENDER* render, int dx, int dy, int sx, int sy, int w, int h, int param);

/* * Tue Dec 05 14:59:42 JST 2006 Naoyuki Sawa
 * - オブジェクトを単一色で描くための、DRW_MASKフラグを定義しました。
 *   キャラクタのドロップシャドウや、ダメージ時のフラッシュ等に利用できます。
 *
 *	-----A98 76543210
 *	     ||| ||++++++- DRW_NOMAL等 (1,2,4bit共通のP/ECE BIOS標準パラメータ)
 *	     ||| |||||+++- DRW_CLR(C1) (1bit用のP/ECE BIOS標準パラメータ)
 *	     ||| ||+++---- DRW_CLR(C2) (1bit用のP/ECE BIOS標準パラメータ)
 *	     ||| |+------- DRW_REVY    (1,2,4bit共通のP/ECE BIOS標準パラメータ)
 *	     ||| +-------- DRW_REVX    (1,2,4bit共通のP/ECE BIOS標準パラメータ)
 *	     +++---------- DRW_MASK(C) (1,2,4bit共通のCLiP拡張パラメータ) ← これを定義しました
 *
 * - render_object()をDRW_MASKに対応しました。
 *   sprite_draw()もrender_object()を利用しているので、sprite_draw()にもDRW_MASK指定可能です。
 *
 * - スプライト定義そのものに対して、DRW_MASKを指定することはできません。
 *   SPRITE構造体のparamフィールドは8bitですが、DRW_MASKは9～11bit目に定義されているからです。
 *   スプライト描画に対するDRW_MASK指定は、sprite_draw()へのパラメータとしてのみ指定可能です。
 *
 * - たとえば、通常、次のように描画を行う2bitマスク付きテクスチャがある場合、
 *
 *	render.context->texture = texture_table[TEX_PAT];
 *	render_object(&render, dx, dy, sx, sy, w, h, DRW_NOMAL);
 *
 *   以下のようにしてドロップシャドウやフラッシュを描くことができます。
 *
 *	render.context->texture = texture_table[TEX_PAT];
 *	render_object(&render, dx, dy, sx, sy, w, h, DRW_MASK(2)); // 暗灰(ドロップシャドウ)
 *
 *	render.context->texture = texture_table[TEX_PAT];
 *	render_object(&render, dx, dy, sx, sy, w, h, DRW_MASK(0)); // 白(フラッシュ)
 *
 *   上下反転、左右反転、上下左右反転と併用することもできます。
 *
 *	render.context->texture = texture_table[TEX_PAT];
 *	render_object(&render, dx, dy, sx, sy, w, h, DRW_REVX | DRW_REVY | DRW_MASK(0));
 *
 *   スプライト描画にも指定できます。
 *
 *	sprite_draw(x, y, SPR_FOO, DRW_MASK(0));
 *
 * - 16階調4bitデータの描画時もDRW_MASKを指定することはできますが、単一色の指定は0～3に限られます。
 *   4～15の単一色を指定することはできません。
 *   つまり、この機能を使って、16階調モードで真っ黒のドロップシャドウを描くことはできません。
 *   この制限の理由は、現在の実装では、P/ECE標準の1bit描画機能を利用して単一色描画を行っているためです。
 *   P/ECE標準の1bit描画機能は、0～3(+透明)の色指定しか認識しないからです。
 */
#define DRW_MASK(c)	(((c)|4)<<8)

/****************************************************************************
 *	ユーティリティ：フォント
 ****************************************************************************/

/* 各フォントタイプごとの幅と高さ[ピクセル]です。
 * clippce.cとclipfram.cから参照するので、グローバルにしました。
 */
//{{2015/05/26変更:4x5ピクセルフォントを追加しました。
//extern const unsigned char render_font_size[3][2]/* = { {5,10}, {8,16}, {4,6} }*/;
//↓2015/05/26変更:4x5ピクセルフォントを追加しました。
//extern const unsigned char render_font_size[4][2]/* = { {5,10}, {8,16}, {4,6}, {4,5} }*/;
//↓2017/02/04変更:4x4ピクセルフォントを追加しました。
extern const unsigned char render_font_size[5][2]/* = { {5,10}, {8,16}, {4,6}, {4,5}, {4,4} }*/;
//}}2017/02/04変更:4x4ピクセルフォントを追加しました。

/* 縁取りフォント描画のパラメータテーブルです。
 * clippce.c、clipfnt8.c、clipfntx.cから参照するので、グローバルにしました。
 */
typedef struct _RENDER_FONT_FRAMED_PARAM {
	unsigned char x : 2; /* 水平オフセット */
	unsigned char y : 2; /* 垂直オフセット */
	unsigned char c : 4; /* カラーシフト数 */
} RENDER_FONT_FRAMED_PARAM;
extern const RENDER_FONT_FRAMED_PARAM render_font_framed_param[9];

/* フォントを描きます。
 * [in]
 *	render		レンダラーへのポインタ。
 *	x,y		描画位置の左上座標。
 *	code		文字コード。(シフトJIS)
 *			半角文字の場合は、下位バイトに文字コードを入れて、上位バイトは0としてください。
 *			全角文字の場合は、1バイト目を上位バイト、2バイト目を下位バイトに入れてください。
 *	type		フォントの種類。(bit31～7は無視します)
 *			0x00: 5x10(半角)または10x10(全角)
 *			0x01: 8x16(半角)
 *			0x02: 4x 6(半角)
 *	color		フォントの色。
 *			0: 白
 *			1: 明灰
 *			2: 暗灰
 *			3: 黒
 * [out]
 *	戻り値		下位8ビットに描画したフォントの幅  [ピクセル]、
 *			上位8ビットに描画したフォントの高さ[ピクセル]を返します。
 * [note]
 *	* 描画領域は、renderに設定されたビューポート矩形内にクリッピングされます。
 *	* render_string(),render_printf()とは戻り値のビット数が異なるので、ご注意ください。
 *	* この関数は内部でpceFontSetType()を呼び出しています。
 *	  この関数を呼び出すと、フォントタイプの設定が変更されるので、ご注意ください。
 *	* この関数はrender_プレフィクスを持っていますが、cliprend.h/cには含めませんでした。
 *	  pceFonSetType()/pceFontGetAdrs()およびP/ECEのフォントデータに依存しているからです。
 */
unsigned short render_font(RENDER* render, int x, int y, unsigned short code, int type, int color);

/* 文字列を描きます。
 *	render		レンダラーへのポインタ。
 *	x,y		描画位置の左上座標。
 *	str		文字列へのポインタ。
 *	type		フォントの種類。
 *			0x00: 5x10(半角)または10x10(全角) 改行あり
 *			0x01: 8x16(半角)                  改行あり
 *			0x02: 4x 6(半角)                  改行あり
 *			0x80: 5x10(半角)または10x10(全角) 改行なし
 *			0x81: 8x16(半角)                  改行なし
 *			0x82: 4x 6(半角)                  改行なし
 *	color		フォントの色。
 *			0: 白
 *			1: 明灰
 *			2: 暗灰
 *			3: 黒
 * [out]
 *	戻り値		下位16ビットに描画したフォントの幅  [ピクセル]、
 *			上位16ビットに描画したフォントの高さ[ピクセル]を返します。
 * [note]
 *	* 描画領域は、renderに設定されたビューポート矩形内にクリッピングされます。
 *	* render_font()とは戻り値のビット数が異なるので、ご注意ください。
 *	* この関数は内部でpceFontSetType()を呼び出しています。(render_font()による)
 *	  この関数を呼び出すと、フォントタイプの設定が変更されるので、ご注意ください。
 *	* この関数はrender_プレフィクスを持っていますが、cliprend.h/cには含めませんでした。
 *	  pceFonSetType()/pceFontGetAdrs()およびP/ECEのフォントデータに依存しているからです。
 */
unsigned int render_string(RENDER* render, int x, int y, const char* str, int type, int color);

/* 書式付き文字列を描きます。
 *	render		レンダラーへのポインタ。
 *	x,y		描画位置の左上座標。
 *	type		フォントの種類。
 *			0x00: 5x10(半角)または10x10(全角) 改行あり
 *			0x01: 8x16(半角)                  改行あり
 *			0x02: 4x 6(半角)                  改行あり
 *			0x80: 5x10(半角)または10x10(全角) 改行なし
 *			0x81: 8x16(半角)                  改行なし
 *			0x82: 4x 6(半角)                  改行なし
 *	color		フォントの色。
 *			0: 白
 *			1: 明灰
 *			2: 暗灰
 *			3: 黒
 *	fmt		書式指定文字列へのポインタ。
 *	...		パラメータ。
 * [out]
 *	戻り値		下位16ビットに描画したフォントの幅  [ピクセル]、
 *			上位16ビットに描画したフォントの高さ[ピクセル]を返します。
 * [note]
 *	* 描画領域は、renderに設定されたビューポート矩形内にクリッピングされます。
 *	* render_font()とは戻り値のビット数が異なるので、ご注意ください。
 *	* この関数は、書式付き文字列を展開するために、_def_vbuff[]を利用しています。
 *	  _def_vbuff[]を仮想画面として設定していた場合、画面左上にゴミが出ます。
 *	* この関数は内部でpceFontSetType()を呼び出しています。(render_font()による)
 *	  この関数を呼び出すと、フォントタイプの設定が変更されるので、ご注意ください。
 *	* この関数はrender_プレフィクスを持っていますが、cliprend.h/cには含めませんでした。
 *	  pceFonSetType()/pceFontGetAdrs()およびP/ECEのフォントデータに依存しているからです。
 */
unsigned int render_printf(RENDER* render, int x, int y, int type, int color, const char* fmt, ...);

/* 縁取りフォント/文字列/書式付き文字列を描きます。
 * [in]
 *	color		0…0ccccbbbbaaaa  ※各4bitです！8bitじゃないよ！
 *			    ||||||||++++- 中抜き
 *			    |||||+++----- 縁(直線部分)
 *			    +++++-------- 縁(角の部分)
 *			白背景に、白抜き・黒縁取りで描くなら、0x130がいいです。
 *			黒背景に、黒抜き・白縁取りで描くなら、0x203がいいです。
 *	color以外の引数については、render_font()/render_string()/render_printf()と同じです。
 *	render_font()/render_string()/render_printf()の説明を参照してください。
 * [out]
 *	戻り値		render_font()/render_string()/render_printf()と同じく、描画サイズを返します。
 *			上記関数の戻り値に較べて、縁取りの分、縦横2ピクセルづつ大きな値を返します。
 *			ただし、描画なしの場合は、上記関数と同じく、0を返します。
 */
unsigned short render_font_framed(RENDER* render, int x, int y, unsigned short code, int type, int color);
unsigned int render_string_framed(RENDER* render, int x, int y, const char* str, int type, int color);
unsigned int render_printf_framed(RENDER* render, int x, int y, int type, int color, const char* fmt, ...);

// * Fri Jul 15 21:06:38 JST 2016 Naoyuki Sawa
// - ヌルレンダラーの定数データ「null_render」を定義しました。
//   実際の描画を行わずに、描画関数の戻り値だけを取得したい場合に、空の描画対象として指定するために、汎用的に利用出来ます。
//   現在の所、ヌルレンダラーを指定する意味が有ると思う関数は、文字列描画関数だけです。
//   文字列描画関数は、戻り値として描画した文字列のサイズを返すので、実際に描画せずに、文字列のサイズだけを取得するために、ヌルレンダラーを指定すると便利です。
//   具体的には、下記の関数に対して、ヌルレンダラーを指定する意味が有ると思います。
//   ・render_font(),render_string(),render_printf(),render_font_framed(),render_string_framed(),render_printf_framed()
//   ・render_font7(),render_string7(),render_printf7(),render_font7_framed(),render_string7_framed(),render_printf7_framed()
//   ・render_font8(),render_string8(),render_printf8(),render_font8_framed(),render_string8_framed(),render_printf8_framed()	下記のrender_object()に関する説明を参照せよ。
//   ・render_fontx(),render_stringx(),render_printfx(),render_fontx_framed(),render_stringx_framed(),render_printfx_framed()	下記のrender_object()に関する説明を参照せよ。
// - RENDER構造体のフィールドを変更する関数には、null_renderを引き渡さないように注意して下さい。
//   例えば、render_save(),render_restore()等には、null_renderを引き渡さないように注意して下さい。
//   (もとより、render_save(),render_restore()は戻り値が無いので、ヌルレンダラーを指定する事自体が無意味であり、これらの関数にヌルレンダラーを引き渡す事は無いと思いまずが。)
//   ただし特例として、render_object()に対してヌルレンダラーを指定する事は、(厳密には良くないのですが)、動作上は問題ありません。
//   render_object()は、一時的にnull_render.context->textureを書き換えますが、元に戻すからです。
//   例えば、render_printf8()等にnull_renderを指定した場合、間接的にrender_object()が呼び出され、render_object()に対してnull_renderが引き渡されますが、正常に動作します。
// - ヌルレンダラーの使用例は、以下の通りです。
//   <例>
//   │//文字列の中心が目標位置になるように、文字列を描画するサンプル
//   │void test() {
//   │  int xy, x, y;
//   │  //目標位置を示すためのクロスハッチを描画する。
//   │  x = DISP_X / 2;
//   │  y = DISP_Y / 2;
//   │  render_line(&render, 0, y, DISP_X, y, 1);
//   │  render_line(&render, x, 0, x, DISP_Y, 1);
//   │  //文字列の描画サイズを取得するために、ヌルレンダラーへのダミー描画を行う。
//   │  xy = render_printf(&null_render, 0, 0, 0, 0, "日本語\n数値 %'d\nAB12", (now * now));
//   │  //                               ~~~~     ~ null_renderへ描画する時の、x,y,colorは何でも構いません。
//   │  //文字列の描画サイズから、文字列の中心を目標位置として描画するための、描画原点座標を求める。
//   │  //ここの計算式を変えれば、文字列の右下を目標位置としたり、文字列の左下を目標位置とする事も可能です。
//   │  x -= LOHALF(xy) / 2;
//   │  y -= HIHALF(xy) / 2;
//   │  //文字列を描画する。
//   │  render_printf(&render, x, y, 0, 3, "日本語\n数値 %'d\nAB12", (now * now));
//   │}
//   或いは、ヌルレンダラーを使わなくても、クリッピング領域を狭めたり、サーフェイス外を指定する事で、実際に描画せずに、文字列のサイズだけを取得する事は可能ではあるのですが、
//   ヌルレンダラーを指定する方が、意図が明確に判り、見た目に判り易いソースコードになると思います。
// - ヌルレンダラーの定義においては、極力、メモリを節約するように工夫しました。
//   もし工夫せずに、RENDER構造体とSURFACE構造体を定義すると、(24+52*8)+12=452バイトも消費してしまいます。
//   今回は、以下の工夫を行って、28バイトしか消費しないようにしました。
//   工夫1. RENDER.context_stack[]は1要素分しか使用しないので、定数データに含めませんでした。
//   工夫2. 1要素分のコンテキストは、RENDER.context_stack[0]を指すのではなく、下記の工夫3で重複させた領域を指すようにしました。
//   工夫3. RENDER構造体と、SURFACE構造体の、値が共通な部分を重複させて定義しました。
//   工夫4. 1要素分のコンテキストスタックの行列部分の値は不定値で構わないので、別のコード領域に重複させて、textureフィールドだけが確実にNULLの値を指すようにしました。
//   詳細は、clippce.c内のnull_renderを定義しているアセンブラブロックを参照して下さい。
extern RENDER null_render;

/*****************************************************************************
 *	ユーティリティ：サウンド
 *****************************************************************************/

#define SOUND_MAXCH 4 /* サウンドチャネル数 (/usr/PIECE/sysdev/pcekn/snd.c MAXCH 相当) */

/* サウンドを再生します。
 * [in]
 *	ch		チャネル番号(0～3)
 *	data		サウンドデータの先頭アドレス
 *	{{2006/07/18追加
 *	loop		ループ回数
 *			1を指定すると、一回だけ再生して終了します。(通常の用法)
 *			0を指定すると、再生しません。(「sound_stop(ch)」と等価)
 *			2以上を指定すると、その回数だけループして、終了します。
 *			0未満を指定すると、無限ループします。
 *	}}2006/07/18追加
 * [note]
 *	* pceWaveOut()に渡すPCEWAVEINFOとしては、data内のPCEWAVEINFOは直接使っていません。
 *	  いったんsound_play()内のPCEWAVEINFOにコピーしてからpceWaveOut()に渡しています。
 *	  従って、同じサウンドデータを複数のチャネルで同時に再生しても大丈夫です。
 *	* サウンドデータはpPCMConv.exeの出力形式互換としてください。即ち、
 *	  +0～:シグネチャ('PPCM')
 *	       データ本体(PCEWAVEINFOとサンプルデータ)のサイズ
 *	  +8～:PCEWAVEINFO(pData以外のフィールドは初期化済みであること)
 *	       サンプルデータ
 *	  となっている必要があります。僕のdppcmcnv.exeの出力もこの形式です。
 *	* いきなりPCEWAVEINFOから始まるようなRAW形式データを指定すると、
 *	  実行時にsound_play()内のシグネチャチェックでアサートします。
 */
//void sound_play(int ch, const unsigned char* data);
//↓2006/07/18変更
//void sound_play(int ch, const unsigned char* data, int loop);
//↓2006/12/20変更
void sound_play(int ch, const void* data, int loop);

/* サウンドを停止します。
 * [in]
 *	ch		チャネル番号(0～3)
 */
void sound_stop(int ch);

/* 指定されたサウンドチャネルが、再生中か停止中かを調べます。
 * [in]
 *	ch		チャネル番号(0～3)
 * [out]
 *	戻り値		再生中ならば0以外の値を返します。
 *			停止中ならば0を返します。
 * [note]
 *	* adpcm_stat()との対称のためだけに追加しました。(形式的な理由です)
 *	  adpcm_stat()は安全ですが、sound_stat()は以下のような危険性があります。
 *	- sound_stat()は内部で、pceWaveCheckBuffs()を呼び出しています。
 *	  もしも、stream_play()などによって環状バッファを再生中であるチャネルに対して
 *	  pceWaveCheckBuffs()を呼び出すと、いつまでも残りバッファ数をカウントし続け、
 *	  ハングアップしてしまいます。
 *	- stream_play()を使う可能性のあるBGMチャネルなどに対しては、sound_stat()を
 *	  呼び出さないよう注意してください。
 *	  環状バッファを構成しない、効果音チャネルに対してだけ、利用してください。
 *	- なお、adpcm_stat()は、sound_stat()のようなハングアップの危険性はありません。
 *	  ループ再生中のチャネルに対しても、利用することができます。
 */
int sound_stat(int ch);

//{{2013/07/15追加
/* 指定されたサウンドチャネルの、減衰量を設定します。
 * [in]
 *	ch		チャネル番号(0～3)
 *	att		減衰量。(0～64)
 * [note]
 *	* adpcm_att()との対称のためだけに追加しました。(形式的な理由です)
 *	* 減衰量は 減衰無し:0～64:消音 です。
 *	  数値範囲は、P/ECE APIのpceWaveSetMasterAtt()とpceWaveSetChAtt()に倣いました。
 *	- pceWaveSetMasterAtt()とpceWaveSetChAtt()のAPIリファレンスには、最大:0～127:最小 と書いてありますが、
 *	  実際の動作は、減衰無し:0～64:消音 であり、64以上は全て消音です。
 *	  ⇒ /usr/PIECE/sysdev/pcekn/snd.c volcalc() 参照
 *	  本関数も、pceWaveSetMasterAtt()とpceWaveSetChAtt()の実際の動作に倣い、0～64 で指定することしました。
 */
void sound_att(int ch, int att);
//}}2013/07/15追加

//{{2014/07/01追加
/* ppd形式のサウンドデータの、再生時間を取得します。
 * [in]
 *	data		サウンドデータの先頭アドレス
 * [out]
 *	戻り値		再生時間[ms]
 * [note]
 *	- PCEWAVEINFO.lenは、可変周波数であっても、16000[Hz]基準で格納されています。(\usr\PIECE\sysdev\pcekn\snd.c参照)
 *	  従って、計算式は「len*1000[ms]/16000[Hz]」⇒「len>>4」と、単純化できます。
 *	  関数にする程でもないので、マクロとして実装することにしました。
 */
#define ppd_playback_time(data) ((((PCEWAVEINFO*)(((char*)(data))+8))->len)>>4)
//}}2014/07/01追加

/****************************************************************************
 *	ユーティリティ：ストリーム再生
 ****************************************************************************/

/* ユーザーが用意する、ストリーム再生コールバック関数の型宣言です。
 * [in]
 *	wbuff		ここにサンプルデータを展開してください。
 *			サンプル形式は符号付き16bit(PW_TYPE_16BITPCM)に固定です。
 *			サンプル数はstream_play()のBLKSに指定したサンプル数です。
 *	param		stream_play()に指定したparam値がそのまま渡されます。
 * [out]
 *	戻り値		サンプルデータの展開に成功したら、 0を返してください。
 *			サンプルデータの展開に失敗したら、-1を返してください。
 *			失敗する状況とは、演奏終了やデータが壊れている場合などです。
 * [note]
 *	* コールバック関数が-1を返した場合は、ストリーム再生ルーチン側でバッファをクリアし、
 *	  無音状態にしますので、コールバック関数側でバッファをクリアする必要はありません。
 *	* コールバック関数がいったん1(失敗)を返しても、また次回にコールバックが行われます。
 *	  失敗からの回復が出来ない場合は、毎回-1を返すようにコールバックを作成してください。
 */
typedef int STREAMCALLBACK(short* wbuff, int param);

/* ストリーム再生を開始します。
 * [in]
 *	BLKS		コールバック一回当りの展開サンプル数。（バイト数ではありません！）
 *			pceWave*()の実装に由来する制限により、64の倍数でなければいけません。
 *	param		コールバックに渡される、任意のパラメータを指定することができます。
 *  //{{2014/12/25変更:stream_play()の第3引数をfram4⇒flagsに変更しました。
 *  //	fram4		0を指定すると、スタックを切り替えずにコールバックを呼び出します。
 *  //			1を指定すると、スタックをFRAM4領域に切り替えてからコールバックを呼び出します。
 *  //			詳しくは、clippce.c - STREAMINFO構造体のコメントを参照してください。
 *  ↓}}2014/12/25変更:stream_play()の第3引数をfram4⇒flagsに変更しました。
 *	flags		以下のフラグの組み合わせを指定してください。
 *			ほとんどの場合はどちらのフラグも指定せずに、0を指定するのが適切だと思います。
 *		STREAM_PLAY_STACK_SWITCH_FRAM4
 *			0を指定すると、スタックを切り替えずにコールバックを呼び出します。		┐2014/12/25以前のstream_play()の第3引数がfram4だった時の1指定に相当します。
 *			1を指定すると、スタックをFRAM4領域に切り替えてからコールバックを呼び出します。	├フラグの位置が変わっていないのでこれまでのアプリケーションは変更不要です。
 *			詳しくは、clippce.c - STREAMINFO構造体のコメントを参照してください。		┘今後は直値でなくSTREAM_PLAY_STACK_SWITCH_FRAM4シンボルを使用してください。
 *		STREAM_PLAY_CALLBACK_USES_HEAP
 *			ストリームコールバックが、ヒープAPIを使用することを宣言します。			┐
 *			このフラグが指定されていると、ミキシング割り込みレベルを1にします。		├詳細は、clippce.hの「割り込みレベル設定」の'Mon Dec 22 21:06:44 JST 2014'のコメントを参照してください。
 *			このフラグが指定されていなければ、ミキシング割り込みレベルを2にします。		┘
 *  //}}2014/12/25変更:stream_play()の第3引数をfram4⇒flagsに変更しました。
 * [note]
 *	* 既にストリーム再生中だったら、自動的にstream_stop()が呼ばれます。
 *	* 現在の実装では、ストリーム再生に利用するチャネルは、チャネル#0に固定です。
 *	* stream_play()の内部から、すぐさま初回のコールバックが行われます。
 *	  この関数を呼ぶ前に、コールバックがサンプルを展開できるよう、準備しておいてください。
 *	* stream_play()を呼ぶと、サウンド割り込みベクタがフックされます。
 *	  プログラム終了前に必ずstream_stop()を呼んで、ベクタを復元してください。
 */
//{{2014/12/25変更:stream_play()の第3引数をfram4⇒flagsに変更しました。
//void stream_play(int BLKS, STREAMCALLBACK* callback, int param, int fram4);
//↓2014/12/25変更:stream_play()の第3引数をfram4⇒flagsに変更しました。
#define STREAM_PLAY_STACK_SWITCH_FRAM4 (1<<0)
#define STREAM_PLAY_CALLBACK_USES_HEAP (1<<1)
void stream_play(int BLKS, STREAMCALLBACK* callback, int param, int flags);
//}}2014/12/25変更:stream_play()の第3引数をfram4⇒flagsに変更しました。

/* ストリーム再生を終了します。
 * [note]
 *	* ストリーム再生中でなければ、何もしません。
 *	* コールバック側のリソース開放には関知しませんので、忘れずリソース開放を行ってください。
 *	  全体の流れとしては、次のようになります。
 *		・サンプル展開用のリソース確保・コールバック準備
 *		・stream_play()
 *		・（コールバック×Ｎ）
 *		・stream_stop()
 *		・サンプル展開用のリソース開放
 */
void stream_stop();

/* ストリーム再生中か停止中かを調べます。
 * [out]
 *	戻り値		ストリーム再生中ならば1を返します。
 *			ストリーム停止中ならば0を返します。
 */
int stream_stat();

//{{2014/09/22追加:ストリームフィルタを追加しました。

/* ユーザーが用意する、ストリームフィルタ関数の型宣言です。
 * [in]
 *	wbuff		展開済みのサンプルデータへのポインタです。
 *			ストリームフィルタ関数は、この内容を変更したり、変更せずに別の目的に利用したりすることができます。
 *	len		サンプル数です。stream_play()に指定したBLKSと同じ値となります。
 */
typedef void STREAMFILTER(short wbuff[/*len*/], int len);

/* ストリームフィルタ関数を設定します。
 * [in]
 *	filter		ストリームフィルタ関数。
 *			NULLを指定すると、ストリームフィルタ関数を解除します。
 * [note]
 *	- ストリームフィルタ関数は、stream_play()～stream_stop()を超えて、維持する仕様としています。
 *	  詳細は、clippce.cの、「static STREAMFILTER* stream_filter;」のコメントを参照してください。
 */
void stream_filter_install(STREAMFILTER* filter);

//}}2014/09/22追加:ストリームフィルタを追加しました。

/****************************************************************************
 *	ユーティリティ：スタック切替コール
 ****************************************************************************/

/* 一時的にスタックを切り替えて、関数を呼び出します。
 * [in]
 *	sp		切替先スタックの終端アドレス。
 *	fn		呼び出す関数のアドレス。
 *	arg1		引数1。必要なければ0を指定してください。
 *	arg2		引数2。必要なければ0を指定してください。
 * [out]
 *	戻り値		呼び出した関数からの戻り値。
 * [note]
 *	* 次のように利用するのが一般的です。
 *
 *		retval = stack_switch(FRAM4_END, fn, arg1, arg2);
 *
 *	  FRAM4領域を高速スタックとして利用することが多いと思うので、
 *	  FRAM4領域のアドレスは下で定義してあります。ご利用ください。
 *
 *	* 呼び出す関数は、次のいずれかの形式でなければいけません。
 *
 *		void fn();
 *		void fn(int arg1);
 *		void fn(int arg1, int arg2);
 *		int  fn();
 *		int  fn(int arg1);
 *		int  fn(int arg1, int arg2);
 *
 *	* 2つ未満の引数しか使わない場合は、不要な引数には0を指定してください。
 *
 *		retval = stack_switch(sp, fn, arg1, 0);
 *		retval = stack_switch(sp, fn,    0, 0);
 *
 *	* 呼び出し先の関数が戻り値を返さない場合は、戻り値を無視してください。
 *
 *		stack_switch(FRAM4_END, fn, arg1, arg2);
 */
int stack_switch(void* sp, void* fn, int arg1, int arg2);

#define FRAM4_START	((void*)0x0e00)		/* FRAM4領域開始アドレス */
#define FRAM4_SIZE		0x0200		/* FRAM4領域サイズ       */
#define FRAM4_END	((void*)0x1000)		/* FRAM4領域終了アドレス */

/* * Fri Jan 7 04:19:00 JST 2005 Naoyuki Sawa
 * - FRAM4領域へのstack_switch()は頻繁に使うので、あらかじめ定義しておくことにしました。
 *   呼び出し前後でスタックが溢れていないことも検査します。
 */
int stack_switch_FRAM4(void* fn, int arg1, int arg2);

/****************************************************************************
 *	ユーティリティ：ファイル
 ****************************************************************************/

//→2002/11/26: OBSOLETEです。fread/fwriteを使ってください。
///* セクタに依存しない、ファイル読み込み関数です。
// * [in]
// *	fa		FILEACC構造体。(FOMD_RDで開いておく)
// *	ptr		バッファポインタ。
// *	ofs		ファイル先頭からのバイトオフセット。
// *	len		読み込むバイト数。
// * [out]
// *	戻り値		読み込んだバイト数。
// *			読み込みに失敗したら0を返します。
// * [note]
// *	* セクタ境界をまたいで読み込むこともできます。
// */
int file_read(FILEACC* fa, void* ptr, int ofs, int len);
//→GSM再生ルーチンがfile_read()を使っているので、宣言だけ残しておきます。
//  GSM再生ルーチンは、stream_play/stop対応の修正もまだですので、
//  stream_play/stop対応修正時にいっしょに、fread()を使うように修正する予定です。

//→2002/11/26: OBSOLETEです。fread/fwriteを使ってください。
///* セクタに依存しない、ファイル書き込み関数です。
// * [in]
// *	fa		FILEACC構造体。(FOMD_WRで開いておく)
// *	ptr		バッファポインタ。
// *	ofs		ファイル先頭からのバイトオフセット。
// *	len		書き込むバイト数。
// * [out]
// *	戻り値		書き込んだバイト数。
// *			書き込みに失敗したら0を返します。
// * [note]
// *	* セクタ境界をまたいで書き込むこともできます。
// *	* 既存のファイル内容のうち、書き込まなかった部分は変化せず、元の内容を維持します。
// *	  pceFileWriteSct()を使った場合は、同一セクタの書き込まなかった部分は消去されます。
// */
//int file_write(FILEACC* fa, const void* ptr, int ofs, int len);

//→2002/11/26: OBSOLETEです。unzipを使ってください。
///* ファイルパックからファイルを探します。
// * [in]
// *	fa		FILEACC構造体。(FOMD_RDで開いておく)
// *	fnmame		ファイル名。
// * [out]
// *	戻り値		ファイル情報へのポインタを返します。
// *			見つからなかったらNULLを返します。
// * [note]
// *	* この関数から返されるファイル情報へのポインタは、
// *	  関数内のstatic変数領域を指しています。
// *	  次回、この関数を呼んだときに破壊されますので、
// *	  必要ならば呼び出し元でコピーを取ってください。
// */
//FILE_INFO* fpak_find(FILEACC* fa, const char* fname);

/* フラッシュメモリ上で連続なセクタに配置されたファイルの先頭アドレスを取得します。
 * [in]
 *	fname		ファイル名。
 *	size		ファイルサイズを格納する変数へのポインタ。
 *			ファイルサイズが必要なければ、NULLを指定してください。
 * [out]
 *	戻り値		ファイルが存在し、連続セクタに配置されていたら、先頭アドレスを返します。
 *			ファイルが存在しないか、不連続セクタに配置されていたら、NULLを返します。
 *	*size		ファイルが存在し、連続セクタに配置されていたら、ファイルサイズを格納します。
 *			ただし、sizeにNULLポインタが指定されていた場合は、格納しません。
 */
const void* file_address(const char* fname, int* size);

//{{2003/09/14:あまり使わないので、OBSOLATEにしました。
///* 簡易ファイルセレクタです。
// * [in]
// *	header		ヘッダ文字列。
// *			NULLを指定すると、「ファイルを選んでください」となります。
// *	items		選択候補の文字列リスト。
// *	n_items		選択候補の数。
// *	footer		フッタ文字列。
// *			NULLを指定すると、「[Ａ]：決定／[Ｂ]：取消し」となります。
// * [out]
// *	戻り値		選択確定した場合は、選択された項目のインデックスを返します。
// *			選択取消しした場合は、-1を返します。
// * [note]
// *	* “ファイルセレクタ”と書きましたが、実際は汎用のアイテムセレクタです。
// *	   この関数自身にはファイルをリストアップする機能はありません。
// *	   アプリケーション側でファイルリストを作成する必要があります。
// */
//int file_select(const char* header, char* items[], int n_items, const char* footer);
//}}2003/09/14:あまり使わないので、OBSOLATEにしました。

/* ファイルを整列します。
 * [in]
 *	fname		ファイル名。
 *	size		ファイルサイズを格納する変数へのポインタ。
 *			ファイルサイズが必要なければ、NULLを指定してください。
 * [out]
 *	戻り値		整列したファイルの先頭メモリアドレス。
 *	*size		ファイルが存在し、連続セクタに配置されていたら、ファイルサイズを格納します。
 *			ただし、sizeにNULLポインタが指定されていた場合は、格納しません。
 */
const void* file_defrag(const char* fname, int* size); /* ->clipdfrg.c */

/* ファイルをメモリマッピングします。
 * [in]
 *	fname		ファイル名。
 *	size		ファイルサイズを格納する変数へのポインタ。
 *			ファイルサイズが必要なければ、NULLを指定してください。
 *	defrag		1を指定すると、セクタ不連続時にデフラグ処理を行います。
 *			0を指定すると、セクタ不連続時は失敗します。
 * [out]
 *	戻り値		成功したら、整列したファイルの先頭メモリアドレスを返します。
 *			ファイルが存在しないか、またはセクタ不連続かつdefrag=0の場合は失敗し、NULLを返します。
 *	*size		ファイルが存在し、連続セクタに配置されていたら、ファイルサイズを格納します。
 *			ただし、sizeにNULLポインタが指定されていた場合は、格納しません。
 * [note]
 *	* mmap()関数は、file_address()/file_defrag()の別名です。
 *	- 「mmap(fname, size, 0)」は、「file_address(fname, size)」と等価です。
 *	- 「mmap(fname, size, 1)」は、「file_defrag (fname, size)」と等価です。
 */
//const void* mmap(const char* fname, int* size, int defrag);
//↓2005/09/03:mmap()関数をマクロ化しました。
//↓これまでは、mmap()関数がfile_defrag()を参照していたため、デフラグ機能が不要なアプリケーションにもclipdfrg.oがリンクされていました。
//↓mmap()関数のマクロ化により、デフラグ機能が不要なアプリケーションにはclipdfrg.oがリンクされなくなり、2KB弱のメモリ節約となりました。
#define mmap(fname, size, defrag) (((defrag) ? file_defrag : file_address)((fname), (size)))

/* pexファイルの末尾に付加したリソースデータの、フラッシュメモリ上のアドレスを取得します。
 * [in]
 *	fname		pexファイル名。
 * [out]
 *	戻り値		リソースデータの先頭アドレス。
 * [note]
 *	* 目的のファイルがフラッシュメモリ上で整列していない場合、この関数の内部でデフラグを実行します。
 *	  目的のファイルのデフラグにより、他のファイルの整列が崩れる可能性があることに注意してください。
 *	* プログラム本体(4バイト単位)の直後に、リソースが付加されています。
 *	  付加を行う仕組みについては、test.pce/Makefileを参照してください。
 *	* リソースデータの形式は特に規定していませんが、通常はfpk形式で付加することになると思います。
 *	  (フラッシュメモリ上のデータを直接使うのが目的なので、圧縮されていてはあまり意味が無いから。)
 *	  戻り値のアドレスを、fpk_address()など、リソースデータ形式に応じた関数に引き渡してください。
 */
const void* resource_address(const char* fname); /* →clipdfrg.oの不要なリンクを避けるため、単独モジュールのclipres.cに実装しました */

//{{2015/11/18削除:「ユーティリティ：拡張タイマ」を、(clippce.h,clippce.c)⇒(cliptimr.h,cliptimr.c)へ移動しました。
///****************************************************************************
// *	ユーティリティ：拡張タイマ
// ****************************************************************************/
//
///* * 拡張タイマ機能を作成した理由は、以下のとおりです。
// *
// *   1. pceTimerSetCallback()は、同時利用可能なチャネルが少ない
// *	pceTimerSetCallback()は、Ch.0-3の4チャネルしか利用できません。
// *	(カーネル1.20においては、Ch.4も利用可能ですが、仕様外です)
// *	拡張タイマは、同時に32の拡張タイマを利用可能です。(2005/09/04現在)
// *	→2005/09/17 16個に減らしました。
// *	→2014/12/28 無制限になりました。					//{{2014/12/28変更:拡張タイマテーブルを、固定割り当て⇒動的割り当てに変更しました。}}
// *
// *   2. pceTimerSetCallback()は、チャネル衝突の回避が困難である
// *	pceTimerSetCallback()は、呼び出し側にてチャネル番号を指定するので、
// *	関連の無い複数のルーチンが同時にタイマを利用する場合、チャネル衝突の回避が困難です。
// *	拡張タイマは、timer_start()から呼び出し側へ拡張タイマIDを返すので、
// *	関連の無い複数のルーチンが同時にタイマを利用する場合も、チャネル衝突は有り得ません。
// *
// * * 拡張タイマ機能は、pceTimerSetCallback()のCh.0を利用しています。(2005/09/04現在)
// *   最初にtimer_start()を呼び出したとき、pceTimerSetCallback()のCh.0を設定します。
// *   以後、ライブラリの終了ルーチンにて自動的にタイマを停止するまで、そのままです。
// *   以下の点に注意してください。
// *
// *   1. pceTimerSetCallback()のCh.0を利用するアプリケーションと併用できません
// *	pceTimerSetCallback()のCh.0を利用するアプリケーションは、timer_start()を利用しないでください。
// *	timer_start()を利用するアプリケーションは、pceTimerSetCallback()のCh.0を利用しないでください。
// *	今後のプログラム作成方針として、アプリケーション、および、CLiPライブラリ内の各モジュールは、
// *	pceTimerSetCallback()のいずれのチャネルも利用せず、timer_start()を利用するようにしてください。
// *	(2005/09/04現在、clipcbxモジュールがpceTimerSetCallback()のCh.0を利用しています。いずれ修正する予定です)
// *
// *   2. timer_start()を呼び出すと、アプリケーション終了まで、一定のオーバーヘッドが発生します
// *	拡張タイマ機能は、pceTimerSetCallback()のCh.0を利用し、1ミリ秒コールバックにてドライブしています。
// *	アプリケーション実行後、初回のtimer_start()にて、pceTimerSetCallback()のCh.0を起動しています。
// *	(2005/09/04現在の実装は、簡単のために、timer_start()が呼ばれる度にpceTimerSetCallback()のCh.0を
// *	 再起動していますが、アプリケーションから見た挙動は、初回呼び出し時のみ起動と見なしても同じです)
// *	timer_start()を呼び出さないアプリケーションでは、拡張タイマ機能のオーバーヘッドは発生しません。
// *	一度でもtimer_start()を呼び出すと、アプリケーション終了まで1ミリ秒コールバックが継続するため、
// *	オーバーヘッドが発生します。(実際には、気にするほどの速度低下では無いかも知れませんが…)
// *	処理速度が重要なアプリケーションにおいては、無駄にtimer_start()を利用しないよう注意してください。
// */
//
///* 拡張タイマを開始します。
// * [in]
// *	interval	コールバック間隔[ms]。
// *			1以上の値を指定してください。1未満の値を指定すると、エラー終了します。
// *	callback	コールバック関数。
// *			コールバック関数の指定は必須です。NULLを指定すると、エラー終了します。
// *	context		コールバック引数。
// *			アプリケーションにて、自由に設定できます。
// * [out]
// *	戻り値		拡張タイマID。
// *			2005/09/10追記: これまで0～31を返していましたが、1～32となるよう変更しました。
// *			アプリケーションが保持している拡張タイマIDの、有効or無効を簡単にするためです。
// *			→2005/09/17 1～16に減らしました。
// *			→2014/12/28 1～∞に変更しました。			//{{2014/12/28変更:拡張タイマテーブルを、固定割り当て⇒動的割り当てに変更しました。}}
// * [note]
// *	* 2005/09/04現在、同時に32個までの拡張タイマが利用可能です。
// *	  同時に32個を超える拡張タイマを利用しようとすると、エラー終了します。
// *	  →2005/09/17 16個に減らしました。
// *	  →2014/12/28 無制限になりました。					//{{2014/12/28変更:拡張タイマテーブルを、固定割り当て⇒動的割り当てに変更しました。}}
// *	* 拡張タイマを停止せずに、アプリケーションを終了しても安全です。
// *	  アプリケーション終了時に、ライブラリが適切に拡張タイマを停止します。
// *	* 2005/09/17追記 コールバック引数の指定を追加しました。
// */
//int timer_start(int interval, void (*callback)(void* context), void* context);
//
///* 拡張タイマを停止します。
// * [in]
// *	id		拡張タイマID。
// *			timer_start()から返された拡張タイマIDを指定してください。
// *			不正な拡張タイマIDや、既に停止した拡張タイマIDを指定すると、エラー終了します。
// */
//void timer_stop(int id);
//}}2015/11/18削除:「ユーティリティ：拡張タイマ」を、(clippce.h,clippce.c)⇒(cliptimr.h,cliptimr.c)へ移動しました。

/****************************************************************************
 *	ユーティリティ：タイムアウト処理
 ****************************************************************************/

/* タイムアウト時間が経過するか、明示的に中断されるまで、同じ処理を繰り返します。
 * [in]
 *	timeout		タイムアウト時間[ms]。(0以上)
 *	action		繰り返す処理。(以下、アクションと呼びます)
 * [out]
 *	戻り値		タイムアウトした場合、-1を返します。
 *			アクションの中で、BREAK_TIMEOUTを呼び出した場合、0を返します。
 *			または、BREAK_TIMEOUT_()を呼び出した場合、その引数を返します。
 * [note]
 *	* タイムアウト時間に0を指定した場合も、必ず一度はアクションを実行します。
 *	  その後、ただちに処理を返します。
 *	* REPEAT_TIMEOUT()マクロは、以下のGCC拡張機能を利用しています。
 *	- 式の中の文と宣言
 *	- 局所的に宣言されたラベル
 *	- 定数以外の初期化子
 * [note]
 *	* "if(0) { goto __RESTART__; goto __CONTINUE__; goto __BREAK__; }"は、
 *	  未使用ラベルに対するコンパイラ警告を抑制するための記述です。
 *	  コンパイラの最適化により削除されるので、実行バイナリには残りません。
 */
#define REPEAT_TIMEOUT(timeout, action) ({				\
__label__ __RESTART__, __CONTINUE__, __BREAK__;				\
	int __result__, __timeout__, __start__;				\
	if(0) { goto __RESTART__; goto __CONTINUE__; goto __BREAK__; }	\
	__timeout__ = (timeout);					\
__RESTART__:								\
	__start__ = pceTimerGetCount();					\
	do {								\
		action;							\
__CONTINUE__:								\
	} while(pceTimerGetCount() - __start__ < __timeout__);		\
	__result__ = -1;						\
__BREAK__:								\
	__result__;							\
})

/* 結果コード0で、REPEAT_TIMEOUT()を中断します。 */
#define BREAK_TIMEOUT			BREAK_TIMEOUT_(0)

/* 結果コードを指定して、REPEAT_TIMEOUT()を中断します。 */
#define BREAK_TIMEOUT_(result)		do { __result__ = (result); goto __BREAK__; } while(0)

/* アクションの残りをスキップし、タイムアウト時間を変更せずに、タイムアウト判定へ進みます。 */
#define CONTINUE_TIMEOUT		CONTINUE_TIMEOUT_(__timeout__)

/* アクションの残りをスキップし、タイムアウト時間を再設定して、タイムアウト判定へ進みます。 */
#define CONTINUE_TIMEOUT_(timeout)	do { __timeout__ = (timeout); goto __CONTINUE__; } while(0)

/* アクションの残りをスキップし、タイムアウト時間を変更せずに、タイムアウト処理を再起動します。 */
#define RESTART_TIMEOUT			RESTART_TIMEOUT_(__timeout__)

/* アクションの残りをスキップし、タイムアウト時間を再設定して、タイムアウト処理を再起動します。 */
#define RESTART_TIMEOUT_(timeout)	do { __timeout__ = (timeout); goto __RESTART__; } while(0)

/* REPEAT_TIMEOUT()の使用例:
 *
 *	* 1000ミリ秒タイムアウトするまで、変数aをインクリメントし続けます。
 *	  途中で終了することはありません。
 *
 *		REPEAT_TIMEOUT(1000, a++);
 *
 *	* 一度だけ変数aをインクリメントし、ただちに処理を返します。
 *	  単純に"a++"と書くのと等価であり、あまり意味はありません。
 *
 *		REPEAT_TIMEOUT(0, a++);
 *
 *	* 192.168.1.1の80番ポートに対し、TCPアクティブオープンを起動します。
 *	  3000ミリ秒以内に接続が確立したら、(result= 0)となります。
 *	  3000ミリ秒以内に接続できなければ、(result=-1)となります。
 *	  resultの値によって、接続成功、または、接続失敗時の処理を行います。
 *
 *		socket = tcp_socket_open(0, IP_ADDRESS(192,168,1,1), 80, 1);
 *		result = REPEAT_TIMEOUT(3000,
 *			if(tcp_socket_state(socket) == TCP_ESTABLISHED) {
 *				BREAK_TIMEOUT;
 *			}
 *		);
 *		if(result == 0) {
 *			// 接続成功
 *		} else {
 *			// 接続失敗
 *		}
 *
 *	  ただし実際には、TCP_ESTABLISHEDを経由してTCP_CLOSED等へ進んでしまう場合があり、
 *	  上述のコードではそのようなケースに対応できないことに注意してください。
 *	  tcp_socket_recv()、tcp_socket_send()は、未接続状態にて負数ではなく0を返すので、
 *	  上述のコードのような、明示的な接続待ちを行う必要はありません。
 *	  接続が確立するまでの間、tcp_socket_recv()の戻り値(0)はパケット未到着と同じ、
 *	  tcp_socket_send()の戻り値(0)は送信バッファ空き無しと同じと見なすことができます。
 *	  従って、tcp_socket_open()後、ただちに、送受信処理へ進んでしまって大丈夫です。
 *
 *	* TCPソケットから、データを読み出します。
 *	  3000ミリ秒以内にデータが到着したら、(result=データ長)となります。
 *	  データが到着しないか、または、相手側から切断されたら、(result=負数)となります。
 *	  resultの値によって、受信成功、または、受信失敗時の処理を行います。
 *	  tcp_socket_recv()が、相手から切断されたときに負数の戻り値を返すことを利用して、
 *	  タイムアウト(戻り値=-1)と同じ条件で判断しています。
 *
 *		result = REPEAT_TIMEOUT(3000,
 *			int tmpval = tcp_socket_recv(socket, buf, buflen);
 *			if(tmpval) { // データが到着したら正数、切断されたら負数
 *				BREAK_TIMEOUT_(tmpval);
 *			}
 *		);
 *		if(result > 0) {
 *			// 受信成功 (buf[0..result-1]に、受信データが入っている)
 *		} else {
 *			// 受信失敗 (タイムアウト、または、相手側から切断された)
 *		}
 *
 *	  上のコードでは、読み易さのために、ローカル変数tmpvalを使っていますが、
 *	  次のように、resultを使っても結果は同じです。
 *	  REPEAT_TIMEOUT()の戻り値からresultへの代入が、最後に行われるからです。
 *
 *		result = REPEAT_TIMEOUT(3000,
 *			result = tcp_socket_recv(socket, buf, buflen);
 *			if(result) { // データが到着したら正数、切断されたら負数
 *				BREAK_TIMEOUT_(result);
 *			}
 *		);
 *		if(result > 0) {
 *			// 受信成功 (buf[0..result-1]に、受信データが入っている)
 *		} else {
 *			// 受信失敗 (タイムアウト、または、相手側から切断された)
 *		}
 *
 *	  2005/09/23現在のTCPドライバは、再送間隔2000ミリ秒で実装しているので、
 *	  タイムアウト時間はそれよりも長い時間としてください。(推奨、3000ミリ秒)
 *	  再送間隔よりも短いタイムアウトでは、再送処理が意味を成さなくなります。
 *
 *	* TCPソケットから、1文字づつ受信を試みます。
 *	  TCPソケットが相手から切断されたら、ただちに処理を返します。
 *	  受信データが無いか、または、制御文字を受信した場合は、何もしません。
 *	  それ以外の場合は、関数foo()にて、受信した文字を処理します。
 *	  以上の処理を繰り返し、3000ミリ秒でタイムアウトします。
 *
 *		REPEAT_TIMEOUT(3000,
 *			result = tcp_socket_recv(socket, &ch, 1);
 *			if(result < 0) {
 *				BREAK_TIMEOUT_(result);
 *			}
 *			if(!result) {
 *				CONTINUE_TIMEOUT;
 *			}
 *			if(ch < ' ') {
 *				CONTINUE_TIMEOUT;
 *			}
 *			foo(ch);
 *		);
 *
 *	* UDPソケットに最初のパケットが到着するまで、3000ミリ秒待ちます。
 *	  3000ミリ秒以内に最初のパケットが到着しなければ、タイムアウトします。
 *	  3000ミリ秒以内に最初のパケットが到着した場合は、関数foo()にて処理を行います。
 *	  以降、1000ミリ秒間隔で次のパケットが到着する間、タイムアウトせずに処理を継続します。
 *
 *		REPEAT_TIMEOUT(3000,
 *			result = udp_socket_recv(socket, NULL, NULL, buf, buflen);
 *			if(result >= 0) {
 *				foo(buf, result);
 *				RESTART_TIMEOUT_(1000);
 *			}
 *		);
 */

/****************************************************************************
 *	zlib展開 -> clipzlib.c
 ****************************************************************************/

//→2002/11/26: OBSOLETEです。unzipを使ってください。
///* ファイルに含まれる圧縮データを展開します。
// * [in]
// *	fa		FILEACC構造体。(FOMD_RDで開いておく)
// *	outbuf		展開バッファ。
// *	outlen		展開バッファサイズ。
// *	inofs		圧縮データの先頭オフセット。
// *	inlen		圧縮データのバイト数。
// *			0を指定すると、inofsからファイル終端までと見なします。
// * [out]
// *	戻り値		展開後のバイト数。
// *			展開に失敗したら0を返します。
// */
//int file_inflate(FILEACC* fa, void* outbuf, int outlen, int inofs, int inlen);

//→2002/11/26: OBSOLETEです。unzipを使ってください。
///* ファイルに含まれる圧縮データの展開サイズを調べます。
// * [in]
// *	fa		FILEACC構造体。(FOMD_RDで開いておく)
// *	inofs		圧縮データの先頭オフセット。
// *	inlen		圧縮データのバイト数。
// *			0を指定すると、inofsからファイル終端までと見なします。
// * [out]
// *	戻り値		展開後のバイト数。
// *			展開に失敗したら0を返します。
// */
//int file_inflate_size(FILEACC* fa, int inofs, int inlen);

//→2002/11/26: OBSOLETEです。unzipを使ってください。
///* ファイルパックに含まれる圧縮データを展開します。
// * [in]
// *	fa		FILEACC構造体。(FOMD_RDで開いておく)
// *	outbuf		展開バッファ。
// *	outlen		展開バッファサイズ。
// *	fname		ファイル名。
// * [out]
// *	戻り値		展開後のバイト数。
// *			展開に失敗したら0を返します。
// */
//int fpak_inflate(FILEACC* fa, void* outbuf, int outlen, const char* fname);

//→2002/11/26: OBSOLETEです。unzipを使ってください。
///* ファイルパックに含まれる圧縮データの展開サイズを調べます。
// * [in]
// *	fa		FILEACC構造体。(FOMD_RDで開いておく)
// *	fname		ファイル名。
// * [out]
// *	戻り値		展開後のバイト数。
// *			展開に失敗したら0を返します。
// */
//int fpak_inflate_size(FILEACC* fa, const char* fname);

/* メモリ上のデータを圧縮します。
 * [in]
 *	out		圧縮バッファ。
 *	outlen		圧縮バッファサイズが設定された変数へのポインタ。
 *	in		データバッファ。
 *	inlen		データサイズ。
 * [out]
 *	戻り値		成功ならZ_OK。
 *			失敗ならZ_OK以外の値を返します。
 *	*out		成功なら圧縮データが格納されます。
 *			失敗なら内容は不定となります。
 *	*outlen		成功なら圧縮データサイズが格納されます。
 *			失敗なら内容は不定となります。
 * [note]
 *	* 圧縮処理は展開処理以上に作業用メモリを必要とするので、
 *	  zlib標準のcompress()やcompress2()では、メモリ不足で利用できません。
 *	- また、zlib 1.1.4 には、deflateInit2()のエラー処理に問題があるようです。
 *	  deflateInit2()でエラーが起きると、zlib内部でメモリリークしてしまいます。
 *	  deflateInit2()を使っている、compress()やcompress2()も同様です。
 *	- deflateInit2()が失敗するのはたいてい、作業用メモリが足りない場合です。
 *	  以上の理由により、省メモリ設定の圧縮関数を用意することにしました。
 *	- しかしながら、それでも作業用メモリが不足することはあります。
 *	  圧縮データサイズに比例した作業用メモリが必要になるようで、
 *	  約8KBのデータ圧縮時には、16KB程度の作業用メモリが必要でした。
 *	  大きなデータを圧縮しようとすると、deflateInit2()が失敗し、メモリリークします。
 *	  この関数が失敗した場合は、メッセージ表示後、プログラムを終了した方が安全です。
 *	* my_compress()を呼ぶ前に、*outlen圧縮バッファサイズを設定しておくのを忘れないで！
 *	* 展開には、zlib標準のuncompress()をそのまま使ってください。
 */
int my_compress(void* out, int* outlen, const void* in, int inlen);

/****************************************************************************
 *	zip展開 -> clipunz.c
 ****************************************************************************/

/* 一般的なZIPファイル読み込み手順を行います。
 * [in]
 *	zip_fname	ZIPファイル名。「mydata.zip」等です。
 *	item_name	ZIPファイル内のアイテム名。「music1.mod」等です。
 *			フォルダ付きで指定することもできます。「mus/music1.mod」等です。
 *	buffer		読み込み先バッファの先頭アドレス。
 *			NULLを指定すると、アイテムを読み込まずにサイズだけを取得します。
 *	max_size	バッファサイズ。アイテムサイズがこれより大きければ読み込み失敗します。
 *			bufferにNULLを指定した場合は、max_sizeは無視します。
 *	ufi_out		unz_file_info変数へのポインタを指定すると、読み込んだアイテムの情報が格納されます。
 *			読み込み失敗時の格納値は不定です。(現在は“変化なし”ですが、今後変更の可能性あり。)
 *			アイテムの情報が必要ない場合は、NULLポインタを指定してください。
 * [out]
 *	戻り値		読み込み成功なら、アイテムのバイト数を返します。
 *			読み込み失敗なら、0を返します。
 * [note]
 *	* この関数はunzWindowBitsを操作しません。
 *	  スライドウインドウサイズを減らして作業メモリを節約する場合は、
 *	  この関数を呼び出す側で「unzWindowBits=9」を行ってください。
 *	  圧縮ファイル作成時も「minizip -w9 ...」と指定するのを忘れずに！
 */
int my_unzip(const char* zip_fname, const char* item_name, void* buffer, int max_size, unz_file_info* ufi_out);

/****************************************************************************
 *	GSM再生 -> clipgsm.c
 ****************************************************************************/

/* GSMファイルの再生を開始します。
 * [in]
 *	ch		再生チャネル。(0～3)
 *	fname		GSMファイル名。
 *	loop		ループ回数。(-1:無限,0:再生しない,1～:ループ回数)
 * [out]
 *	戻り値		正しく再生を開始できたら0を返します。
 *			失敗したら-1を返します。(ファイルが見つからない、等)
 */
int gsm_play(int ch, const char* fname, int loop);

/* GSMファイルの再生を停止します。
 * [note]
 *	* 再生中でなければ、この関数は何もしません。
 */
void gsm_stop();

/****************************************************************************
 *	割り込みレベル設定
 ****************************************************************************/

//┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
//┃■割り込みレベルの方針を、以下のように定めることにします。                                                                    ┃
//┃│①割り込み外,及び,割り込みレベル1の割り込み処理内では、ヒープマネージャAPI(pceHeap*)とファイルAPI(pceFile*)を使用して良い。 ┃
//┃│②割り込みレベル2以上の割り込み処理内では、ヒープマネージャAPI(pceHeap*)とファイルAPI(pceFile*)を使用してはいけない。       ┃
//┃│③ヒープマネージャAPI(pceHeap*)とファイルAPI(pceFile*)を、当モジュールにてフックして、割り込みレベル1以下をマスクしている。 ┃
//┃│　ルール①②に従う限り、アプリケーションはヒープマネージャAPI(pceHeap*),ファイルAPI(pceFile*)の排他制御を意識しなくて良い。 ┃
//┃上記のルールを設けた主な理由は、GCが起動した時に、ミキシング割り込みが長時間禁止されて、音飛びすることを極力避けるためです。  ┃
//┃今後は、GCの実行中にも割り込みレベル2以上の割り込みは許可されるので、ミキシング割り込み(=レベル7)が発生できるようになります。 ┃
//┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
// * Fri Dec 19 22:30:18 JST 2014 Naoyuki Sawa
// - '割り込み外でヒープマネージャAPIを呼び出す(1)⇒割り込みレベル1をマスク⇒ミキシング割り込み⇒ストリームコールバック起動⇒ヒープマネージャAPIを呼び出す(2)'	┐
//   という場合において、(1)と(2)のヒープマネージャAPIが排他制御されない問題が起こり得ると思う。本当に起こり得るか検証し、起こり得るならば対策方法を検討せよ。	├→2014/12/22対策済み｡後述のｺﾒﾝﾄ参照せよ｡
//   (ただし、ストリームコールバック内でヒープマネージャAPIやファイル書き込みAPIを使用しなければ現在化しないと思うので、緊急ではない。)				┘
// * Mon Dec 22 00:00:51 JST 2014 Naoyuki Sawa
// - 上記の問題が起こり得ることを確認した。対策方法を検討せよ。													─→2014/12/22対策済み｡後述のｺﾒﾝﾄ参照せよ｡
//   □問題を再現するﾌﾟﾛｸﾞﾗﾑ:
//   │static int stream_callback(short wbuff[/*320*/],int param){
//   │  int i;
//   │  for(i=0;i<320;i++){wbuff[i]=(i&32)?SHRT_MAX:SHRT_MIN;}
//   │  malloc(4);//app_main()のmalloc()実行中に当関数が呼び出される可能性があり､ここでﾋｰﾌﾟ破損を検出してｴﾗｰ停止する｡
//   │  return 0;
//   │}
//   │void app_main(){
//   │  int i;
//   │  BitmapGC_Init(3);
//   │  stream_play(320,stream_callback,0,0);
//   │  do{
//   │    schedule();
//   │    surface_clear(&surface,0);
//   │    render_printf(&render,0,0,1,3,"%d\n%d",now,pceHeapGetMaxFreeSize());
//   │//ENTER_CS;//この行を有効にするとｴﾗｰ停止しなくなるが､音飛びの問題が出る｡
//   │    for(i=0;i<1000;i++){malloc(4);}
//   │//LEAVE_CS;//この行を有効にするとｴﾗｰ停止しなくなるが､音飛びの問題が出る｡
//   │  }while(!pcePadGetDirect());
//   │  BitmapGC_Free();
//   │}
// * Mon Dec 22 21:06:44 JST 2014 Naoyuki Sawa
// - 上記の問題を解決しました。
//   対策方法,及び,変更内容は、「Mon Dec 22 21:06:44 JST 2014」,及び,「//{{2014/12/22」のコメントを参照してください。
// - ライブラリが適切に排他制御を行うようになったので、今後はアプリケーションが上記の排他制御を意識する必要は有りません。
// - GCと併用すると、音飛びすることがあります。
//   GCが起動すると、長時間ENTER_IL(1)～LEAVE_ILとなり、ストリームコールバック処理が起動できないからです。
//   アプリケーション定義のストリームコールバック処理の中で、ヒープAPIやGCを使用*しない*ことが確実である場合は、		┐
//   アプリケーションにて『bINT_PHSD01L_PHSD0L = 2;』を実行することによって、音飛びを低減できます。				├→2014/12/25追記:stream_play()の第3引数に0を指定すればストリームコールバックを(IL=2)にできるようになりました。詳細はclippce.hのstream_play()の説明を参照してください。
//   ストリームコールバック処理を擬似的な割り込みレベル2とすることによって、GC実行中にも起動できるようになるからです。		┘
//   ほとんどのアプリケーション(及びサウンド関連モジュール)において、ストリームコールバック処理の中でヒープAPIやGCを使用しないので、
//   上記の対策を行っても安全ではありますが、充分の注意して行ってください。
//   もし、ストリームコールバック処理の中でヒープAPIやGCを使用するアプリケーションが『bINT_PHSD01L_PHSD0L = 2;』を行うと、
//   前述の'ヒープマネージャAPIが排他制御されない問題'が再発してしまうからです。
// - 尚、『bINT_PHSD01L_PHSD0L = 2;』を行っても、タイマ割り込みの中でGCが起動した場合は音飛びを防ぐことはできません。		┐
//   タイマ割り込み処理中はENTER_CS～LEAVE_CSとなり、割り込みレベルに関係なく割り込みがマスクされるからです。			├→2014/12/24対策済み。clippce.cの「タイマ割り込み処理中の多重割り込み許可」の'Wed Dec 24 19:14:00 JST 2014'のコメントを参照せよ。
//   タイマ割り込み処理中に多重割り込みに切り替えることは、タイマ割り込みがP/ECEのタイマAPIを利用しているため難しいです。	│
//   タイマ割り込みの中でGCが起動した場合に音飛びすることは、回避できません。(音飛び以外の動作には、問題ありません。)		┘
//─────────────────────────────────────────────────────────────────

/* 割り込みレベルを、指定された割り込みレベル以上へ引き上げます。
 * [in]
 *	il		割り込みレベル	0～15	S1C33209のITCは8以上に未対応なので、実質は8以上を指定しても意味がありません。
 * [out]
 *	戻り値		変更前の%psr		後でLeaveIL()にこの値を渡して、割り込みレベルを元のレベルに復元してください。
 * [note]
 *	- P/ECE標準APIにも、割り込みレベルを設定するマクロやAPIが用意されてはいる。
 *	  ・/usr/PIECE/include/s1c33cpu.h: SET_IL0～SET_IL7
 *	  ・/usr/PIECE/lib/src/pceSyncSafetySetIL.s,/usr/PIECE/sysdev/pcekn/critical.c: pceSyncSafetySetIL
 *	  しかし、これらのマクロやAPIは使いづらい。
 *	  一般的に必要な要件は、「現在の割り込みレベルが特定のレベル未満ならば、特定のレベルまで引き上げる」処理である。
 *	  しかし、上記のマクロやAPIは、無条件で割り込みレベルを変更してしまうため、上記の要件を満たせない。
 *	  さらに悪いことに、pceSyncSafetySetILは、ILを設定するだけでなくIEもセットしてしまう、余計な処理が行われている。
 *	- SET_IL0～SET_IL7やpceSyncSafetySetILは使いづらいので、割り込みレベルを設定する関数を自前で作成することにした。
 *	  以下の、EnterILとLeaveIL,及び,ENTER_ILとLEAVE_ILが、それです。
 *	  ENTER_IL,LEAVE_ILを経由して使用することを推奨します。使い方は既存のENTER_CS,LEAVE_CSと同様です。
 */
int EnterIL(int il);

/* 割り込みレベルを、元のレベルに復元する。
 * [in]
 *	psr		変更前の%psr
 */
void LeaveIL(int psr);

//□使用例
//│void test(){
//│ENTER_IL(6);//割り込みﾚﾍﾞﾙが6以下の割り込みをﾏｽｸする｡
//│  ～処理～
//│LEAVE_IL;   //割り込みﾚﾍﾞﾙのﾏｽｸ状態を元に戻す｡
//│}
#define ENTER_IL(il) do { const int __il__ = EnterIL(il)
#define LEAVE_IL LeaveIL(__il__); } while(0)

/****************************************************************************
 *	8ビットプログラマブルタイマ割り込みの一元管理
 ****************************************************************************/

/* 8ビットプログラマブルタイマ割り込みのコールバックを設定します。
 * [in]
 *	iCh		チャネル番号。		0～3
 *	callback	コールバック関数。	NULLを指定すると、設定を解除します。
 * [note]
 *	- 当機能が、8ビットプログラマブルタイマ割り込みの、割り込みプライオリティ,割り込みイネーブルフラグ,割り込み要因フラグ,割り込みサービスルーチンを、一元管理します。
 *	  当機能を使用するアプリケーションや他のモジュールは、上記のレジスタを操作してはいけません。
 *	- 当機能は、8ビットプログラマブルタイマの、割り込み以外のレジスタを操作しません。
 *	  具体的には、制御レジスタ,リロードデータレジスタ,カウントデータレジスタは、当機能の管理外です。アプリケーションや他のモジュールが、それらを直接設定してください。
 *	- 8ビットプログラマブルタイマを、割り込み以外の用途に使用するアプリケーションや他のモジュールは、当機能を使用する必要はありません。
 *	  例えば、IC外部へのクロック出力や、シリアルインターフェイスへのクロック供給として使用し、当該チャネルの割り込みを使用しない場合は、当機能を使う必要はありません。
 */
void install_8tu_interrupt_callback(int iCh, void (*callback)());

/****************************************************************************
 *	割り込みサービスルーチンを定義するマクロ
 ****************************************************************************/

// * Sun Jan 04 13:35:55 JST 2015 Naoyuki Sawa
// - 「割り込みサービスルーチンを定義するマクロ」を追加しました。
// - ISR_DEF()マクロを使って割り込みサービスルーチンを定義すると、以下の利点が有ります。
//   1. C関数だけで割り込みサービスルーチンを定義できます。明示的にasmブロックを書く必要が有りません。
//   2. レジスタ退避処理が共通処理になり、コードサイズを節約できます。
// - ■使用例①宣言と定義を同時に行う例
//   │ISR_DEF(p7_isr) {
//   │  bRST_RESET_RSTONLY=1;
//   │  pINT_FP47_FCT_FAD=(1<<5);
//   │  bRST_RESET_RSTONLY=0;
//   │  //～略～
//   │}
//   │void app_init() {
//   │  //～略～
//   │  pceVectorSetTrap(TRAP_P7,p7_isr);
//   │  //～略～
//   │}
// - ■使用例②宣言と定義を分けて行う例
//   │ISR_DEF(p7_isr);
//   │void app_init() {
//   │  //～略～
//   │  pceVectorSetTrap(TRAP_P7,p7_isr);
//   │  //～略～
//   │}
//   │static void _p7_isr() {
//   │  bRST_RESET_RSTONLY=1;
//   │  pINT_FP47_FCT_FAD=(1<<5);
//   │  bRST_RESET_RSTONLY=0;
//   │  //～略～
//   │}
#define ISR_DEF(__isr__)											\
	asm(".code \n .align 2 \n " #__isr__ ": \n ext isr_call@rm \n call isr_call@rl \n .word _" #__isr__);	\
	extern void __isr__(); static void __attribute__((unused)) _##__isr__()

/****************************************************************************
 *	main()を呼び出す前に初期化関数を実行する仕組み
 *	main()が終了した後に終了時関数を実行する仕組み
 ****************************************************************************/

// * Thu Jun 02 21:20:46 JST 2016 Naoyuki Sawa
// - 「main()を呼び出す前に初期化関数を実行する仕組み」を追加しました。
//   VC++の、同様の仕組みを参考にしました。
//   ただし、VC++では特定の名前を付けたデータセクションに初期化関数のポインタを登録するという方法ですが、P/ECE開発環境のgcc33.exeでは名前を付けてセクションを作成出来ないので、少し違う方法を取る事にしました。
//   CODEセクション内に初期化関数のポインタ配列を作成し、その直前に特定のシグネチャを置くという方法です。
//   ライブラリの初期化ルーチン(から呼び出される_cinit())が、CODEセクション全体を走査して、シグネチャを頼りに初期化関数のポインタ配列を見つけ、初期化関数を呼び出します。
//   シグネチャの文字列は何でも良かったのですが、VC++のセクション名に倣って".CRT$XIU"とする事にしました。
//   詳細は、clippce.c内のローカル関数_cinit()の実装を参照して下さい。
//   ちなみに、そのローカル関数_cinit()の名前も、VC++の同様の処理を行う内部関数_cinit()(C:\Program Files (x86)\Microsoft Visual Studio\VC98\CRT\SRC\CRT0DAT.C)から名前を取りました。
// - ■main()よりも前に呼び出される初期化関数を登録するには、以下のような配列を定義して下さい。
//   │static void InitFunc1() { ～ }      //初期化関数。関数名は任意です。
//   │static void InitFunc2() { ～ }      //初期化関数。関数名は任意です。
//   │static void* const TBL_InitTbl[]={  //初期化関数を登録する配列。配列名は任意です。
//   │    //       ~~~~~忘れないで!!
//   │    (void*)FOURCC_pCRT,             //┬配列のシグネチャ
//   │    (void*)FOURCC_dXIU,             //┘
//   │    InitFunc1,                      //┬0個以上、複数指定可
//   │    InitFunc2,                      //┘
//   │    NULL};                          //終端。忘れないで!!
//   上記の配列を、一つのモジュール内に複数定義する事も出来ますし、複数のモジュールに複数定義する事も出来ます。
//   また、ライブラリ内に定義する事も出来ますし、アプリケーション内に定義する事も出来ます。
//   上記の特性は、VC++の初期化関数の仕組みと同じです。
// * Fri Jun 03 21:47:06 JST 2016 Naoyuki Sawa
// - 「main()が終了した後に終了時関数を実行する仕組み」を追加しました。
//   方法は、昨日追加した「main()が終了した後に終了時関数を実行する仕組み」と同じです。
//   ".CRT$XTU",_cexit(),_initterm()の名前も、VC++の同様の処理を行う内部関数(C:\Program Files (x86)\Microsoft Visual Studio\VC98\CRT\SRC\CRT0DAT.C)から名前を取りました。
// - 終了時処理は既存のatexit()で登録出来るので、今回追加したような仕組みを追加する必要も無かったのですが、昨日追加した処理と_initterm()を共用して少ないコストで追加出来るので、追加しておく事にしました。
//   尚、atexit()で登録した関数と、今回追加した仕組みで登録した関数の順序は、atexit()で登録した関数の方が先です。(この点もVC++と同じです。)
// - ■main()が終了した後に呼び出される終了時関数を登録するには、以下のような配列を定義して下さい。
//   │static void ExitFunc1() { ～ }      //終了時関数。関数名は任意です。
//   │static void ExitFunc2() { ～ }      //終了時関数。関数名は任意です。
//   │static void* const TBL_ExitTbl[]={  //終了時関数を登録する配列。配列名は任意です。
//   │    //       ~~~~~忘れないで!!
//   │    (void*)FOURCC_pCRT,             //┬配列のシグネチャ
//   │    (void*)FOURCC_dXTU,             //┘
//   │    ExitFunc1,                      //┬0個以上、複数指定可
//   │    ExitFunc2,                      //┘
//   │    NULL};                          //終端。忘れないで!!
//   上記の配列を、一つのモジュール内に複数定義する事も出来ますし、複数のモジュールに複数定義する事も出来ます。
//   また、ライブラリ内に定義する事も出来ますし、アプリケーション内に定義する事も出来ます。
//   上記の特性は、VC++の終了時関数の仕組みと同じです。
#define FOURCC_pCRT	MAKEFOURCC('.','C','R','T')	//period,C,R,T
#define FOURCC_dXIU	MAKEFOURCC('$','X','I','U')	//dollar,X,I,U
#define FOURCC_dXTU	MAKEFOURCC('$','X','T','U')	//dollar,X,T,U

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

#endif /*__CLIP_PCE_H__*/
