/*
 *  TOPPERS/JSP Kernel
 *      Toyohashi Open Platform for Embedded Real-Time Systems/
 *      Just Standard Profile Kernel
 * 
 *  Copyright (C) 2000-2003 by Embedded and Real-Time Systems Laboratory
 *                              Toyohashi Univ. of Technology, JAPAN
 *
 *  TOPPERS/JSP for Blackfin
 *
 *  Copyright (C) 2004,2006,2006 by Takemasa Nakamura
 *  Copyright (C) 2004 by Ujinosuke
 *
 *  上記著作権者は，以下の (1)〜(4) の条件か，Free Software Foundation 
 *  によって公表されている GNU General Public License の Version 2 に記
 *  述されている条件を満たす場合に限り，本ソフトウェア（本ソフトウェア
 *  を改変したものを含む．以下同じ）を使用・複製・改変・再配布（以下，
 *  利用と呼ぶ）することを無償で許諾する．
 *  (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
 *      権表示，この利用条件および下記の無保証規定が，そのままの形でソー
 *      スコード中に含まれていること．
 *  (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
 *      用できる形で再配布する場合には，再配布に伴うドキュメント（利用
 *      者マニュアルなど）に，上記の著作権表示，この利用条件および下記
 *      の無保証規定を掲載すること．
 *  (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
 *      用できない形で再配布する場合には，次のいずれかの条件を満たすこ
 *      と．
 *    (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
 *        作権表示，この利用条件および下記の無保証規定を掲載すること．
 *    (b) 再配布の形態を，別に定める方法によって，TOPPERSプロジェクトに
 *        報告すること．
 *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
 *      害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
 * 
 *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
 *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，その適用可能性も
 *  含めて，いかなる保証も行わない．また，本ソフトウェアの利用により直
 *  接的または間接的に生じたいかなる損害に関しても，その責任を負わない．
 * 
 *  
 */


#define _MACRO_ONLY

/*
 *	カーネル用のスタートアップモジュール（BLACKfin用）
 */
 
#include "jsp_kernel.h"
 


			// 割込み、例外からの戻りをリクエストする例外引数
#define RETURNREQ 0xf

			// 32bit レジスタに即値をロードするマクロ
#ifdef __GNUC__
#define LOADLABEL( reg, value32 ) reg##.h = value32; reg##.l = value32;
#define LOADVALUE( reg, value32 ) reg##.h = ( value32 >> 16 ) &0xFFFF; reg##.l = value32 & 0xFFFF;
#elif defined(__ECC__)
#define LOADVALUE( reg, value32 ) reg##.h = hi(value32); reg##.l = lo(value32);
#define LOADLABEL LOADVALUE
#else
#error "Compiler is not supported"
#endif


#ifdef __GNUC__
#include "cdef_LPBlackfin.h"		/* gnu tool chain */
#elif defined(__ECC__)
#include <cdef_lpblackfin.h>	/* VisualDSP++ */
#else
#error "Compiler is not supported"
#endif

#include "saverestore.h"


#ifdef __GNUC__
.section .init;
.extern _boot_for_gdb;
.extern __bss_start, __bss_end;
#elif defined(__ECC__)
.section program;
#else
#error "Compiler is not supported"
#endif

.global start;
.extern _exc_vector;
.extern ldf_stack_end;
.extern _kernel_start;
.extern _reqflg;

#ifdef USE_RUNTIME_INIT
.extern _mi_initialize;
#endif

start:
	R0 = 0;
	LC0 = R0;
	LC1 = R0;
	L0 = R0;
	L1 = R0;
	L2 = R0;
	L3 = R0;
    LOADLABEL( p0, ldf_stack_end )
    sp = p0;
#ifdef __GNUC__                 // bss領域の初期化
    LOADLABEL( r0, __bss_start) // bss開始番地
    LOADLABEL( r1, __bss_end )
    r2 = r1 - r0;            // bssのサイズ
    p0 = r0;                // 開始アドレス
    p2 = r2;
    r0 = 0;
    loop bssfill lc0 = p2; 
loop_begin bssfill
        b[p0++] = r0;
loop_end bssfill;

    sp += -12;
    call _boot_for_gdb;     // gdbでロードしたときにリセットを確実にするためのコード
    sp += 12;
#elif defined(__ECC__)
#else
#error "Compiler is not supported"
#endif

#ifdef USE_RUNTIME_INIT			// board_config.h を参照
	sp += -12;
	call _mi_initialize;		// テーブル初期化
	sp += 12;
	cc = r0;					// 返り値をチェック
invalid : 
	if cc jump invalid; 		// 非0ならエラー
