/*	
 *	clipdbg.c
 *
 *	デバッグモード
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2007 Naoyuki Sawa
 *
 *	* Sat Sep 08 22:23:37 JST 2007 Naoyuki Sawa
 *	- 1st リリース。
 *	* 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
 *	- デバッグユニットの制御レジスタのシンボル定義を追加したことに伴い、それらを利用するように書き換えました。
 */
#include "clip.h"

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

static int dbg_save[3]; /* [0x0],[0x8],[0xC]を退避 */

static void (*dbg_func)(DBGINFO* dbg_info);

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

static void dbg_isr_sub(DBGINFO* dbg_info) __attribute__((unused)); /*asmブロックから参照*/
static void
dbg_isr_sub(DBGINFO* dbg_info)
{
	// [dbg_info+ 0] = dummy <- [0x8](=%pc)
	// [dbg_info+ 4] = %psr
	// [dbg_info+ 8] = dummy <- [dbg_info+20](=%sp)
	// [dbg_info+12] = %alr
	// [dbg_info+16] = %ahr
	// [dbg_info+20] = %sp   <- [0xC](=%r0)
	// [dbg_info+24] = %r1
	// [dbg_info+28] = %r2
	// [dbg_info+32] = %r3
	// [dbg_info+36] = %r4
	// [dbg_info+40] = %r5
	// [dbg_info+44] = %r6
	// [dbg_info+48] = %r7
	// [dbg_info+52] = %r8
	// [dbg_info+56] = %r9
	// [dbg_info+60] = %r10
	// [dbg_info+64] = %r11
	// [dbg_info+68] = %r12
	// [dbg_info+72] = %r13
	// [dbg_info+76] = %r14
	// [dbg_info+80] = %r15
	dbg_info->sp = dbg_info->r[0];
	dbg_info->pc = *(volatile int*)0x8;
	dbg_info->r[0] = *(volatile int*)0xC;

	if(dbg_func) {
		dbg_func(dbg_info);
	}
	pDBG_DSR1 = 0x00;	/* デバッグ関数がDSRをクリアする手間を省くために、 */
	pDBG_DSR2 = 0x00;	/* ここでまとめてDSRをクリアすることにします。 */

	// [dbg_info+ 0] = %pc  -> [0x8](=%pc)
	// [dbg_info+ 4] = %psr
	// [dbg_info+ 8] = %sp  -> [dbg_info+20](=%sp)
	// [dbg_info+12] = %alr
	// [dbg_info+16] = %ahr
	// [dbg_info+20] = %r0  -> [0xC](=%r0)
	// [dbg_info+24] = %r1
	// [dbg_info+28] = %r2
	// [dbg_info+32] = %r3
	// [dbg_info+36] = %r4
	// [dbg_info+40] = %r5
	// [dbg_info+44] = %r6
	// [dbg_info+48] = %r7
	// [dbg_info+52] = %r8
	// [dbg_info+56] = %r9
	// [dbg_info+60] = %r10
	// [dbg_info+64] = %r11
	// [dbg_info+68] = %r12
	// [dbg_info+72] = %r13
	// [dbg_info+76] = %r14
	// [dbg_info+80] = %r15
	*(volatile int*)0xC = dbg_info->r[0];
	*(volatile int*)0x8 = dbg_info->pc;
	dbg_info->r[0] = dbg_info->sp;
}

