/*	
 *	clipdbg.h
 *
 *	デバッグモード
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2007 Naoyuki Sawa
 *
 *	* Sat Sep 08 22:23:37 JST 2007 Naoyuki Sawa
 *	- 1st リリース。
 *	* Sun Sep 09 12:02:00 JST 2007 Naoyuki Sawa
 *	- デバッグ機能を制御するレジスタの定義名を間違えていたのを修正しました。
 *	* Fri Sep 21 17:34:51 JST 2007 Naoyuki Sawa
 *	- dbg_call()は使い勝手が悪かったので、廃止しました。
 *	  dbg_call()の代わりに、インラインでデバッグモードへ切り替えとユーザーモードへ切り戻しができる、ENTER_DBGとLEAVE_DBGを追加しました。
 *	- デバッグ機能使用方法のサンプルを追記しました。
 *	* Wed Oct 03 11:39:51 JST 2007 Naoyuki Sawa
 *	- 『S1C33401 Technical Manual S1C33401-(Rev.0.6) No.2』(PRE_S1C33401_TM.pdf)「Appendix I/O Map 0x402E0-0x402F4 Debug Unit」を参考に、
 *	  デバッグユニットの制御レジスタのシンボル定義を追加しました。
 *	- 上述の資料は、S1C33401のC33 ADVコアの資料であり、基本的には、S1C33209のC33 STDコアの上位互換です。
 *	  従って、これらすべてのレジスタが、S1C33209でも同じ仕様とは限らないのですが、少なくとも、pDBG1_DBGV_WPとbDBG1_DBGVは有効のようです。
 *	* Wed Nov 18 21:37:53 JST 2015 Naoyuki Sawa
 *	- 'extern "C" {'～'}'で囲みました。.cppを含むWin32プロジェクトからもインクルード出来るようにするためです。
 */
#ifndef __CLIP_DBG_H__
#define __CLIP_DBG_H__

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

/*****************************************************************************
 *	デバッグユニットの制御レジスタ
 *****************************************************************************/

#define plc_DBG1 ((volatile struct c_DBG1tag*)0x402E0)

struct c_DBG1tag {
	volatile unsigned char rDBGVP;				/* 0x402E0 */
	volatile unsigned char Dummy0[3];
	union {							/* 0x402E4 */
		volatile struct {
			unsigned char DBGV : 1;
		} bCTL;
		volatile unsigned char ucCTL;
	} rDBGV;
	volatile unsigned char Dummy1[3];
	volatile unsigned char rDBGOUTP;			/* 0x402E8 */
	volatile unsigned char Dummy2[3];
	union {							/* 0x402EC */
		volatile struct {
			unsigned char DPCTOE : 1;
			unsigned char DBTOE  : 1;
		} bCTL;
		volatile unsigned char ucCTL;
	} rDBGOUT;
	volatile unsigned char Dummy3[3];
	volatile unsigned char rOCRSTP;				/* 0x402F0 */
	volatile unsigned char Dummy4[3];
	union {							/* 0x402F4 */
		volatile struct {
			unsigned char OCRST : 1;
		} bCTL;
		volatile unsigned char ucCTL;
	} rOCRST;
	volatile unsigned char Dummy5[3];
};

#define pDBG1_DBGV_WP		plc_DBG1->rDBGVP		/* 0x402E0 */
#define pDBG1_DBGV		plc_DBG1->rDBGV.ucCTL		/* 0x402E4 */
#define fDBG1_DBGV		plc_DBG1->rDBGV.bCTL
#define bDBG1_DBGV		fDBG1_DBGV.DBGV

#define pDBG1_DBGOUT_WP		plc_DBG1->rDBGOUTP		/* 0x402E8 */
#define pDBG1_DBGOUT		plc_DBG1->rDBGOUT.ucCTL		/* 0x402EC */
#define fDBG1_DBGOUT		plc_DBG1->rDBGOUT.bCTL
#define bDBG1_DBTOE		fDBG1_DBGOUT.DBTOE
#define bDBG1_DPCTOE		fDBG1_DBGOUT.DPCTOE