#endif
					// TOPPERS/JSP for BLACKfinは emu,rst,nmiを管理しない
	LOADVALUE( p0,EVT0+2*4)	// NMIベクトル
	p1 = 4;


	LOADLABEL( r0, nmiEntry )		// NMI
	[p0++p1] = r0;

	LOADLABEL( r0, expEntry)		// EXP
	[p0++p1] = r0;

	p0 = p0+p1;					// 予約領域をスキップ

	LOADLABEL( r0, ivHWEntry)		// ハードウェアエラー
	[p0++p1] = r0;

	LOADLABEL( r0, ivTMREntry)		// タイマー
	[p0++p1] = r0;

	LOADLABEL( r0, ivg7Entry)		// IVG7
	[p0++p1] = r0;

	LOADLABEL( r0, ivg8Entry)		// IVG8
	r0.H = ivg8Entry;
	[p0++p1] = r0;

	LOADLABEL( r0, ivg9Entry)		// IVG9
	[p0++p1] = r0;

	LOADLABEL( r0, ivg10Entry)		// IVG10
	[p0++p1] = r0;

	LOADLABEL( r0, ivg11Entry)		// IVG11
	[p0++p1] = r0;

	LOADLABEL( r0, ivg12Entry)		// IVG12
	[p0++p1] = r0;

	LOADLABEL( r0, ivg13Entry)		// IVG13
	[p0++p1] = r0;

	LOADLABEL( r0, ivg14Entry)		// IVG14
	[p0++p1] = r0;

	LOADLABEL( r0, task_level)		// IVG15はタスクに遷移するためのエントリー
	[p0++p1] = r0;
	
	LOADLABEL( p2, user)				// ダミーの戻り番地を設定
	reti = p2;
	csync;
	raise	15;					// IVG15を生起する。割り込みは遅延発生する。
	
	r0 = 0xC01F(z);				// IVG15を受付可能に(CPUロック状態)
	sti r0;
	csync;
	rti;						// ユーザーモードへ遷移する
	
task_level:                     // ここからタスクの実行順位
    r0 = syscfg;
    r1 = 0x4;                   // セルフ・ネスティング割込み
    r0 = r0 | r1;
    syscfg = r0;                // セルフ・ネストを有効に

    sp += -12;
#ifdef __GNUC__					/* GCC */
#elif defined(__ECC__)			/* VisualDSP++ */
#ifdef INIT_C_PLUS_PLUS
    r0 = 0;
    r1 = 0;
    call.x ___ctorloop;
#endif
#else
#error "Compiler is not supported"
#endif

    [--sp] = reti;				// 戻り番地を捨てて割り込み可能にする
    jump.x _kernel_start;			// kernel_stgart()からは戻ってこない
user:
	jump	user;
start.end:




#ifdef __GNUC__
.section .text;
#elif defined(__ECC__)
.section program;
#else
#error "Compiler is not supported"
#endif

.extern interrupt_dispatcher;
.extern task_context;

/*
*	例外処理のエントリ
*
*	割り込みとのネスト関係を調べ、ネストしていないならイベントスタックをセットする。
*		p0 : ユーザー定義の例外ハンドラのアドレス
*		p1 : IPENDのアドレス
*		p2 : reqflgのアドレス
*		r6 : タスクスタック
*		r7 : ASTATの退避情報
*
*/
expEntry:
	[--sp] = p0;	
	save_regs;					// ユーザーレジスタの退避

	LOADLABEL( p0, _exc_vector)		// ユーザー定義例外ハンドラの格納アドレス
	LOADVALUE( p1, IPEND )			// IPENDレジスタのアドレス

	l0 = r0;
	l1 = r0;
	l2 = r0;
	l3 = r0;
	lc0 = r0;					// 性能低下抑制のためにLCxをクリア
	lc1 = r0;

	p0 = [p0];					// p0 = exc_vector	
	r0 = [p1];					// IPENDの値を取得
	r1 = 0x7fef;				// 
	r0 = r0 & r1;				// IVG15とGID以外を調べる. r0.Hは必ず0
	r0.L = ones r0;				// 処理中のイベントの数を数える
	r0 += -1;					// イベントの数-1。ネストしていなければ0になる。
	cc = r0 == 0;				// ネストしてなければ真
	if !cc jump call_exception; // もしネストしていればハンドラを呼ぶ
								// ネストしていないイベントなら、スタックを切り替える
	r6 = sp;					// タスクスタックポインタを退避
	LOADLABEL( r0, ldf_stack_end)	// イベントスタックポインタを設定
	sp = r0;
	
call_exception:
	r7 = astat;					// ccにはネスト情報が入っている。それを退避
	r0 = p1;					// 第一引数はIPENDのアドレス
	sp += -12;					// ダミー引数領域確保 (E)
	call	(p0);				// C言語で書かれた例外ハンドラを呼ぶ
	sp += 12;					// ダミー引数領域開放 (E)
	astat = r7;					// ccを復帰
	if !cc jump get_back_x;		// もしネストしているならば、このまま帰る
	
								// ここではイベントはネストしていない
	sp = r6;					// スタックをタスクスタックに設定

	LOADLABEL( p2, _reqflg )
	r0 = [p2];					// reqflgの値を取得
	cc = r0;					// ディスパッチかタスク例外の要求は出ているか
	if !cc jump get_back_x;		// 出ていないならば割り込まれたタスクに戻る

								// コンテキスト切り替え作業開始
	r0 = 0;						// 
	[p2] = r0;					// reqflgをクリアする.
	r0 = retx;					// タスクの戻り番地を取り出す
	r1 = 1;
	r0 = r1 | r0; 				// セルフ・ネストであると偽装する
	[--sp] = r0;				// 戻り番地をスタックにつむ
	LOADLABEL( p0, task_context)
	
	cli r0;						// 現在のCPUロック状態を取得
	[--sp] = r0;				// ロック状態を退避
	r1 = 0xC01F(z);				// タスクコンテキストははCPUロック状態で実行する
	
