//; 
//;   TOPPERS/SSP Kernel
//;       Smallest Set Profile Kernel
//;  
//;   Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
//;                               Toyohashi Univ. of Technology, JAPAN
//;   Copyright (C) 2007      by Embedded and Real-Time Systems Laboratory
//;               Graduate School of Information Science, Nagoya Univ., JAPAN
//;  
//;   Copyright (C) 2010 by Witz Corporation, JAPAN
//;   上記著作権者は，以下の(1)～(4)の条件を満たす場合に限り，本ソフトウェ
//;   ア（本ソフトウェアを改変したものを含む．以下同じ）を使用・複製・改
//;   変・再配布（以下，利用と呼ぶ）することを無償で許諾する．
//;   (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
//;       権表示，この利用条件および下記の無保証規定が，そのままの形でソー
//;       スコード中に含まれていること．
//;   (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
//;       用できる形で再配布する場合には，再配布に伴うドキュメント（利用
//;       者マニュアルなど）に，上記の著作権表示，この利用条件および下記
//;       の無保証規定を掲載すること．
//;   (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
//;       用できない形で再配布する場合には，次のいずれかの条件を満たすこ
//;       と．
//;     (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
//;         作権表示，この利用条件および下記の無保証規定を掲載すること．
//;     (b) 再配布の形態を，別に定める方法によって，TOPPERSプロジェクトに
//;         報告すること．
//;   (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
//;       害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
//;       また，本ソフトウェアのユーザまたはエンドユーザからのいかなる理
//;       由に基づく請求からも，上記著作権者およびTOPPERSプロジェクトを
//;       免責すること．
//;  
//;   本ソフトウェアは，無保証で提供されているものである．上記著作権者お
//;   よびTOPPERSプロジェクトは，本ソフトウェアに関して，特定の使用目的
//;   に対する適合性も含めて，いかなる保証も行わない．また，本ソフトウェ
//;   アの利用により直接的または間接的に生じたいかなる損害に関しても，そ
//;   の責任を負わない．
//;  
//;

/*-----------------------------------------------------------------------------
 * 髙橋メモ　覚書
 *	SSPはスタックは一本である。　sta_kerで呼ばれた時のスタックから変更されない。
 *  SSPは、カーネル動作状態および、タスク動作状態いずれもCPUモードは
 *  スーパーバイザーモードで動作する。
 *  システムモードは利用しない。
 *  また、IRQ FIQのスタックポインタ(バンク)は初期化していないので利用してはならない。
 *  割り込み処理の最初に、スーパーバイザーモードに切り替える。
 *
 *
 *  スタックは通常、
 *
 *  -------------------------------------------------
 *  実行中のタスクのスタック
 *　最下層　カーネルのディスパッチ　までのスタック（call で積まれているのみ
 *  -------------------------------------------------
 *  の状態であるが、act_tsk()などで、さらに上位のタスクが呼ばれたいる場合には　
 *  -------------------------------------------------
 *  実行中のタスクのスタック
 *  act_tsk等のカーネルのスタック
 *  中断中のタスクのスタック
 *　最下層　カーネルのディスパッチ　までのスタック（call で積まれているのみ
 *  -------------------------------------------------
 *  という積み方になり、割り込みから、iact_tskした場合には
 *  -------------------------------------------------
 *  実行中のタスクのスタック
 *  iact_tsk等のカーネルのスタック
 *  以下のような、中断タスクへレジスタ保存
	;           例外フレーム(ARMv6-7)            offset
	;      ------------------------------
	;     |            R0-R12            |  0　
	;      ------------------------------
	;     |          LR_svc              |  
	;      ------------------------------
	;     |     例外前のPC(戻り先)       |  
	;      ------------------------------
	;     |        例外前のCPSR          |  
	;      ------------------------------
 *  
 *  中断中のタスクのスタック
 *　最下層　カーネルのディスパッチ　までのスタック（call で積まれているのみ
 *  -------------------------------------------------
 *  という積み方になる。また多重割り込みは、
 * 
	;           例外フレーム(ARMv6-7)            offset
	;      ------------------------------
	;     |            R0-R12            |  0　
	;      ------------------------------
	;     |          LR_svc              |  
	;      ------------------------------
	;     |     例外前のPC(戻り先)       |  
	;      ------------------------------
	;     |        例外前のCPSR          |  
	;      ------------------------------
 *  ハンドラルーチンのスタック
	;           例外フレーム(ARMv6-7)            offset
	;      ------------------------------
	;     |            R0-R12            |  0　
	;      ------------------------------
	;     |          LR_svc              |  
	;      ------------------------------
	;     |     例外前のPC(戻り先)       |  
	;      ------------------------------
	;     |        例外前のCPSR          |  
	;      ------------------------------
 *  
 *  中断中のタスクのスタック
 *　最下層　カーネルのディスパッチ　までのスタック（call で積まれているのみ
 *  -------------------------------------------------
 *　という積まれかたになる
 *  髙橋　覚書　ここまで
 */

/*
 *        コア依存モジュール アセンブリ言語部（ARM用）
 */

#define TOPPERS_MACRO_ONLY
#define TOPPERS_ASM_MACRO
#define UINT_C(val)     (val)        /* uint_t型の定数を作るマクロ */
#define ULONG_C(val)    (val)        /* ulong_t型の定数を作るマクロ */

#include "target_asm.inc"

//
//;   public宣言
//;
	AGLOBAL(__kernel_default_int_handler_entry)

//;
//;	external 宣言
//;
	AGLOBAL(_kernel_search_schedtsk)
	AGLOBAL(_kernel_run_task)

	AGLOBAL(_kernel_intnest)
	AGLOBAL(_kernel_reqflg)

	AGLOBAL(IRQ_handler)

	ATEXT
	AALIGN(2)


