;* ;* 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 ;* Copyright (C) 2003-2007 by Naoki Saito ;* Nagoya Municipal Industrial Research Institute, JAPAN ;* Copyright (C) 2003-2004 by Ryosuke Takeuchi ;* Platform Development Center RICOH COMPANY,LTD. JAPAN ;* ;* 上記著作権者は,以下の (1)〜(4) の条件か,Free Software Foundation ;* によって公表されている GNU General Public License の Version 2 に記 ;* 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア ;* を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下, ;* 利用と呼ぶ)することを無償で許諾する. ;* (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 ;* 権表示,この利用条件および下記の無保証規定が,そのままの形でソー ;* スコード中に含まれていること. ;* (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 ;* 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 ;* 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 ;* の無保証規定を掲載すること. ;* (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 ;* 用できない形で再配布する場合には,次のいずれかの条件を満たすこ ;* と. ;* (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 ;* 作権表示,この利用条件および下記の無保証規定を掲載すること. ;* (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに ;* 報告すること. ;* (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 ;* 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. ;* ;* 本ソフトウェアは,無保証で提供されているものである.上記著作権者お ;* よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も ;* 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直 ;* 接的または間接的に生じたいかなる損害に関しても,その責任を負わない. ;* ;* @(#) $Id: cpu_support.a30,v 1.7 2007/03/23 07:06:35 honda Exp $ ; ; プロセッサ依存モジュール アセンブリ言語部(M16C用) ; ; ; offset.incはmakeoffset.cとm16coffset.exeコマンドにより ; 自動生成される. ; .include offset.inc .glb __kernel_runtsk .glb __kernel_schedtsk .glb __kernel_reqflg .glb __kernel_enadsp .glb __kernel_dispatch .glb __kernel_exit_and_dispatch .glb __kernel_activate_r .glb __kernel_call_texrtn .glb __kernel_interrupt .glb __kernel_intnest .glb _iana_tsk .glb __kernel_break_wait .section program, code, align ; ; タスクディスパッチャ ; ; dispatch は,タスクコンテキスト状態・割込み禁止状態で呼び出さなけ ; ればならない.exit_and_dispatch も,タスクコンテキスト状態・割込 ; み禁止状態で呼び出すのが原則であるが,カーネル起動時に対応するため, ; 割込みモードで呼び出した場合にも対応している. ; 呼び出し条件: IPL=0, FLGレジスタIビット=0 (CPUロック状態), ; intnest = 0(タスクコンテキスト), タスクスタック ; __kernel_dispatch: pushm sb, fb ; スタックへレジスタ保存 mov.w __kernel_runtsk, a0 stc isp, TCB_sp[a0] ; スタックポインタをTCBに保存 mov.w #(dispatch_r>>16), TCB_pc+2[a0] ; 実行再開番地をTCBに保存 mov.w #(dispatch_r & 0ffffh), TCB_pc[a0] jmp.b dispatcher ; ; 呼び出し条件: IPL=0, FLGレジスタIビット=0 (CPUロック状態), ; intnest = 0(タスクコンテキスト), タスクスタック ; ; a0 にはruntsk のアドレスが格納されている ; dispatch_r: popm sb,fb ; タスクスタックからレジスタ復帰 mov.w TCB_enatex[a0], r0 btst TCB_enatex_bit, r0 ; タスク例外処理許可? jz dispatch_r_1 ; 許可でなければ dispatch_r_1 へ mov.w TCB_texptn[a0], r0 ; 保留例外要因があるか? jz dispatch_r_1 ; なければ dispatch_r_1 へ jmp __kernel_call_texrtn ; タスク例外ハンドラへ dispatch_r_1: ; タスク例外を実行しない場合 rts ; dispatch 呼び出し元へ戻る. ; ; タスク起動時処理 ; ; ここでは, CPUロック解除状態にし, タスクを起動する. ; ; 呼出条件: FLGレジスタIビット=0 (CPUロック状態), タスクスタック ; IPL=0, タスクコンテキスト(intnest=0) ; __kernel_activate_r: pop.w a0 ; タスクの起動番地をA1A0に設定 pop.w a1 ldc #0040h, flg ; 割込み許可, ISP, IPL=0 jmpi.a a1a0 ; ; dispatch呼び出し条件: ; ・すべてのタスクのコンテキストは保存されている. ; ・FLGレジスタIビット=0 (CPUロック状態) ; ・コンテキストはタスクコンテキスト(intnest=0) ;  但し、exit_and_dispatchについてはモニター起動等を考慮 ;  した上記以外の呼び出し条件の対応を行う ; dispatcher 呼出時のスタック: ; __kernel_dispatch からきた場合: タスクスタック ; exit_and_dispatch からきた場合: ; exit_task からきた場合はタスクスタック ; カーネル起動時は割込みスタック ; ret_int からきた場合: 割込みスタック ; dispatcher_2 での割込み待ちからきた場合: 割込みスタック ; __kernel_exit_and_dispatch: fclr i ; 割込み禁止 mov.b #0, __kernel_intnest ; ネストカウンタクリア dispatcher: mov.w __kernel_schedtsk, a0 ; mov.w a0, __kernel_runtsk ; schedtsk を runtsk に .IF MON == 1 ; タスクモニター機能用分岐 ; 不要の場合は (MON = 0) jsr.a _iana_tsk ; タスク実行情報の設定 mov.w __kernel_runtsk,a0 ; a0を復帰 .ENDIF jz dispatcher_1 ; schedtsk がなければ割込み待ち ldc TCB_sp[a0], isp ; タスクスタックポインタを復帰 jmpi.a TCB_pc[a0] ; 実行再開番地へジャンプ ; ; schdedtskが NULL の場合は、これより下には行かない ; dispatcher_1: ldc #RAMEND, isp ; 割込み用のスタックへ切替え inc.b __kernel_intnest ; 非タスクコンテキスト dispatcher_2: fset i ; 割込み待ち wait ; wait命令を使用すると nop ; 消費電力を抑えることができる. nop ; コメントをつけたまま(nopのみ)にすると nop ; アイドルループと同じような動作になる. nop ; ; ; ここで非タスクコンテキスト,割込みスタックに切り換えたのは, ; ここで発生する割込み処理にどのスタックを使うかという問題の解決と, ; 割込みハンドラ内でのディスパッチ防止という2つの意味がある. ; fclr i ; 割込み禁止 mov.w __kernel_reqflg, r0 ; reqflg が FALSE なら jz dispatcher_2 ; dispatcher_2 へ mov.w #0, __kernel_reqflg ; reqflgがTRUEならFALSEにする dec.b __kernel_intnest ; タスクコンテキストに戻す jmp.b dispatcher ; dispatcher へ戻る ; ; 割込みハンドラ/CPU例外ハンドラ出口処理 ; ; 呼出し条件: ; ・FLGレジスタのIビット=0, IPL=0, タスクコンテキスト(intnest=0) ; ・使用スタックはタスクスタック, reqflg = TRUE ; ret_int: mov.w #0, __kernel_reqflg ; reqflg <--- FALSE mov.w __kernel_runtsk, a0 ; A0 <--- runtsk mov.w __kernel_enadsp, r0 ; enadsp が FALSE なら jz ret_int_r ; ret_int_r へ mov.w __kernel_schedtsk, r0 ; schedtskと cmp.w a0, r0 ; runtsk が同じなら jeq ret_int_r ; ret_int_r へ ;;;; (runtsk == NULL) のチェックは必要ないため削除 (07/03/02) stc isp, TCB_sp[a0] ; タスクスタックを保存 mov.w #(ret_int_r&0ffffh), TCB_pc[a0] ; 実行再開番地を保存 mov.w #(ret_int_r>>16), TCB_pc+2[a0] jmp.b dispatcher __kernel_break_wait: ret_int_r: mov.w TCB_enatex[a0],r0 ; enatex が FALSE ならリターン btst TCB_enatex_bit,r0 jz ret_int_r_1 mov.w TCB_texptn[a0],r0 ; texptn が 0 ならばリターン jz ret_int_r_1 jsr.a __kernel_call_texrtn ; タスク例外処理ルーチンの呼出し ret_int_r_1: popm r0,r1,r2,r3,a0,a1,sb,fb ; スタックからレジスタを復帰 reit ; タスクへ戻る ; ; 割込み/CPU例外の出入口処理(アセンブリ言語記述部分) ; ; 呼出し条件: ; ・FLGレジスタのIビット=0, IPLは受付けた割込みのIPL. ; ・スタックは多重割り込みなら割込みスタック, そうでなければ ; タスクスタック ; ・a1とa0 には割込み/CPU例外ハンドラのアドレスが格納されている. ; ・r1 には(タスクor割込み)スタックポインタの値が格納されている. ; これはそのままCPU例外ハンドラに渡すVP型の変数 p_excinf となる. ; ; レジスタがスタック上にどのように保存されているかを以下に示す. ; この図では上が低位, 下が高位のアドレスで, スタックは下から ; 上方向に向かって積み上げられるものとする. ; ; -------------------------------------- ; | R0(2byte) | <--- p_excinf ; | | ; -------------------------------------- ; | R1(2byte) | ; | | ; -------------------------------------- ; | R2(2byte) | ; | | ; -------------------------------------- ; | R3(2byte) | ; | | ; -------------------------------------- ; | A0(2byte) | ; | | ; -------------------------------------- ; | A1(2byte) | ; | | ; -------------------------------------- ; | SB(2byte) | ; | | ; -------------------------------------- ; | FB(2byte) | ; | | ; -------------------------------------- ; | PCの下位2バイト | ; | | ; -------------------------------------- ; | FLGの下位1バイト | ; -------------------------------------- ; | FLGの上位4ビット/PCの上位4ビット | ; -------------------------------------- ; ; ハンドラからリターンした後は, 多重割込みでなく, かつ reqflg が ; TRUE になった時に,ret_int へ分岐する. ; ; 多重割込みかどうかは割込みネストカウンタの値で判定する. ; intnest != 0 ならば多重割込みであると判定する. ; ; reqflg はCPUロック状態でチェックする. そうでないと, ; reqflg チェック後に起動された割込みハンドラ内で ; ディスパッチが要求された場合に,ディスパッチされない. ; __kernel_interrupt: cmp.b #0, __kernel_intnest ; 多重割り込みかどうか jnz int_from_int ; 0でなければ多重割込み int_from_task: ; 初段の割込み ldc #RAMEND, isp ; 割込み用のスタックへ切替える push.w r1 ; スタックポインタを割込みスタックへ保存 int_from_int: ; 多重割込み inc.b __kernel_intnest ; ネスト回数をインクリメント fset i ; 割込み禁止解除 jsri.a a1a0 ; Cルーチン呼び出し fclr i ; 割込み禁止 dec.b __kernel_intnest ; ネスト回数をデクリメント jnz int_return ; 多重割り込みならリターン int_from_task2: ; 初段の割込み pop.w r1 ; タスクスタックポインタを戻す ldc r1, isp ldipl #0 ; タスクのIPL値をセット(IPL=0) mov.w __kernel_reqflg, r1 ; ディスパッチ要求がないか? jz int_return ; なければ割込み発生元のタスクに戻る jmp.b ret_int ; あれば ret_int へジャンプ int_return: popm r0,r1,r2,r3,a0,a1,sb,fb ; レジスタ復帰 reit ; 割込み前の処理に戻る ; ; 微少時間待ち ; SIL_DLY_TIM1 .equ 625 ; 最小時間(ループ0回)[ns] SIL_DLY_TIM2 .equ 250 ; ループ1回あたりの時間[ns] .glb $sil_dly_nse $sil_dly_nse: sub.w #SIL_DLY_TIM1, r1 jgtu L0 rts L0: sub.w #SIL_DLY_TIM2, r1 jgtu L0 rts ; 未使用割込みの処理 .glb _unused_interrupt _unused_interrupt: reit .end