#define pDBG1_OCRST_WP		plc_DBG1->rOCRSTP		/* 0x402F0 */
#define pDBG1_OCRST		plc_DBG1->rOCRST.ucCTL		/* 0x402F4 */
#define fDBG1_OCRST		plc_DBG1->rOCRST.bCTL
#define bDBG1_OCRST		fDBG1_OCRST.OCRST

#define DBG1_DBGV_WP_VALUE			0xA9
#define DBG1_DBGV_0x0060000			0		/* 初期値 */
#define DBG1_DBGV_0x0000000			1

#define DBG1_DBGOUT_WP_VALUE			0x59
#define DBG1_DPCTOE_ENABLED			1		/* 初期値 */
#define DBG1_DPCTOE_DISABLED			0
#define DBG1_DBTOE_ENABLED			1
#define DBG1_DBTOE_DISABLED			0		/* 初期値 */

#define DBG1_OCRST_WP_VALUE			0x9A
#define DBG1_OCRST_MINI_MONITOR_START_REQUEST	1
#define DBG1_OCRST_INVALID			0		/* 初期値 */

/*****************************************************************************
 *	デバッグ機能を制御するレジスタ
 *****************************************************************************/

#define plc_DBG ((volatile struct c_DBGtag*)0x78000)

struct c_DBGtag {
	union {							/* 0x78000 */
		volatile struct {
			unsigned char DM    : 1;
			unsigned char SE    : 1;
			unsigned char IBE0  : 1;
			unsigned char IBE1  : 1;
			unsigned char DBE   : 1;
			unsigned char MRDBE : 1;
			unsigned char MWDBE : 1;
		} bDCR1;
		volatile unsigned char ucDCR1;
	} rDCR1;
	volatile unsigned char Dummy0;				/* 0x78001 */
	union {							/* 0x78002 */
		volatile struct {
			unsigned char DR   : 1;
			unsigned char SS   : 1;
			unsigned char IB0  : 1;
			unsigned char IB1  : 1;
			unsigned char DB   : 1;
			unsigned char MRDB : 1;
			unsigned char MWDB : 1;
			unsigned char BKF  : 1;
		} bDSR1;
		volatile unsigned char ucDSR1;
	} rDSR1;
	volatile unsigned char Dummy1;				/* 0x78003 */
	volatile unsigned int rIBAR0;				/* 0x78004 */
	volatile unsigned int rIBAR1;				/* 0x78008 */
	volatile unsigned int rDBAR;				/* 0x7800C */
	union {							/* 0x78010 */
		volatile struct {
			unsigned char IBE2 : 1;
		} bDCR2;
		volatile unsigned char ucDCR2;
	} rDCR2;
	volatile unsigned char Dummy2;				/* 0x78011 */
	union {							/* 0x78012 */
		volatile struct {
			unsigned char IB2 : 1;
		} bDSR2;
		volatile unsigned char ucDSR2;
	} rDSR2;
	volatile unsigned char Dummy3;				/* 0x78013 */
	volatile unsigned int rIBAR2;				/* 0x78014 */
};

#define pDBG_DCR1		plc_DBG->rDCR1.ucDCR1		/* 0x78000 */
#define fDBG_DCR1		plc_DBG->rDCR1.bDCR1
#define bDBG_DCR_DM		fDBG_DCR1.DM
#define bDBG_DCR_SE		fDBG_DCR1.SE
#define bDBG_DCR_IBE0		fDBG_DCR1.IBE0
#define bDBG_DCR_IBE1		fDBG_DCR1.IBE1
#define bDBG_DCR_DBE		fDBG_DCR1.DBE
#define bDBG_DCR_MRDBE		fDBG_DCR1.MRDBE
#define bDBG_DCR_MWDBE		fDBG_DCR1.MWDBE