#ifdef UNMANAGED_INT
    r2 = UNMANAGED_INT(z);
    r0 = r0 & r2;				// 管理外割り込みのマスク状態を抽出
    r1 = r0 | r1;				// タスクコンテキストはCPUロック状態で実行する
#endif
	sti r1;						// CPUロック (F)
	
	retx = p0;					// ラベル"taskiv_context"を例外からの戻り番地にする
	rtx;						// 例外から戻る。コンテキストはタスクになる
	
get_back_x:	
	restore_regs;				// 退避したレジスタを全て戻す
	p0=[sp++];
	rtx;
expEntry.end:

// イベントハンドラのエントリーコード群。
// EVTのエントリには対応する以下のコードのラベルが格納される。
// それぞれのコードはイベント中にをp0に格納した後、
// interrupt_dispatcherにジャンプする
// evtvectorはユーザーハンドラへのポインタの配列




ivHWEntry:
	[--sp] = p0;
	p0 = 5;
	jump.x interrupt_dispatcher;
ivHWEntry.end:

ivTMREntry:
	[--sp] = p0;
	p0 = 6;
	jump.x interrupt_dispatcher;
ivTMREntry.end:

ivg7Entry:
	[--sp] = p0;
	p0 = 7;
	jump.x interrupt_dispatcher;
ivg7Entry.end:

ivg8Entry:
	[--sp] = p0;
	p0 = 8;
	jump.x interrupt_dispatcher;
ivg8Entry.end:

ivg9Entry:
	[--sp] = p0;
	p0 = 9;
	jump.x interrupt_dispatcher;
ivg9Entry.end:

ivg10Entry:
	[--sp] = p0;
	p0 = 10;
	jump.x interrupt_dispatcher;
ivg10Entry.end:

ivg11Entry:
	[--sp] = p0;
	p0 = 11;
	jump.x interrupt_dispatcher;
ivg11Entry.end:

ivg12Entry:
	[--sp] = p0;
	p0 = 12;
	jump.x interrupt_dispatcher;
ivg12Entry.end:

ivg13Entry:
	[--sp] = p0;
	p0 = 13;
	jump.x interrupt_dispatcher;
ivg13Entry.end:

#ifdef __GNUC__
.type ivg14Entry, STT_FUNC;
#elif defined(__ECC__)
#else
#error "Compiler is not supported"
#endif


ivg14Entry:					// dispatch()の割り込み待ち部
#if !defined(USE_TIC_CORE) && !defined(USE_HW_ERROR)
	csync;						// コアタイマーでティックを刻むときにはidle命令を使えない。
	idle;						// イベント待ち
	csync;
#endif
	[--sp] = reti;				// 割込みネスト許可
	r1 = 0xffff(z);				// CPU アンロック用パターン
#ifdef UNMANAGED_INT
    cli r0;               // 現在のマスクを取り出す
	r2 = UNMANAGED_INT(z);
	r0 = r0 & r2;				// 管理外割り込みのみ取り出す
	r2 = ~r2;					// 逆マスク
	r1 = r1 & r2;				// 
	r1 = r1 | r0;				// 管理外割り込みを考慮したマスク
#endif
	sti r1;						// CPU アンロック
	r1 = 0xC01F(z);				// CPU ロック用パターン
    cli r0;               // 現在のマスクを取り出す
                                // 管理外割り込みを使わない場合も、保護のため必要
#ifdef UNMANAGED_INT
	r2 = UNMANAGED_INT(z);
	r0 = r0 & r2;				// 管理外割り込みのみ取り出す
	r1 = r1 | r0;				// 管理外割り込みを考慮したマスク
#endif
	sti r1;
	reti=[sp++];				// 割込みネスト禁止
	rti;
ivg14Entry.end:

#ifdef __GNUC__
.size	ivg14Entry, .-ivg14Entry
#elif defined(__ECC__)
#else
#error "Compiler is not supported"
#endif


nmiEntry:
	jump	nmiEntry;
	rtn;
nmiEntry.end:	




#ifdef __GNUC__
#elif defined(__ECC__)

#ifdef INIT_C_PLUS_PLUS
.section ctor;
	.align 4;
___ctor_table:
	.byte4=0;
.global ___ctor_table;
.type ___ctor_table,STT_OBJECT;
.extern ___ctorloop;
.section .gdt;
        .align 4;
___eh_gdt:
.global ___eh_gdt;
        .byte4=0;
.type ___eh_gdt,STT_OBJECT;
.section .frt;
        .align 4;
___eh_frt:
.global ___eh_frt;
        .byte4=0;
.type ___eh_frt,STT_OBJECT;
#endif  /* INIT_C_PLUS_PLUS */

#else
#error "Compiler is not supported"
#endif

