; ; TOPPERS/ASP Kernel ; Toyohashi Open Platform for Embedded Real-Time Systems/ ; Advanced Standard 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 ; Copyright (C) 2013 by Mitsuhiro Matsuura ; ; 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ ; ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改 ; 変・再配布(以下,利用と呼ぶ)することを無償で許諾する. ; (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 ; 権表示,この利用条件および下記の無保証規定が,そのままの形でソー ; スコード中に含まれていること. ; (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 ; 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 ; 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 ; の無保証規定を掲載すること. ; (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 ; 用できない形で再配布する場合には,次のいずれかの条件を満たすこ ; と. ; (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 ; 作権表示,この利用条件および下記の無保証規定を掲載すること. ; (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに ; 報告すること. ; (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 ; 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. ; また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理 ; 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを ; 免責すること. ; ; 本ソフトウェアは,無保証で提供されているものである.上記著作権者お ; よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的 ; に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ ; アの利用により直接的または間接的に生じたいかなる損害に関しても,そ ; の責任を負わない. ; ; @(#) $Id: prc_support.src 536 2014-10-09 23:11:40Z coas-nagasima $ ; ; ; プロセッサ依存モジュール アセンブリ言語部(RX630用) ; ; ; ディスパッチャおよび割込み(CPU例外)出入り口のルール: ; 動作モードを以下のように定義する. ; ディスパッチャモード: ; CPUロック状態, 割込み優先度マスク全解除状態, ; タスクコンテキスト(intnest = 0), タスクスタック ; 割込み(CPU例外)処理モード ; 全割込みロック状態(PSWレジスタIビット = 0), ; 割込み優先度マスク全解除でない状態(IPL != 0) ; 割込みコンテキスト(intnest != 0), 割込みスタック ; ; カーネル管理外割込みのサポート有無と, CPUロック状態, 割込み優先度 ; マスク全解除状態の関係は以下の通りである. ; カーネル管理外割込み未サポート時: ; CPUロック状態(PSWレジスタIビット = 0) ; 割込み優先度マスク全解除状態(IPL = 0) ; カーネル管理外割込みサポート時: ; CPUロック状態 ; (PSWレジスタIビット = 0, IPL = IPL_LOCK, lock_flag = true) ; 割込み優先度マスク全解除状態(saved_ipl = 0) ; ; 各構造体ポインタを以下のように各レジスタにアサインする. ; r15 = p_runtsk ただしディスパッチャの各出口では無効 ; r14 = *p_runtsk dispatcher の中では p_runtsk 確定時に再取得する ; 各入り口から最初に変数アクセスするときに上記レジスタに保存する. ; ; 構造体アライメントへの対応 ; 構造体アライメントが4Byte(アンパック)の場合: ; 一般的なレジスタ相対アドレッシングが可能 ; 例: mov.l #__kernel_p_runtsk, r15 ; mov.l r0, TCB_sp[r15] ; 構造体アライメントが4Byteではない(パック)の場合: ; mov.lのようにロングサイズ指定の場合、相対値は4の倍数のみ有効 ; このため, 一度対象アドレスを求めてからアクセスする必要がある ; 例: mov.l #__kernel_p_runtsk, r15 ; add #TCB_sp, r15, r5 ; mov.l r0, [r5] ; 各オフセット値を判断し, 条件アセンブルによりコードを切り替える ; ; ; 構造体アクセスのオフセット定義 ; .include offset.inc ; ; 各種EQU定義(Hファイルの#define定義) ; .include asm_config.inc .glb __kernel_istkpt .glb __kernel_p_runtsk .glb __kernel_p_schedtsk .glb __kernel_reqflg .glb __kernel_dspflg .glb __kernel_dispatch .glb __exit_and_dispatch .glb __kernel_start_r .glb __kernel_call_texrtn .glb _kernel_interrupt .glb _kernel_exception .glb __kernel_intnest .glb __kernel_call_exit_kernel .glb __kernel_start_dispatch .glb _ext_tsk .glb __kernel_exit_kernel .if TIPM_LOCK != -15 .glb __kernel_lock_flag .glb __kernel_saved_ipl .endif .glb __kernel_break_wait .glb _sil_dly_nse .if LOG_INH_ENTER_ENABLE == 1 .glb _kernel_log_inh_enter .endif ; LOG_INH_ENTER_ENABLE == 1 .if LOG_INH_LEAVE_ENABLE == 1 .glb _kernel_log_inh_leave .endif ; LOG_INH_LEAVE_ENABLE == 1 .if LOG_EXC_ENTER_ENABLE == 1 .glb _kernel_log_exc_enter .endif ; LOG_EXC_ENTER_ENABLE == 1 .if LOG_EXC_LEAVE_ENABLE == 1 .glb _kernel_log_exc_leave .endif ; LOG_EXC_LEAVE_ENABLE == 1 .if LOG_DSP_ENTER_ENABLE == 1 .glb _kernel_log_dsp_enter .endif ; LOG_DSP_ENTER_ENABLE == 1 .if LOG_DSP_LEAVE_ENABLE == 1 .glb _kernel_log_dsp_leave .endif ; LOG_DSP_LEAVE_ENABLE == 1 ; ; TCB_sp への書込みマクロ ; st_TCB_sp .macro src, tcb, tmp .if (TCB_sp % 4) == 0 mov.l src, TCB_sp[tcb] .else add #TCB_sp, tcb, tmp mov.l src, [tmp] .endif .endm ; ; TCB_sp からの読出しマクロ ; ld_TCB_sp .macro dst, tcb, tmp .if (TCB_sp % 4) == 0 mov.l TCB_sp[tcb], dst .else add #TCB_sp, tcb, tmp mov.l [tmp], dst .endif .endm ; ; TCB_pc への書込みマクロ ; st_TCB_pc .macro src, tcb, tmp .if (TCB_pc % 4) == 0 mov.l src, TCB_pc[tcb] .else add #TCB_pc, tcb, tmp mov.l src, [tmp] .endif .endm ; ; TCB_pc からの読出しマクロ ; ld_TCB_pc .macro dst, tcb, tmp .if (TCB_pc % 4) == 0 mov.l TCB_pc[tcb], dst .else add #TCB_pc, tcb, tmp mov.l [tmp], dst .endif .endm ; ; TCB_texptn からの読出しマクロ ; ld_TCB_texptn .macro dst, tcb, tmp .if (TCB_texptn % 4) == 0 mov.l TCB_texptn[tcb], dst .else add #TCB_texptn, tcb, tmp mov.l [tmp], dst .endif .endm ; ; TCB_p_tinib からの読出しマクロ ; ld_TCB_p_tinib .macro dst, tcb, tmp .if (TCB_p_tinib % 4) == 0 mov.l TCB_p_tinib[tcb], dst .else add #TCB_p_tinib, tcb, tmp mov.l [tmp], dst .endif .endm ; ; TINIB_exinf からの読出しマクロ ; ld_TINIB_exinf .macro dst, tinib, tmp .if (TINIB_exinf % 4) == 0 mov.l TINIB_exinf[tinib], dst .else add #TINIB_exinf, tinib, tmp mov.l [tmp], dst .endif .endm ; ; TINIB_task からの読出しマクロ ; ld_TINIB_task .macro dst, tinib, tmp .if (TINIB_task % 4) == 0 mov.l TINIB_task[tinib], dst .else add #TINIB_task, tinib, tmp mov.l [tmp], dst .endif .endm .section P, CODE ; ; APIからのタスクディスパッチャ入口 ; ; 呼び出し条件: ; ・ディスパッチャモード(ファイルヘッダ参照) ; ; ここでは, コンテキストの退避と, 実行再開番地の設定をする. ; __kernel_dispatch: pushm r6-r13 ; 非スクラッチレジスタ保存 mov.l #__kernel_p_runtsk, r15 mov.l [r15], r14 st_TCB_sp r0, r14, r5 ; スタックポインタをTCBに保存 st_TCB_pc #dispatch_r, r14, r5 ; 実行再開番地をTCBに保存 bra dispatcher ; ; APIへのタスクディスパッチャ出口 ; ; 呼び出し条件: ; ・ディスパッチャモード(ファイルヘッダ参照) ; ; ここでは, タスク例外ハンドラ呼出しと, コンテキストの復帰をする. ; dispatch_r: btst #TCB_enatex_bit, TCB_enatex[r14] ; タスク例外処理許可? bz dispatch_r_rts ld_TCB_texptn r5, r14, r4 ; 保留例外要因があるか? cmp #0, r5 bz dispatch_r_rts bsr __kernel_call_texrtn ; タスク例外ハンドラ呼出し処理実行 dispatch_r_rts: popm r6-r13 ; 非スクラッチレジスタ復帰 rts ; dispatch 呼び出し元へ戻る. ; ; タスク起動処理(タスク先頭へのタスクディスパッチャ出口) ; ; 呼び出し条件: ; ・ディスパッチャモード(ファイルヘッダ参照) ; ; ここでは, CPUロック解除状態にし, タスクを起動する. ; __kernel_start_r: mov.l #_ext_tsk, r5 push.l r5 ; 戻り番地をスタックに積む ld_TCB_p_tinib r5, r14, r4 ld_TINIB_exinf r1, r5, r4 ; 拡張情報を第一引数に設定 ld_TINIB_task r5, r5, r4 ; タスクの起動番地を取得 .if TIPM_LOCK == -15 setpsw i ; 割込み許可(CPUロック解除状態) .else mov.l #__kernel_lock_flag, r4 ; CPUロック解除状態へ mov.l #0, [r4] ; ここに来るときは必ず saved_ipl の mvtc #00010000H, psw ; 値は 0 のため, 直値を設定する. ; 全割込みロック解除状態( I = 1 ) ; 割込み優先度マスク全解除状態( IPL = 0 ) .endif jmp r5 ; ; カーネル起動からのタスクディスパッチャ入口 ; ; このルーチンは,カーネル起動時に,すべての割込みを禁止した状態 ; (割込みロック状態と同等)で呼び出される.また,割込みモード(非 ; タスクコンテキストと同等)で呼び出されることを想定している. ; ; 呼び出し条件: ; ・割込み(CPU例外)処理モード(ファイルヘッダ参照) ; ; ここでは, ディスパッチャモードに変更する. ; __kernel_start_dispatch: mov.l #__kernel_intnest, r5 mov.w #0, [r5] ; タスクコンテキストに切換え .if TIPM_LOCK != -15 mvtc #(IPL_LOCK | 00010000H), psw ; 全割込みロック解除状態 ; 割込み優先度マスク全解除でない状態 .endif ; ; タスク終了(現在のコンテキストを捨てる)からのタスクディスパッチャ入口 ; ; 呼び出し条件: ; ・ディスパッチャモード(ファイルヘッダ参照) ; ; ここでは, 何もすることはない. ; なお, p_runtsk のアドレス取得だけは行なう. ; __exit_and_dispatch: mov.l #__kernel_p_runtsk, r15 ; ; ディスパッチャ本体 ; ; 呼び出し条件: ; ・すべてのタスクのコンテキストは保存されている. ; ; dispatcher 呼出時のスタック: ; ・__kernel_dispatch からきた場合 : タスクスタック ; ・exit_and_dispatch からきた場合: ; exit_task からきた場合 : タスクスタック ; カーネル起動時(__kernel_start_dispatch) : 割込みスタック ; ・ret_int からきた場合 : タスクスタック ; ・dispatcher_idle_loop からきた場合 : 割込みスタック ; dispatcher: .if LOG_DSP_ENTER == 1 push.l r15 mov.l r14, r1 ; 引数(ディスパッチ元TCB)を設定 bsr _kernel_log_dsp_enter pop.l r15 .endif mov.l #__kernel_p_schedtsk, r5 mov.l [r5], [r15] ; p_schedtsk を p_runtsk に mov.l [r15], r14 cmp #0, r14 bz dispatcher_pre_idle ; schedtsk がなければアイドルループへ ld_TCB_sp r0, r14, r5 ; タスクスタックポインタを復帰 .if LOG_DSP_LEAVE == 1 push.l r14 mov.l r14, r1 ; 引数(ディスパッチ先TCB)を設定 bsr _kernel_log_dsp_leave pop.l r14 .endif ld_TCB_pc r5, r14, r4 jmp r5 ; 実行再開番地へジャンプ ; ; schdedtskがNULLの場合はアイドルループに入る ; アイドルループは割込み処理モードで動作させる ; ; ここで割込みモードに切り換えるのは,ここで発生する割込み処理に ; どのスタックを使うかという問題の解決と,割込みハンドラ内でのタ ; スクディスパッチの防止という2つの意味がある. ; dispatcher_pre_idle: mov.l #__kernel_istkpt,r5 mov.l [r5], r0 ; 割込み用のスタックへ切替え mov.l #__kernel_intnest, r5 mov.w #1, [r5] ; 非タスクコンテキストに切換え .if TIPM_LOCK != -15 mov.l #__kernel_lock_flag, r5 ; CPUロック解除状態へ mov.l #0, [r5] mvtc #0, psw ; 優先度0の割込み処理中を偽装 .endif dispatcher_idle_loop: setpsw i ; 全割込み許可 clrpsw i ; 全割込み禁止 mov.l #__kernel_reqflg, r5 ; reqflg が FALSE なら mov.l [r5], r4 cmp #0, r4 bz dispatcher_idle_loop ; アイドルループを繰り返す mov.l #0, [r5] ; reqflgがtrueならfalseにする mov.l #__kernel_intnest, r5 mov.w #0, [r5] ; タスクコンテキストに切換え .if TIPM_LOCK != -15 mov.l #__kernel_lock_flag, r5 ; CPUロック状態へ mov.l #1, [r5] mov.l #__kernel_saved_ipl, r5 mov.l #0, [r5] mvtc #(IPL_LOCK | PSW_I_MASK), psw ; 全割込みロック解除状態 ; 割込み優先度マスク全解除でない状態 .endif bra dispatcher ; dispatcher へ戻る ; ; カーネルの終了処理の呼出し ; ; モードとスタックを非タスクコンテキスト用に切り替え. ; .glb __kernel_call_exit_kernel __kernel_call_exit_kernel: .if TIPM_LOCK != -15 clrpsw i ; 全割込み禁止 mov.l #__kernel_lock_flag, r5 ; CPUロック解除状態へ mov.l #0, [r5] .endif mov.l #__kernel_istkpt, r5 mov.l [r5], r0 ; 割込み用のスタックへ切替え mov.l #__kernel_intnest, r5 mov.w #1, [r5] ; 非タスクコンテキストに切換え bsr __kernel_exit_kernel bra __kernel_call_exit_kernel ; ; 割込み(CPU例外)からのタスクディスパッチャ入口 ; ; 呼出し条件: ; ・全割込みロック状態(PSWレジスタIビット = 0) ; ・割込み優先度マスク全解除でない状態(IPL != 0) ; ・タスクコンテキスト(intnest=0) ; ・使用スタックはタスクスタック ; ・reqflg = true ; ; ここでは, ディスパッチャモードに変更し, reqflgをOFFにしてから, ; 遅延ディスパッチの有無を判断する. ; ; ; ret_int先頭でスタックに積まれているPSWレジスタへのオフセット ; ACC + FPSW + R14--R15 + R1--R5 + PC ; RET_INT_GET_PSW_OFFSET .equ (8+4+28+4) ret_int: .if TIPM_LOCK == -15 mov.l RET_INT_GET_PSW_OFFSET[r0], r5 ; 割込み/CPU例外発生前のIPL値取得 and #PSW_IPL_MASK, r5 mvtc r5, psw ; 全割込みロック(CPUロック)状態 ; 割込み/CPU例外発生前の割込み優先度 .else mov.l #__kernel_lock_flag, r5 ; CPUロック状態へ mov.l #1, [r5] mov.l RET_INT_GET_PSW_OFFSET[r0], r5 ; 割込み/CPU例外発生前のIPL値取得 and #PSW_IPL_MASK, r5 mov.l #__kernel_saved_ipl, r4 mov.l r5, [r4] mvtc #(IPL_LOCK | PSW_I_MASK), psw ; 全割込みロック解除状態 ; 割込み優先度マスク全解除でない状態 .endif mov.l #__kernel_reqflg, r5 mov.l #0, [r5] ; reqflg <--- FALSE mov.l #__kernel_p_runtsk, r15 mov.l [r15], r14 mov.l #__kernel_dspflg, r5 ; dspflg が FALSE なら ret_int_r へ mov.l [r5], r5 cmp #0, r5 bz ret_int_r_call_tex mov.l #__kernel_p_schedtsk, r5 mov.l [r5], r5 cmp r5, r14 ; p_schedtsk と p_runtsk が同じなら beq ret_int_r_call_tex ; ret_int_r_call_tex へ pushm r6-r13 ; 非スクラッチレジスタ保存 st_TCB_sp r0, r14, r5 ; スタックポインタをTCBに保存 st_TCB_pc #ret_int_r, r14, r5 ; 実行再開番地をTCBに保存 bra dispatcher ; ; 割込み(CPU例外)へのタスクディスパッチャ出口 ; ; 呼び出し条件: ; ・ディスパッチャモード(ファイルヘッダ参照) ; ; ここでは, タスク例外ハンドラ呼出しと, 割込み(CPU例外)処理モードへの ; 変更と, コンテキストの復帰を行い, 割込み(CUP例外)発生元へ戻る. ; __kernel_break_wait: ;タスクモニタ用ラベル ret_int_r: popm r6-r13 ; 非スクラッチレジスタ復帰 ret_int_r_call_tex: btst #TCB_enatex_bit, TCB_enatex[r14] ; タスク例外処理許可? bz ret_int_r_rte ld_TCB_texptn r5, r14, r4 ; 保留例外要因があるか? cmp #0, r5 bz ret_int_r_rte bsr __kernel_call_texrtn ; タスク例外ハンドラ呼出し処理実行 ret_int_r_rte: .if TIPM_LOCK != -15 clrpsw i ; 全割込み禁止 mov.l #__kernel_lock_flag, r5 ; CPUロック解除状態へ mov.l #0, [r5] .endif popm r4-r5 ; アキュムレータ復帰 mvtaclo r5 ; ACC最下位16bitは0で復帰 mvtachi r4 popc fpsw ; FPUステータスレジスタ復帰 popm r14-r15 ; レジスタ復帰 popm r1-r5 rte ; 割込み前の処理に戻る ; ; 割込みの出入口処理(アセンブリ言語記述部分) ; ; 呼出し条件: ; ・割込み発生時のH/W処理により, PSWレジスタのIビット=0, IPLは受付け ; た割込みのIPL. ; ・スタックは多重割り込みなら割込みスタック, そうでなければ ; タスクスタック ; ・割込み発生時のH/W処理により,スタックに割込みからの復帰PCとPSWが ; 保存されている. ; ・ベクタテーブルに登録された個別の入り口処理により, スタックに ; スクラッチレジスタ(R1-R5)が保存されている. ; ; 引数: ; ・r1:割込み要因番号 ; ・r2:割込みハンドラのアドレス ; ; レジスタがスタック上にどのように保存されているかを以下に示す. ; この図では上が低位, 下が高位のアドレスで, スタックは下から ; 上方向に向かって積み上げられるものとする. ; ; ------------------------- ; | ACC-HI(4byte) | ; -------------------------(SP + 0) ; | ACC-LO(4byte) | ; -------------------------(SP + 4) ; | FPSW(4byte) | ; -------------------------(SP + 8) ; | R14(4byte) | ; -------------------------(SP + 12) ; | R15(4byte) | ; -------------------------(SP + 16) ; | R1(4byte) | ; -------------------------(SP + 20) ; | R2(4byte) | ; -------------------------(SP + 24) ; | R3(4byte) | ; -------------------------(SP + 28) ; | R4(4byte) | ; -------------------------(SP + 32) ; | R5(4byte) | ; -------------------------(SP + 36) ; | PC(4byte) | ; -------------------------(SP + 40) ; | PSW(4byte) | ; -------------------------(SP + 44) ; ; ここでは, 割込み処理モードに変更してハンドラを実行する. ; ; ハンドラからリターンした後は, 多重割込みでなく, かつ reqflg が ; TRUE になった時に,ret_int へ分岐(遅延ディスパッチ)する. ; ; 多重割込みかどうかは割込みネストカウンタの値で判定する. ; intnest != 0 ならば多重割込みであると判定する. ; ; reqflg はCPUロック状態でチェックする. そうでないと, ; reqflg チェック後に起動された割込みハンドラ内で ; ディスパッチが要求された場合に,ディスパッチされない. ; _kernel_interrupt: pushm r14-r15 ; スクラッチレジスタを退避 pushc fpsw ; FPUステータスレジスタ退避 mvfacmi r5 shll #16, r5 ; ACC最下位16bitは0とする mvfachi r4 pushm r4-r5 ; アキュムレータ退避 mov.l #__kernel_intnest, r5 mov.w [r5], r4 add #1, r4 ; ネスト回数をインクリメント mov.w r4, [r5] cmp #1, r4 ; 多重割り込みかどうか bnz interrupt_from_int ; 加算前が0でなければ多重割込み ; 初段の割込み mov.l r0, r3 ; スタックポインタを取り出し mov.l #__kernel_istkpt, r5 ; 割込み用のスタックへ切替える mov.l [r5], r0 push.l r3 ; タスクスタックを保持 interrupt_from_int: ; 多重割込み setpsw i ; 割込み許可(CPUロック解除状態) .if LOG_INH_LEAVE == 1 push.l r1 ; ログトレースの引数を保持 .endif .if LOG_INH_ENTER == 1 push.l r2 bsr _kernel_log_inh_enter ; ログトレース関数の呼出し ; 引数の割込み要因番号は既にr1に入っている pop r2 .endif jsr r2 ; Cルーチン呼び出し .if LOG_INH_LEAVE == 1 pop r1 ; 引数に割込み要因番号を設定 bsr _kernel_log_inh_leave ; ログトレース関数の呼出し .endif clrpsw i ; 割込み禁止(CPUロック状態) mov.l #__kernel_intnest, r5 mov.w [r5], r4 sub #1, r4 ; ネスト回数をデクリメント mov.w r4, [r5] cmp #0, r4 ; 多重割り込みかどうか bnz interrupt_return ; 多重割り込みならリターン ; 初段の割込み pop r0 ; タスクのスタックに戻す mov.l #__kernel_reqflg, r5 ; ディスパッチ要求がないか? mov.l [r5], r5 cmp #1, r5 bz ret_int ; あれば ret_int へジャンプ interrupt_return: popm r4-r5 ; アキュムレータ復帰 mvtaclo r5 ; ACC最下位16bitは0で復帰 mvtachi r4 popc fpsw ; FPUステータスレジスタ復帰 popm r14-r15 ; レジスタ復帰 popm r1-r5 rte ; 割込み前の処理に戻る ; ; CPU例外の出入口処理(アセンブリ言語記述部分) ; ; 呼出し条件: ; ・CPU例外発生時のH/W処理により, PSWレジスタのIビット=0, IPL=0. ; ・スタックは多重割り込みなら割込みスタック, そうでなければ ; タスクスタック ; ・CPU例外発生時のH/W処理により,スタックにCPU例外からの復帰PCと ; PSWが保存されている. ; ・ベクタテーブルに登録された個別の入り口処理により, スタックに ; スクラッチレジスタ(R1-R5)が保存されている. ; ; 引数: ; ・r1:CPU例外要因番号 ; ・r2:CPU例外ハンドラのアドレス ; ; レジスタがスタック上にどのように保存されているかを以下に示す. ; この図では上が低位, 下が高位のアドレスで, スタックは下から ; 上方向に向かって積み上げられるものとする. ; なお, CPU例外要因番号とR6-R13はCPU例外ハンドラ内で情報を取得 ; する目的で退避しており, 出口処理では保存内容を破棄すればよい. ; ; ------------------------- ; | CPU例外要因番号 | <----- p_excinf ; ------------------------- (intptr_t)(p_excinf + 0) ; | R6(4byte) | ; ------------------------- (intptr_t)(p_excinf + 4) ; | R7(4byte) | ; ------------------------- (intptr_t)(p_excinf + 8) ; | R8(4byte) | ; ------------------------- (intptr_t)(p_excinf + 12) ; | R9(4byte) | ; ------------------------- (intptr_t)(p_excinf + 16) ; | R10(4byte) | ; ------------------------- (intptr_t)(p_excinf + 20) ; | R11(4byte) | ; ------------------------- (intptr_t)(p_excinf + 24) ; | R12(4byte) | ; ------------------------- (intptr_t)(p_excinf + 28) ; | R13(4byte) | ; ------------------------- (intptr_t)(p_excinf + 32) ; | ACC-HI(4byte) | ; ------------------------- (intptr_t)(p_excinf + 36) ; | ACC-LO(4byte) | ; ------------------------- (intptr_t)(p_excinf + 40) ; | FPSW(4byte) | ; ------------------------- (intptr_t)(p_excinf + 44) ; | R14(4byte) | ; ------------------------- (intptr_t)(p_excinf + 48) ; | R15(4byte) | ; ------------------------- (intptr_t)(p_excinf + 52) ; | R1(4byte) | ; ------------------------- (intptr_t)(p_excinf + 56) ; | R2(4byte) | ; ------------------------- (intptr_t)(p_excinf + 60) ; | R3(4byte) | ; ------------------------- (intptr_t)(p_excinf + 64) ; | R4(4byte) | ; ------------------------- (intptr_t)(p_excinf + 68) ; | R5(4byte) | ; ------------------------- (intptr_t)(p_excinf + 72) ; | PC(4byte) | ; ------------------------- (intptr_t)(p_excinf + 76) ; | PSW(4byte) | ; ------------------------- (intptr_t)(p_excinf + 80) ; ; ここでは, 割込み処理モードに変更してハンドラを実行する. ; CPU例外ハンドラに渡すVP型の変数 p_excinf としてISPの値渡す. ; ; ハンドラからリターンした後は, 多重割込みでなく, かつ reqflg が ; TRUE になった時に,ret_int へ分岐(遅延ディスパッチ)する. ; ; 多重割込みかどうかは割込みネストカウンタの値で判定する. ; intnest != 0 ならば多重割込みであると判定する. ; ; reqflg はCPUロック状態でチェックする. そうでないと, ; reqflg チェック後に起動された割込みハンドラ内で ; ディスパッチが要求された場合に,ディスパッチされない. ; ; ; CPU例外入口処理 ; ; ここでは, 割込み処理モードに変更してハンドラを実行する. ; ; ; CPU例外ハンドラ呼出し後に不要となるスタック情報のサイズ ; EXCNO + R6--R13 ; EXCINF_REG_SIZE .equ (4+32) _kernel_exception: pushm r14-r15 ; スクラッチレジスタを退避 pushc fpsw mvfacmi r5 shll #16, r5 ; ACC最下位16bitは0とする mvfachi r4 pushm r4-r5 ; アキュムレータ退避 pushm r6-r13 ; 非スクラッチレジスタ保存 push.l r1 ; CPU例外要因番号を保持 mov.l r0, r3 ; スタックポインタを取り出し mov.l EXC_GET_PSW_OFFSET[r3], r5 and #PSW_I_MASK, r5 bz exception_nonkernel ; 全割込み禁止(CPUロック)状態なら管理外 .if TIPM_LOCK != -15 mov.l EXC_GET_PSW_OFFSET[r3], r5 and #PSW_IPL_MASK, r5 cmp #IPL_LOCK, r5 bgt exception_nonkernel ; IPLがCPUロックレベル以上なら管理外 .endif mov.l #__kernel_intnest, r5 mov.w [r5], r4 add #1, r4 ; ネスト回数をインクリメント mov.w r4, [r5] cmp #1, r4 ; 多重割り込みかどうか bnz exception_from_int ; 加算前が0でなければ多重割込み ; 初段の割込み mov.l #__kernel_istkpt, r5 ; 割込み用のスタックへ切替える mov.l [r5], r0 push.l r3 ; タスクスタックを保持 exception_from_int: ; 多重割込み mov.l EXC_GET_PSW_OFFSET[r3], r5 mvtc r5, psw ; CPU例外発生前の状態に戻す .if LOG_EXC_LEAVE == 1 push.l r1 ; ログトレースの引数を保持 .endif .if LOG_EXC_ENTER == 1 pushm r2-r3 bsr _kernel_log_exc_enter ; ログトレース関数の呼出し ; 引数の割込み要因番号は既にr1に入っている popm r2-r3 .endif mov.l r3, r1 ; 引数のp_excinfを設定 jsr r2 ; Cルーチン呼び出し .if LOG_EXC_LEAVE == 1 pop r1 ; 引数に割込み要因番号を設定 bsr _kernel_log_exc_leave ; ログトレース関数の呼出し .endif clrpsw i ; ここからは必ず割込み禁止 mov.l #__kernel_intnest, r5 mov.w [r5], r4 sub #1, r4 ; ネスト回数をデクリメント mov.w r4, [r5] cmp #0, r4 ; 多重割り込みかどうか bnz exception_return ; 多重割り込みならリターン ; 初段の割込み pop r0 ; タスクのスタックに戻す mov.l #__kernel_reqflg, r5 ; ディスパッチ要求がないか? mov.l [r5], r5 cmp #1, r5 bnz exception_return ; なければリターン add #EXCINF_REG_SIZE, r0 ; CPU例外情報の破棄 bra ret_int ; あれば ret_int へジャンプ exception_nonkernel: mov.l #__kernel_intnest, r5 mov.w [r5], r4 add #1, r4 ; ネスト回数をインクリメント mov.w r4, [r5] cmp #1, r4 ; 多重割り込みかどうか bnz exception_from_nonkernelint ; 加算前が0でなければ多重割込み ; 初段の割込み mov.l #__kernel_istkpt, r5 ; 割込み用のスタックへ切替える mov.l [r5], r0 push.l r3 ; タスクスタックを保持 exception_from_nonkernelint: ; 多重割込み mov.l EXC_GET_PSW_OFFSET[r3], r5 mvtc r5, psw ; CPU例外発生前の状態に戻す mov.l r3, r1 ; 引数のp_excinfを設定 jsr r2 ; Cルーチン呼び出し clrpsw i ; ここからは必ず割込み禁止 mov.l #__kernel_intnest, r5 mov.w [r5], r4 sub #1, r4 ; ネスト回数をデクリメント mov.w r4, [r5] cmp #0, r4 ; 多重割り込みかどうか bnz exception_return ; 多重割り込みならリターン ; 初段の割込み pop r0 ; タスクのスタックに戻す exception_return: add #EXCINF_REG_SIZE, r0 ; CPU例外情報の破棄 popm r4-r5 ; アキュムレータ復帰 mvtaclo r5 ; ACC最下位16bitは0で復帰 mvtachi r4 popc fpsw ; FPUステータスレジスタ復帰 popm r14-r15 ; レジスタ復帰 popm r1-r5 rte ; 割込み前の処理に戻る ; ; 微少時間待ち ; _sil_dly_nse: mov.l #SIL_DLY_TIM1, r5 sub r5, r1 ble sil_dly_nse_ret sil_dly_nse_loop: mov.l #SIL_DLY_TIM2, r5 sub r5, r1 bgt sil_dly_nse_loop sil_dly_nse_ret: rts .end