#define pDBG_DSR1		plc_DBG->rDSR1.ucDSR1		/* 0x78002 */
#define fDBG_DSR1		plc_DBG->rDSR1.bDSR1
#define bDBG_DSR_DR		fDBG_DSR1.DR
#define bDBG_DSR_SS		fDBG_DSR1.SS
#define bDBG_DSR_IB0		fDBG_DSR1.IB0
#define bDBG_DSR_IB1		fDBG_DSR1.IB1
#define bDBG_DSR_DB		fDBG_DSR1.DB
#define bDBG_DSR_MRDB		fDBG_DSR1.MRDB
#define bDBG_DSR_MWDB		fDBG_DSR1.MWDB
#define bDBG_DSR_BKF		fDBG_DSR1.BKF

#define pDBG_IBAR0		plc_DBG->rIBAR0			/* 0x78004 */
#define pDBG_IBAR1		plc_DBG->rIBAR1			/* 0x78008 */
#define pDBG_DBAR		plc_DBG->rDBAR			/* 0x7800C */

#define pDBG_DCR2		plc_DBG->rDCR2.ucDCR2		/* 0x78010 */
#define fDBG_DCR2		plc_DBG->rDCR2.bDCR2
#define bDBG_DCR_IBE2		fDBG_DCR2.IBE2

#define pDBG_DSR2		plc_DBG->rDSR2.ucDSR2		/* 0x78012 */
#define fDBG_DSR2		plc_DBG->rDSR2.bDSR2
#define bDBG_DSR_IB2		fDBG_DSR2.IB2

#define pDBG_IBAR2		plc_DBG->rIBAR2			/* 0x78014 */

/*****************************************************************************
 *	
 *****************************************************************************/

/* * BRKを使用するときは、以下の点に注意してください。
 * - コンパイラはBRKを関数呼び出しと認識しないため、最適化によりBRKの前後の処理が保証されない場合があります。
 *   たとえば、以下のコードを-O2最適化でコンパイルすると、
 *	int var;
 *	void foo() {
 *		var = 1; // ①
 *		BRK;
 *		var = 2; // ②
 *	}
 *   ①と②が最適化され、①は不要と判断されて、その結果、以下のコードと等しいバイナリが生成されてしまいます。
 *	int var;
 *	void foo() {
 *		BRK;
 *		var = 2;
 *	}
 *   デバッグ処理ルーチンが「var = 1」であることを期待していた場合、予期できない結果となってしまいます。
 * - 上述の問題を避けるには、変数を「volatile」としてください。
 *	volatile int var;
 *	void foo() {
 *		var = 1;
 *		BRK;
 *		var = 2;
 *	}
 *   上のように変更すれば、最適化を行っても、期待どおりのバイナリが生成されます。
 * - ちなみに、上述の問題を避けるための別の方法として、brkを関数呼び出しにするという方法もありました。
 *	void Brk() { asm volatile ("brk"); }
 *	void foo() {
 *		var = 1;
 *		Brk();
 *		var = 2;
 *	}
 *   しかし、この方法では、brk時の%pcがfoo()の中でなく、常にBrk()の中の同じ位置になってしまいます。
 *   brk時の%pcも有用なデバッグ情報のひとつでなので、brkを関数呼び出しにする方法は採用しませんでした。
 */
#define BRK asm volatile ("brk")

typedef struct _DBGINFO {
	int pc;		/* + 0, 4 */
	//
	int psr;	/* + 4, 4 */
	int sp;		/* + 8, 4 */
	int alr;	/* +12, 4 */
	int ahr;	/* +16, 4 */
	//
	int r[16];	/* +20,64 */
} DBGINFO;		/* =84 */

/* ユーザーがデバッグモードを使用するよう、DBGユニットの設定を変更します。
 * [note]
 *	* デバッグモードを使用するアプリケーションは、最初に一度dbg_init()を呼び出してください。
 *	  //dbg_init()を呼び出さずにbrkを実行したりdbg_call()を呼び出すと、ハングアップします。
 *	  //↓2007/09/21:dbg_call()廃止に伴って、コメントを変更しました。
 *	  dbg_init()を呼び出さずにbrkを実行したりENTER_DBG/LEAVE_DBGを使うとハングアップします。
 *	* 二回以上dbg_init()を呼び出した場合、二回目以降のdbg_init()は何もせずに帰ります。
 */