void dbg_isr() __attribute__((noreturn));
asm("
	.code
	.align	1
dbg_isr:
	;// [0x8] = %pc
	;// [0xC] = %r0
	ld.w	%r0, %sp
	pushn	%r15
	;// [%sp+ 0] = %sp
	;// [%sp+ 4] = %r1
	;// [%sp+ 8] = %r2
	;// [%sp+12] = %r3
	;// [%sp+16] = %r4
	;// [%sp+20] = %r5
	;// [%sp+24] = %r6
	;// [%sp+28] = %r7
	;// [%sp+32] = %r8
	;// [%sp+36] = %r9
	;// [%sp+40] = %r10
	;// [%sp+44] = %r11
	;// [%sp+48] = %r12
	;// [%sp+52] = %r13
	;// [%sp+56] = %r14
	;// [%sp+60] = %r15
	ld.w	%r1, %psr
	ld.w	%r3, %alr
	ld.w	%r4, %ahr
	pushn	%r4
	;// [%sp+ 0] = dummy
	;// [%sp+ 4] = %psr
	;// [%sp+ 8] = dummy
	;// [%sp+12] = %alr
	;// [%sp+16] = %ahr
	;// [%sp+20] = %sp
	;// [%sp+24] = %r1
	;// [%sp+28] = %r2
	;// [%sp+32] = %r3
	;// [%sp+36] = %r4
	;// [%sp+40] = %r5
	;// [%sp+44] = %r6
	;// [%sp+48] = %r7
	;// [%sp+52] = %r8
	;// [%sp+56] = %r9
	;// [%sp+60] = %r10
	;// [%sp+64] = %r11
	;// [%sp+68] = %r12
	;// [%sp+72] = %r13
	;// [%sp+76] = %r14
	;// [%sp+80] = %r15
	ld.w	%r12, %sp
	xcall	dbg_isr_sub
	;
	;// [%sp+ 0] = dummy
	;// [%sp+ 4] = %psr
	;// [%sp+ 8] = dummy
	;// [%sp+12] = %alr
	;// [%sp+16] = %ahr
	;// [%sp+20] = %sp
	;// [%sp+24] = %r1
	;// [%sp+28] = %r2
	;// [%sp+32] = %r3
	;// [%sp+36] = %r4
	;// [%sp+40] = %r5
	;// [%sp+44] = %r6
	;// [%sp+48] = %r7
	;// [%sp+52] = %r8
	;// [%sp+56] = %r9
	;// [%sp+60] = %r10
	;// [%sp+64] = %r11
	;// [%sp+68] = %r12
	;// [%sp+72] = %r13
	;// [%sp+76] = %r14
	;// [%sp+80] = %r15
	popn	%r4
	ld.w	%ahr, %r4
	ld.w	%alr, %r3
	ld.w	%psr, %r1
	;// [%sp+ 0] = %sp
	;// [%sp+ 4] = %r1
	;// [%sp+ 8] = %r2
	;// [%sp+12] = %r3
	;// [%sp+16] = %r4
	;// [%sp+20] = %r5
	;// [%sp+24] = %r6
	;// [%sp+28] = %r7
	;// [%sp+32] = %r8
	;// [%sp+36] = %r9
	;// [%sp+40] = %r10
	;// [%sp+44] = %r11
	;// [%sp+48] = %r12
	;// [%sp+52] = %r13
	;// [%sp+56] = %r14
	;// [%sp+60] = %r15
	popn	%r15
	ld.w	%sp, %r0
	retd
	;// %pc = [0x8]
	;// %r0 = [0xC]
");

void
dbg_init()
{
	/* まず、確実に解除します。 */
	dbg_free();

	dbg_save[0] = *(volatile int*)0x0;	/* デバッグ例外処理ベクタ領域退避 */
	dbg_save[1] = *(volatile int*)0x8;	/* PCスタック領域退避 */
	dbg_save[2] = *(volatile int*)0xC;	/* R0レジスタスタック領域退避 */

	*(volatile int*)0x0 = (int)dbg_isr;	/* デバッグ例外処理ベクタ設定 */

/*{{2007/10/03:デバッグユニットの制御レジスタのシンボル定義に伴う変更*/
//	/*{{DBG制御レジスタ(隠し機能?)*/
//	*(volatile unsigned char*)0x402E0 = 0xA9;	/* 0x402E4の書込み保護を解除 */
//	*(volatile unsigned char*)0x402E4 = 1/*or3?*/;	/* ユーザーがデバッグモードを使用 (0x0〜0xFを使用) */
//	/*}}DBG制御レジスタ(隠し機能?)*/
//↓2007/10/03:デバッグユニットの制御レジスタのシンボル定義に伴う変更
	pDBG1_DBGV_WP = DBG1_DBGV_WP_VALUE;
	bDBG1_DBGV = DBG1_DBGV_0x0000000;
/*}}2007/10/03:デバッグユニットの制御レジスタのシンボル定義に伴う変更*/
}

/*{{2007/09/21:dbg_call()廃止に伴う変更*/
//static void
//dbg_free_sub()
//{
//	pDBG_DCR1 = 0x00;
//	//pDBG_DSR1 = 0x00;	/* dbg_isr_sub()でクリアされるから不要 */
//	pDBG_IBAR0 = (int)NULL;
//	pDBG_IBAR1 = (int)NULL;
//	pDBG_DBAR = (int)NULL;
//	pDBG_DCR2 = 0x0E;	/* DCR2[5:1]は--00111-固定です。(仕様) */
//	//pDBG_DSR2 = 0x00;	/* dbg_isr_sub()でクリアされるから不要 */
//	pDBG_IBAR2 = (int)NULL;
//}
/*}}2007/09/21:dbg_call()廃止に伴う変更*/

void
dbg_free()
{
	/* 既に解除されていたら、何もせずに帰ります。 */
/*{{2007/10/03:デバッグユニットの制御レジスタのシンボル定義に伴う変更*/
//	if(!*(volatile unsigned char*)0x402E4) {
//		return;
//	}
//↓2007/10/03:デバッグユニットの制御レジスタのシンボル定義に伴う変更
	if(bDBG1_DBGV == DBG1_DBGV_0x0060000) {
		return;
	}
/*}}2007/10/03:デバッグユニットの制御レジスタのシンボル定義に伴う変更*/

	/* ユーザー指定のデバッグ関数の設定を、確実に解除します。
	 * (次回にdbg_init()したとき、前回のデバッグ関数設定が残っていることを防ぐため)
	 */
	dbg_func = NULL;

	/* デパッグ機能を全てオフにします。 */
/*{{2007/09/21:dbg_call()廃止に伴う変更*/
//	dbg_call(dbg_free_sub);
//↓2007/09/21:dbg_call()廃止に伴う変更
ENTER_DBG;
	pDBG_DCR1 = 0x00;
	pDBG_DSR1 = 0x00;	/* 2007/09/21:dbg_call()廃止に伴い、dbg_free_sub()の場合と違ってdbg_isr_sub()を経由しなくなったので、クリア必要です */
	pDBG_IBAR0 = (int)NULL;
	pDBG_IBAR1 = (int)NULL;
	pDBG_DBAR = (int)NULL;
	pDBG_DCR2 = 0x0E;	/* DCR2[5:1]は--00111-固定です。(仕様) */
	pDBG_DSR2 = 0x00;	/* 2007/09/21:dbg_call()廃止に伴い、dbg_free_sub()の場合と違ってdbg_isr_sub()を経由しなくなったので、クリア必要です */
	pDBG_IBAR2 = (int)NULL;
LEAVE_DBG;
/*}}2007/09/21:dbg_call()廃止に伴う変更*/

/*{{2007/10/03:デバッグユニットの制御レジスタのシンボル定義に伴う変更*/
//	/*{{DBG制御レジスタ(隠し機能?)*/
//	*(volatile unsigned char*)0x402E0 = 0xA9;	/* 0x402E4の書込み保護を解除 */
//	*(volatile unsigned char*)0x402E4 = 0;		/* ICEがデバッグモードを使用 (0x60000〜0x6000Fを使用) */
//	/*}}DBG制御レジスタ(隠し機能?)*/
//↓2007/10/03:デバッグユニットの制御レジスタのシンボル定義に伴う変更
	pDBG1_DBGV_WP = DBG1_DBGV_WP_VALUE;
	bDBG1_DBGV = DBG1_DBGV_0x0060000;
/*}}2007/10/03:デバッグユニットの制御レジスタのシンボル定義に伴う変更*/

	*(volatile int*)0x0 = dbg_save[0];	/* デバッグ例外処理ベクタ領域復元 */
	*(volatile int*)0x8 = dbg_save[1];	/* PCスタック領域復元 */
	*(volatile int*)0xC = dbg_save[2];	/* R0レジスタスタック領域復元 */
}

//void dbg_call(void (*func)());
//asm("
//	.code
//	.align	1
//	.global	dbg_call
//dbg_call:
//	xld.w	%r10, dbg_func
//	xld.w	%r11, [%r10]		; dbg_funcを退避
//	xld.w	[%r10], %r12		; dbg_funcを一時的に変更
//	brk
//	xld.w	[%r10], %r11		; dbg_funcを復元
//	ret
//");
//→2007/09/21:dbg_call()を廃止しました。

void dbg_enter();
asm("
	.code
	.align	1
	.global	dbg_enter
dbg_enter:
	xld.w	%r4, [0x0]		; デバッグ例外処理ベクタを退避
	xld.w	%r5, dbg_enter_0x0	; デバッグ例外処理ベクタ = (brk命令の次)
	xld.w	[0x0], %r5
	brk				; デバッグモードに切り替えます
dbg_enter_0x0:
	;//xbclr [0x78002], 7		; bDBG_DSR_BKF = 0 → 必須ではありません
	xld.w	[0x0], %r4		; デバッグ例外処理ベクタを復元
	ret
");

void dbg_leave();
asm("
	.code
	.align	1
	.global	dbg_leave
dbg_leave:
	xld.w	[0xC], %r0		; R0レジスタスタック = %r0  (retdで復元)
	popn	%r0			; PCスタック = [%sp]+ (リターンアドレス)
	xld.w	[0x8], %r0
	retd				; ユーザーモードに切り替えます
");

void
atdbg(void (*func)(DBGINFO* dbg_info))
{
	dbg_func = func;
}