//;----------------------------------------------------------------------
//;	割り込みベクタ登録から直接くるところ
//;   ここではユーザー割り込みルーチン　_CMI0 を呼び出す
//;----------------------------------------------------------------------
ALABEL(__kernel_default_int_handler_entry)

/*
 * 割込みハンドラ
 *   r1 割り込み番号
 */
ALABEL(ssp_irq_handler)
	/* 
	 * IRQモードで実行される
　　　　 * スタックはスーパーバイザーモードにコンテキスト
	 * を保存
	 */
	sub   lr, lr, #4 			/* 戻り先アドレス  */
	srsdb #CPSR_SVC! 			/*lr(戻り先) spsr(cpsr_svc)を	*/
						/* スーパーバイザーモードのスタックへ保存	*/

						/*
						 *  割込み前のモード(スーパーバイザーモード)へ
						 *  移行し，コンテキストを保存する
						 */
	msr   cpsr_cxsf, #(CPSR_SVC AOR CPSR_CPULOCK AOR CPSR_ALWAYS_SET)
//;	stmfd sp!, {r0-r3,ip,lr}
	stmfd sp!, {r0-r12,lr}				/* 全部保存する								*/
//	;----------------------------------------------------------
//	;ここまでで、スーパーバイザースタックに以下のように積まれる
//	;
//	;           例外フレーム(ARMv6-7)            offset
//	;      ------------------------------
//	;     |            R0-R12            |  0　
//	;      ------------------------------
//	;     |          LR_svc              |  
//	;      ------------------------------
//	;     |     例外前のPC(戻り先)       |  
//	;      ------------------------------
//	;     |        例外前のCPSR          |  
//	;      ------------------------------
//	;-------------------------------------------------------------
								/*
								 *  多重割込みか判定
								 */
	ldr   r2, =_kernel_intnest /* 例外・割込みネスト回数を取得 */
	ldr   r3, [r2]
	add   r0,r3,#1              /* 例外・割込みネスト回数を更新 */
	str   r0, [r2]

ALABEL(irq_handler_1)
								/* 
								 * 割込みハンドラの呼び出し
								 */
	bl	IRQ_handler
								/*
								 * 後の処理はARM依存部で実行
								 */
/*
 *  割込みハンドラ/CPU例外ハンドラ出口処理
 *
 *  ret_intは，割込みハンドラから戻った直後に実行するルーチンで，
 *  割込みハンドラ終了後，ターゲット依存の処理を実行した後，
 *  カーネル管理の割込みを禁止，スタックを割込み前のスタックにした
 *  状態で呼び出される．
 *  
 *  プロセッサは，スーパーバイザーモード・カーネル管理の割込みを禁止
 *  した状態となっていることが前提。．
 */
	AGLOBAL(ret_int)
ALABEL(ret_int)
//	;----------------------------------------------------------
//	;ここまでで、スーパーバイザースタックに以下のように積まれる
//	;           例外フレーム(ARMv6-7)            offset
//	;      ------------------------------
//	;     |            R0-R12            |  0　
//	;      ------------------------------
//	;     |          LR_svc              |  
//	;      ------------------------------
//	;     |     例外前のPC(戻り先)       |  
//	;      ------------------------------
//	;     |        例外前のCPSR          |  
//	;      ------------------------------
//	;-------------------------------------------------------------
	/*
	 *  例外・割込みのネストカウント（__kernel_intnest)のデクリメント
	 */
	ldr   r0, =_kernel_intnest   /* r0 <-__kernel_intnest */
	ldr   r1, [r0]
	sub   r2, r1, #1
	str   r2, [r0]
	cmp   r2, #0                  /* 戻り先が非タスクコンテキストなら */
	bne   ret_int_1               /* すぐにリターン */

	/*
	 *  __kernel_reqflgをチェックする前に割込みを禁止するのは，__kernel_reqflgをチェック
	 *  した直後に割込みハンドラが起動され，その中でディスパッチが要求
	 *  された場合に，すぐにディスパッチされないという問題が生じるため
	 *  である．
	 */
	ldr   r0, =_kernel_reqflg
	ldr   r1, [r0]
	cmp   r1, #0                  /* __kernel_reqflgがtrueであればret_int_2へ */
	beq   ret_int_1

ALABEL(ret_int_2)
ALABEL(ret_int_3)
	/*
	 *  ここへは，CPU例外ハンドラの出口処理からも分岐してくる．
	 *
	 *  ここでは，戻り先がタスクであり，スタックは，タスクスタックの上
	 *  にスクラッチレジスタのみが保存された状態になっている．また，
	 *  プロセッサは，スーパーバイザーモード・カーネル管理の割込みを禁止
	 *  した状態となっている．
	 */
	ldr   r0, =_kernel_reqflg   /* __kernel_reqをfalseに */
	mov   r1, #0
	str   r1, [r0]

	bl		_kernel_search_schedtsk	//; タスクを実行
	bl		_kernel_run_task	//; search_schedtskの返り値(R1)がそのまま
						// run_tskの引数になる

ALABEL(ret_int_1)
ALABEL(ret_int_5)
	/*
	 *  割込み処理からのリターンにより，CPUロック解除状態に移行するよ
	 *  うにする．ARMはCPSRのIRQビットによってCPUロック状態を表してい
	 *  るため，そのままリターンすればよい．
	 */
//;	ldmfd sp!, {r0-r3,ip,lr}
	ldmfd sp!, {r0-r12,lr}			//; 全部戻す
	rfeia sp!