void dbg_init();

/* ICEがデバッグモードを使用するよう、DBGユニットの設定を元に戻します。
 * [note]
 *	* dbg_init()を呼び出したアプリケーションは、終了する前に一度dbg_free()を呼び出してください。
 *	  dbg_free()を呼び出さずにアプリケーションを終了すると、ハングアップします。
 *	* 二回以上dbg_free()を呼び出した場合、二回目以降のdbg_free()は何もせずに帰ります。
 *	  また、dbg_init()を呼び出さずにdbg_free()を呼び出した場合も、何もせずに帰ります。
 */
void dbg_free();

///* 一時的にデバッグモードに切り替えて、関数を呼び出します。
// * [in]
// *	func		呼び出す関数。
// * [note]
// *	* 通常のユーザーモードでは、デバッグ機能を制御するレジスタへの書き込みができません。
// *	  デバッグ機能を制御するレジスタへ書き込むには、dbg_call()を経由してデバッグモードで関数を呼び出し、
// *	  その関数内でデバッグ機能を制御するレジスタへ書き込んでください。
// *	* デバッグモード内からdbg_call()を呼び出してはいけません。
// *	  デバッグモード内からdbg_call()を呼び出した場合の動作は、未定義です。
// *	* dbg_call()を経由して呼び出した関数内で、atdbg()を呼び出してはいけません。
// *	  dbg_call()がdbg_funcを退避・復元しているので、atdbg()の効果が無効化されます。
// */
//void dbg_call(void (*func)());
//→2007/09/21:dbg_call()を廃止しました。

/* デバッグモードへ切り替えます。
 * [note]
 *	- 既にデバッグモードの状態で、ENTER_DBGを実行しないでください。
 *	  動作が不安定となるおそれがあります。
 *	  ※実際には、既にデバッグモードの状態でENTER_DBGを実行しても、何も起こりません。
 *	    デバッグモードでも、brk命令は同じ挙動をとるようだからです。(実験より)
 *	    しかし、Undoc'dな挙動ですので、行わない方が安全です。
 *	- 上述のコメントと同じ理由により、ENTER_DBG/LEAVE_DBGを多重にネストしないでください。
 *	- ENTER_DBGを実行すると、内部で使用しているbrkの副作用で、bDBG_DSR_BKFが1になります。
 *	  ENTER_DBG自身でbDBG_DSR_BKFをクリアすることも可能でしたが、特に影響は無いと判断し、クリアしていません。
 *	  bDBG_DSR_BKFをクリアするためのコードは、既にdbg_enter()の実装の中にコメントアウト状態で用意してあります。
 *	  もし、ENTER_DBG自身でbDBG_DSR_BKFをクリアすることが必要になったら、コメントアウトを解除してください。
 */
void dbg_enter();
#define ENTER_DBG dbg_enter()

/* ユーザーモードへ切り戻します。
 * [note]
 *	- 既にユーザーモードの状態で、LEAVE_DBGを実行しないでください。
 *	  動作が不安定となるおそれがあります。
 *	  ※実際には、既にユーザーモードの状態でLEAVE_DBGを実行しても、何も起こりません。
 *	    ユーザーモードでも、retd命令は同じ挙動をとるようだからです。(実験より)
 *	    しかしこれは、Undoc'dな挙動ですので、行わない方が安全です。
 *	- 上述のコメントと同じ理由により、ENTER_DBG/LEAVE_DBGを多重にネストしないでください。
 */
void dbg_leave();
#define LEAVE_DBG dbg_leave()

/* ユーザー指定のデバッグ関数を設定します。
 * [in]
 *	func		デバッグ関数。(NULL = 解除)
 * [note]
 *	* デバッグ関数内では、DSRを参照してブレーク要因に応じた処理を行ったり、
 *	  必要に応じてDCRやIBAR、DBARなどを適切に設定してください。
 *	  また、dbg_infoのフィールドを書き換えることで、ユーザーモードに戻る時のレジスタ値を
 *	  任意に変更することもできます。
 *	  たとえば、dbg_info->pcを書き換えて、ブレーク発生点とは異なる関数から再開できます。
 *	* DSRのクリアはまとめて行っているので、デバッグ関数が行う必要は有りません。
 *	* //dbg_call()を経由して呼び出した関数内で、atdbg()を呼び出してはいけません。
 *	  //dbg_call()がdbg_funcを退避・復元しているので、atdbg()の効果が無効化されます。
 *	  //→2007/09/21:dbg_call()廃止を廃止したので、このコメントは不要となりました。
 */
void atdbg(void (*func)(DBGINFO* dbg_info));

//////////////////////////////////////////////////////////////////////////////
//	デバッグ機能使用方法のサンプル
//////////////////////////////////////////////////////////////////////////////
//
//	void app_init() {
//		・
//		・
//		・
//		// DBGユニットの使用を開始します。
//		dbg_init();
//		・
//		・
//		・
//	}
//	
//	void app_exit() {
//		・
//		・
//		・
//		// DBGユニットの使用を終了します。
//		dbg_free();
//		・
//		・
//		・
//	}
//	
//	// この関数を実行しようとすると、命令ブレークが発生します。
//	void dontExecMe() { DIE(); }
//	
//	// この変数に書き込んだ後、数命令遅れて(仕様)、データブレークが発生します。
//	unsigned char dontWriteMe;
//	
//	void alterExec(int cnt) {
//		pceFontPrintf("You exec me.(cnt=%d)\n", cnt);
//	}
//	
//	void myDbgIsr(DBGINFO* info) {
//		if(bDBG_DSR_IB0) {
//			// %pcを変更して、別の場所から処理を継続する方法のサンプルです。
//			static int cnt;
//			info->pc = (int)alterExec;
//			info->r[12] = ++cnt;
//			return;
//		}
//		if(bDBG_DSR_DB) {
//			// デバッグハンドラの中から、直接プログラムを終了する方法のサンプルです。
//			// - LEAVE_DBGを使って、明示的にユーザーモードへ切り戻すことに注意してください。
//			//   デバッグモードのまま終了しようとすると、ハングアップしてしまいます。
//			//   die()は内部でpceLCDTrans()を呼び出していますが、デバッグモードの間は
//			//   DMAが停止しているため(推測)、pceLCDTrans()内のDMA処理が完了しないからです。
//			int val = dontWriteMe;
//			LEAVE_DBG;
//			die("You touch me.(val=%d)", val);
//		}
//	}
//	
//	void
//	app_main()
//	{
//		pceFontSetPos(0, 0);
//	
//		// デバッグハンドラを設定します。
//		atdbg(myDbgIsr);
//	
//		// デバッグ機能を制御するレジスタへ書き込むために、一時的にデバッグモードへ切り替えます。
//	ENTER_DBG;
//		// 命令ブレークの設定方法のサンプルです。
//		bDBG_DCR_IBE0 = 1;
//		pDBG_IBAR0 = (int)&dontExecMe;
//		// 書き込みデータブレークの設定方法のサンプルです。
//		bDBG_DCR_DBE = 1;
//		bDBG_DCR_MWDBE = 1;
//		pDBG_DBAR = (int)&dontWriteMe;
//	LEAVE_DBG;
//	
//		for(;;) {
//			schedule();
//			if(joy & TRG_A) {
//				dontExecMe(); // 命令ブレークが発生します
//			}
//			if(joy & TRG_B) {
//				dontWriteMe = now; // データブレークが発生します
//			}
//		}
//	}
//
//////////////////////////////////////////////////////////////////////////////

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

#endif /*__CLIP_DBG_H__*/
