= JSPカーネル ターゲット依存部 ポーティングガイド = (Release 1.4.3対応,最終更新: 22-Apr-2007) ------------------------------------------------------------------------ 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) 2004-2005 by Embedded and Real-Time Systems Laboratory Graduate School of Information Science, Nagoya Univ., JAPAN 上記著作権者は,以下の (1)〜(4) の条件か,Free Software Foundation によって公表されている GNU General Public License の Version 2 に記 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下, 利用と呼ぶ)することを無償で許諾する. (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 権表示,この利用条件および下記の無保証規定が,そのままの形でソー スコード中に含まれていること. (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 の無保証規定を掲載すること. (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 用できない形で再配布する場合には,次のいずれかの条件を満たすこ と. (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 作権表示,この利用条件および下記の無保証規定を掲載すること. (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに 報告すること. (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. 本ソフトウェアは,無保証で提供されているものである.上記著作権者お よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直 接的または間接的に生じたいかなる損害に関しても,その責任を負わない. @(#) $Id: config.txt,v 1.40 2007/05/28 02:06:45 honda Exp $ ------------------------------------------------------------------------ このドキュメントでは,JSPカーネルのターゲット依存部で提供すべきデータ 型や関数などについて解説する. JSPカーネルのターゲット依存部は,依存部の再利用性を考慮し,プロセッサ 依存部,システム依存部,開発環境依存部に分離している.開発環境依存部に 関しては,おおよその役割分担を決まっているが,プロセッサ依存部とシステ ム依存部については,役割分担が明確なわけではない.以下のデータ型や関数 の多くは,どの依存部で定義してもかまわない.シミュレーション環境などの 極端なケースでは,システム依存部を全く使わないことも考えられる. JSPカーネルのデバイスドライバ等は,トロン協会において検討されているデ バイスドライバ設計ガイドラインに沿う形で実装している.デバイスドライバ 設計ガイドラインWGの中間報告は,以下のURLからダウンロードすることがで きる. http://www.ertl.jp/ITRON/GUIDE/device-j.html 1.システム構築環境 JSPカーネルは,GNU開発環境を標準としており,コンフィギュレータや開発支 援ユーティリティは,主にGNU開発環境と組み合わせて動作するように実装さ れている.そこで以下では,GNU開発環境を用いる場合を中心に説明する.そ れ以外の開発環境を用いる場合には,開発支援ユーティリティの改造が必要に なったり,一部のユーティリティが使用できないケースがある. (1) ターゲット略称の決定 新しいターゲット依存部を作成する時は,プロセッサ略称とシステム略称を定 める.また,GNU以外の開発環境を用いる場合には,開発環境略称を定める. これらの略称に用いる文字は,英文字,数字および "_" に限定する. (2) ターゲット依存部のファイルを置くためのディレクトリ ターゲット依存部のファイルを置くためのディレクトリを,config の下に作 成する.ディレクトリ名は,ターゲット略称から以下のように決定する.ただ し,ディレクトリ名に含まれる英文字はすべて小文字とする.すなわち,ディ レクトリ名には,英小文字,数字および "_" のみを使うことができる. GNU開発環境を用いる場合には,config の下にプロセッサ略称を用いてプロセッ サ依存部のファイルを置くためのディレクトリ(プロセッサ依存部ディレクト リ)を,さらにその下にシステム略称を用いてシステム依存部のファイルを置 くためのディレクトリ(システム依存部ディレクトリ)を作成する. GNU以外の開発環境を用いる場合には,config の下にプロセッサ略称と開発環 境略称を "-" で連結した名称(例えば,"sh3-hitachi")で,プロセッサ依存 部ディレクトリを作成する.さらにその下に,システム略称を用いてシステム 依存部ディレクトリを作成する.これらのディレクトリには,GNU開発環境用 のディレクトリに置かれているファイルと異なるファイルのみを置く.ファイ ルが置かれていない場合には,GNU開発環境用のディレクトリを参照する.た だし,Makefile.config に関しては,GNU開発環境用のディレクトリを参照し ないため,同じ内容であっても用意しなければならない. (3) システム構築方法の設定 プロセッサ依存部ディレクトリおよびシステム依存部ディレクトリの下に,そ れぞれ,システム構築方法を設定するための Makefile.config ファイルを用 意する.これらのファイルは,Makefile からインクルードされる. プロセッサ依存部およびシステム依存部の Makefile.config で定義すべき変 数には,開発環境のコマンド名を設定するもの,コンパイルオプションを設定 するもの,その他のものがある.ここでは,その他の変数とその定義の方法に ついて説明する. (3-1) TEXT_START_ADDRESS テキストセクションの先頭番地 (3-2) DATA_START_ADDRESS データセクションの先頭番地 各セクションの先頭番地の指定が必要な場合には,これらの変数に先頭番地を 定義する. (3-3) LDSCRIPT リンカスクリプトのファイル名 専用のリンカスクリプトを用いる場合には,この変数にリンカスクリプトのファ イル名を定義する.ファイル名は,config ディレクトリからの相対パスで指 定する. (4) 開発環境のコマンド名の設定 (4-1) TARGET ターゲット名 GNU開発環境を configure する場合に指定するターゲット名で,コンパイラ等 のコマンド名の先頭に付与される文字列(最後の "-" は不要)に定義する. 例えば,TARGET が m68k-unknown-elf に定義された場合には,コンパイラと して m68k-unknown-elf-gcc が使われる.この変数が定義されない場合には, 単なる gcc が使われる.GNU以外の開発環境を用いる場合には,定義する必要 がない. (4-2) CC Cコンパイラドライバの名称 (4-3) CXX C++コンパイラドライバの名称 (4-4) AS アセンブラの名称 (4-5) LD リンカの名称 (4-6) AR アーカイバの名称 (4-7) NM nmプログラムの名称 (4-8) RANLIB ranlibプログラムの名称 (4-9) OBJCOPY objcopyプログラムの名称 (4-10) OBJDUMP objdumpプログラムの名称 GNU以外の開発環境を用いる場合に,それぞれのコマンドの名称に定義する. 対応するコマンドがない場合や,コマンドパラメータが異なる場合には, Makefile 中のそのコマンドを呼び出している部分を変更する必要がある.GNU 開発環境では,これらは TARGET を用いて定義されるので,定義する必要はな い. (5) コンパイルオプションの設定 (5-1) CDEFS マクロ定義オプション(-D) (5-2) INCLUDES インクルードファイルのディレクトリ指定オプション(-I) (5-3) COPTS コンパイラに対するその他のオプション (5-4) LDFLAGS リンカに対するオプション (5-5) LIBS ライブラリリンク指定のためのオプション ターゲットに依存して,すべてのソースファイルに共通するコンパイルオプショ ンの追加が必要な場合には,オプションの種類毎に上に示した変数に定義する. システム依存部の Makefile.config でこれらの変数を定義する時は,":=" を 用いて,それまでの定義に追加する形で行う.例えば,プロセッサ依存部で 「-Wall -g -O2 -m68020-40」というオプションを追加したい場合には,以下 の記述をプロセッサ依存部の Makefile.config に含める. COPTS := $(COPTS) -Wall -g -O2 -m68020-40 それに対して,システム依存部の Makefile.config は Makefile の最初でイ ンクルードされるため,このような配慮は必要ないが,変更に強くするために 同様に扱うことにする. ほとんどの場合に,プロセッサ依存部の Makefile.config には以下の記述を 含める必要がある. GNU開発環境を用いる場合 INCLUDES := -I$(CONFIGDIR)/$(CPU) その他の開発環境を用いる場合 INCLUDES := -I$(CONFIGDIR)/$(CPU)-$(TOOL) -I$(CONFIGDIR)/$(CPU) また,システム依存部の Makefile.config には以下の記述を含める必要があ る. GNU開発環境を用いる場合 INCLUDES := $(INCLUDES) -I$(CONFIGDIR)/$(CPU)/$(SYS) その他の開発環境を用いる場合 INCLUDES := $(INCLUDES) -I$(CONFIGDIR)/$(CPU)-$(TOOL)/$(SYS) \ -I$(CONFIGDIR)/$(CPU)/$(SYS) また,アセンブリ言語レベルの識別名が,C言語レベルの識別名の先頭に "_" が付いたものになる場合には,いずれかの Makefile.config で CDEFS に -DLABEL_ASM を追加する. (5-6) STASK_DIR システムサービスのソースが置かれたディレクトリ (5-7) STASK_ASMOBJS アセンブラで記述されたシステムサービスのオブジェクト (5-8) STASK_COBJS C言語で記述されたシステムサービスのオブジェクト (5-9) STASK_CFLAGS システムサービスに対するコンパイルオプション (5-10) STASK_LIBS システムサービスに対するライブラリリンク指定 システムサービス(システムログタスクやデバイスドライバなど)のソースが 置かれたディレクトリ,それを構成するオブジェクトファイルのリスト,それ らをコンパイルする際に適用するコンパイルオプション,その構成に必要なラ イブラリリンク指定を行う場合には,上に示した変数に定義する. システム依存部の Makefile.config でこれらの変数を定義する時は,CDEFS などと同様の扱いが必要である. (5-11) KERNEL_DIR カーネルのソースが置かれたディレクトリ (5-12) KERNEL_ASMOBJS アセンブラで記述されたカーネルのオブジェクト (5-13) KERNEL_COBJS C言語で記述されたカーネルのオブジェクト (5-14) KERNEL_CFLAGS カーネルに対するコンパイルオプション カーネルのソースが置かれたディレクトリ,それを構成するオブジェクトファ イルのリスト,それらをコンパイルする際に適用するコンパイルオプションを 指定する場合には,上に示した変数に定義する. システム依存部の Makefile.config でこれらの変数を定義する時は,CDEFS などと同様の扱いが必要である. ほとんどの場合に,プロセッサ依存部の Makefile.config には以下の記述を 含める必要がある. GNU開発環境を用いる場合 KERNEL_DIR := $(KERNEL_DIR):$(CONFIGDIR)/$(CPU) KERNEL_ASMOBJS := $(KERNEL_ASMOBJS) cpu_support.o KERNEL_COBJS := $(KERNEL_COBJS) cpu_config.o その他の開発環境を用いる場合 KERNEL_DIR := $(KERNEL_DIR):$(CONFIGDIR)/$(CPU)-$(TOOL) KERNEL_DIR := $(KERNEL_DIR):$(CONFIGDIR)/$(CPU) KERNEL_ASMOBJS := $(KERNEL_ASMOBJS) cpu_support.o KERNEL_COBJS := $(KERNEL_COBJS) cpu_config.o また,システム依存部ディレクトリの Makefile.config には以下の記述を含 める必要がある. GNU開発環境を用いる場合 KERNEL_DIR := $(KERNEL_DIR):$(CONFIGDIR)/$(CPU)/$(SYS) KERNEL_ASMOBJS := $(KERNEL_ASMOBJS) sys_support.o KERNEL_COBJS := $(KERNEL_COBJS) sys_config.o その他の開発環境を用いる場合 KERNEL_DIR := $(KERNEL_DIR):$(CONFIGDIR)/$(CPU)-$(TOOL)/$(SYS) KERNEL_DIR := $(KERNEL_DIR):$(CONFIGDIR)/$(CPU)/$(SYS) KERNEL_ASMOBJS := $(KERNEL_ASMOBJS) sys_support.o KERNEL_COBJS := $(KERNEL_COBJS) sys_config.o (6) オフセットファイルの生成 アセンブリ言語で記述されるプログラムから,C言語の構造体にアクセスする 場合には,構造体の各フィールドのオフセットを参照することが必要である. JSPカーネルでは,必要なオフセット値をファイル(標準では offset.h)に出 力するための仕組みとして,makeoffset.c と genoffset を用意している. makeoffset.c は,どのオフセット値をファイルに出力するかを指定するもの で,ターゲット依存部で用意する必要がある.genoffset は,現時点ではGNU 開発環境にのみ対応している. makeoffset.c と genoffset を使うことで,例えば,TCB 中の texptn フィー ルドのオフセット値を TCB_texptn にマクロ定義することや,TCB 中のタスク コンテキストブロック(tskctxb)に含まれる pc フィールドのオフセット値 を TCB_pc にマクロ定義することができる.また,TCB 中の enatex フィール ドのオフセット値,ビット位置,ビットマスクを,それぞれ TCB_enatex, TCB_enatex_bit,TCB_enatex_mask にマクロ定義することができる.マクロ定 義するビット位置やビットマスクは,アクセスするサイズやエンディアンを指 定することができる. GNU開発環境以外を用いる場合など,この仕組みでオフセットファイルを生成 できない時には,offset.h をターゲット依存部で用意し,Makefile.config で OMIT_MAKEOFFSET をヌルストリング以外に定義する. makeoffset.c と genoffset に関するマニュアルは,現時点では用意できてい ない.使い方がわからない場合や,機能が足りない場合には,相談されたい. (7) スタートアップモジュールなど ターゲットによっては,ロードモジュールの先頭と最後にリンクすべきプログ ラムを,ターゲット依存部で用意する必要がある.多くの場合,スタートアッ プモジュールをロードモジュールの先頭にリンクする必要がある. ロードモジュールの先頭にリンクすべきプログラムがある場合には, Makefile.config において,そのオブジェクトファイル名を START_OBJS に定 義し,それに対するコンパイルルールと依存関係作成ルールを定義しなければ ならない.ロードモジュールの最後にリンクすべきプログラムがある場合には, そのオブジェクトファイル名を END_OBJS に定義し,それに対するコンパイル ルールと依存関係作成ルールを定義しなければならない. 例えば,スタートアップモジュールのソースファイルが start.S の場合には, Makefile.config に次のような記述を入れるとよい. # スタートアップモジュールのオブジェクトファイル名 START_OBJS = start.o # スタートアップモジュールのコンパイルルール $(START_OBJS): %.o: %.S $(CC) -c $(CFLAGS) $(KERNEL_CFLAGS) $< # スタートアップモジュールの依存関係作成ルール $(START_OBJS:.o=.d): %.d: %.S @$(PERL) $(SRCDIR)/utils/makedep -C $(CC) \ -O "$(CFLAGS) $(KERNEL_CFLAGS)" $< >> Makefile.depend また,コンパイラに標準の crtbegin.o と crtend.o を用いる場合には, Makefile.config に次のような記述を入れるとよい. # オブジェクトファイル名 START_OBJS = $(shell $(CC) -print-file-name=crtbegin.o) END_OBJS = $(shell $(CC) -print-file-name=crtend.o) # 依存関係作成ルール $(START_OBJS:.o=.d): %.d: $(END_OBJS:.o=.d): %.d: この場合,これらのファイルをコンパイルすることはないため,コンパイルルー ルは不要である.また,依存関係作成ルールはダミーでよい(依存関係作成ルー ルがないとエラーになる). なお,カーネル用のスタートアップモジュールからは,main 関数ではなく, kernel_start 関数を起動する必要がある. (8) リンカスクリプト 開発環境に標準のリンカスクリプトが使用できない場合には,ターゲット依存 部で用意する. 2.アプリケーション用のインクルードファイル ターゲット依存部で提供すべきアプリケーション用の定義は次の通りである. これらの定義の中で,(1) および (2) は tool_defs.h に含めなければならな い.その他の定義は,cpu_defs.h または sys_defs.h(またはそれらからイン クルードされるファイル)に含める. (1) コンパイラ依存のデータ型の定義 コンパイラ依存のデータ型を以下のシンボルに定義する.これらの定義は, typedef ではなく,#define によりマクロ定義しなければならない. (1-1) _int8_ 8ビットの整数型 (1-2) _int16_ 16ビットの整数型 (1-3) _int32_ 32ビットの整数型 (1-4) _int64_ 64ビットの整数型 各サイズの整数型を,これらのシンボルにマクロ定義する._int32_ 以外は, コンパイラがサポートしていない場合には定義する必要がない._int32_ の定 義は必須である. (1-5) _bool_ BOOLの型 BOOL は,標準では int に型定義されるが,それで不都合な場合には,適切な 型を _bool_ にマクロ定義する. (1-6) _vp_int_ VP_INTの型 VP_INT は,標準では VP に型定義されるが,それで不都合な場合(例えば, ポインタが16ビットで,int が32ビットの場合)には,適切な型を _vp_int_ にマクロ定義する. (1-7) _intptr_ ポインタを格納できる整数型 _intptr_ は,フォーマット出力において,int型もポインタ型も格納できる整 数型として使用する.これを定義しない場合,long が使われる. (2) コンパイラの拡張機能のためのマクロ定義 (2-1) inline インライン指定 (2-2) Inline ファイル内のみに有効なインライン指定 (2-3) asm インラインアセンブラ(最適化を許す) (2-4) Asm インラインアセンブラ(最適化を抑止) これらの中で,asm と Asm は,ターゲット依存部で用いていなければ定義す る必要がない. (3) タイムティックの定義 (3-1) TIC_NUME タイムティックの周期の分子(単位: 1ミリ秒) (3-2) TIC_DENO タイムティックの周期の分母(単位: 1ミリ秒) (4) 割込みハンドラ/CPU例外ハンドラ関連の定義 (4-1) INHNO 割込みハンドラ番号のデータ型 (4-2) EXCNO CPU例外ハンドラ番号のデータ型 (5) 割込みマスクと割込みマスクの変更/参照関連の定義(オプション) chg_ixx,get_ixx をターゲット依存にサポートする場合には,以下の定義お よび宣言をターゲット依存部で提供する.xx,xxxx,XXXX は,ターゲット毎 に適切な文字列に定める.xxxx および XXXX は,4文字でなくてもよい. (5-1) IXXXX 割込みマスクのデータ型 (5-2) ER chg_ixx(IXXXX ixxxx) chg_ixx のプロトタイプ宣言 (5-3) ER get_ixx(IXXXX *p_ixxxx) get_ixx のプロトタイプ宣言 (6) 割込み番号と割込みの禁止/許可関連の定義(オプション) dis_int,ena_int をターゲット依存にサポートする場合には,以下の定義お よび宣言をターゲット依存部で提供する. (6-1) INTNO 割込み番号のデータ型 (6-2) ER dis_int(INTNO intno) dis_int のプロトタイプ宣言 (6-3) ER ena_int(INTNO intno) ena_int のプロトタイプ宣言 (7) 性能評価用システム時刻関連の定義(オプション) JSPカーネルは,研究への利用を主目的の一つとしていることから,ターゲッ ト依存に,性能評価用のサービスコール vxget_tim をサポート可能としてい る.vxget_tim をサポートする場合には,以下の定義および宣言をターゲット 依存部で提供する. (7-1) SYSUTIM 性能評価用システム時刻のデータ型 (7-2) ER vxget_tim(SYSUTIM *p_sysutim) vxget_tim のプロトタイプ宣言 (8) ターゲット識別マクロの定義 cpu_defs.h ではプロセッサ略称(cpu_defs.h の置かれているディレクトリ名 を大文字にしたもの),sys_defs.h ではシステム略称(sys_defs.h の置かれ ているディレクトリ名を大文字にしたもの)をマクロ定義する. (9) プロセッサのエンディアンの定義 (9-1) SIL_ENDIAN プロセッサがビッグエンディアンの場合には SIL_ENDIAN_BIG(=1),リトル エンディアンの場合には SIL_ENDIAN_LITTLE(=0)にマクロ定義する. (10) システムの停止処理の定義 (10-1) kernel_abort(void) assertマクロにおけるアサーションの失敗や,サービスコールが致命的なエラー を返した場合に,システムを停止させる関数またはマクロ.kernel_exit を呼 び出す方法も考えられるが,デバッグを容易にするためには,インライン関数 かマクロで定義し,その場でシステムを停止させる処理に定義するのが望まし い(kernel_exit を呼び出すと,エラーが発生した時点の状態から変化してし まう). 3.カーネル用のデータ型や関数など ターゲット依存部で提供すべきカーネル用のデータ型や関数などは次の通りで ある.これらのデータ型やマクロの定義と関数のプロトタイプ宣言は,別に記 述がない限り,cpu_config.h または sys_config.h(またはそれらからインク ルードされるファイル)に含める.また,関数の実体は,C言語の場合は cpu_config.c または sys_config.c に,アセンブリ言語の場合は cpu_support.S または sys_support.S に記述する. (0) インクルード方法に関するルール ヘッダファイルをインクルードする記述は,以下のルールに従うのを原則とす る. ANSI Cの標準インクルードファイルは,#include <…> でインクルードする. また,Makefile または Makefile.config で INCLUDES に -Iオプションで指 定したディレクトリにあるファイルは,#include <…> でインクルードする. カーネルを構成するファイルからのインクルードに対しては,以下のディレク トリにあるファイルがこれに該当する(ターゲットにも依存). jsp/include/ jsp/config/$(CPU) jsp/config/$(CPU)/$(SYS) jsp/config/$(CPU)-$(TOOL) jsp/config/$(CPU)-$(TOOL)/$(SYS) pdic/simple_sio その他のインクルードファイルは #include "…" でインクルードする.カー ネルを構成するファイルからのインクルードに対しては,以下のディレクトリ にあるファイルがこれに該当する(ターゲットにも依存). jsp/kernel jsp/systask (1) タスクコンテキストブロックのデータ型 (1-1) CTXB ターゲット依存のタスクコンテキストを保存するために,TCB 中に持つことが 必要なデータ構造の型. (2) システム状態参照 (2-1) BOOL sense_context(void) 現在の実行コンテキストが,タスクコンテキストの場合は FALSE,非タスクコ ンテキストの場合は TRUE を返す関数. (2-2) BOOL sense_lock(void) 現在のシステム状態が,CPUロック状態の場合は TRUE,CPUロック解除状態の 時は FALSE を返す関数. (2-3) BOOL t_sense_lock(void) タスクコンテキストにおいて,現在のシステム状態が,CPUロック状態の場合 は TRUE,CPUロック解除状態の時は FALSE を返す関数.この関数が,非タス クコンテキストから呼ばれることはない. (2-4) BOOL i_sense_lock(void) 非タスクコンテキストにおいて,現在のシステム状態が,CPUロック状態の場 合は TRUE,CPUロック解除状態の時は FALSE を返す関数.この関数が,タス クコンテキストから呼ばれることはない. ※ 原理的には,sense_lock が提供されていれば t_sense_lock と i_sense_lock は必要なく,逆に t_sense_lock と i_sense_lock が提供され ていれば sense_lock を実現することはできるが,ターゲットに依存せずに高 い実行効率を実現するために,ターゲット依存部が3つの関数を提供すること としている. (3) CPUロックとその解除 (3-1) void t_lock_cpu(void) タスクコンテキストにおいて,CPUロック解除状態から,CPUロック状態に遷移 させる関数.この関数が,CPUロック状態で呼ばれることはない.また,非タ スクコンテキストから呼ばれることもない. (3-2) void t_unlock_cpu(void) タスクコンテキストにおいて,CPUロック状態から,CPUロック解除状態に遷移 させる関数.この関数が,CPUロック解除状態で呼ばれることはない.また, 非タスクコンテキストから呼ばれることもない. (3-3) void i_lock_cpu(void) 非タスクコンテキストにおいて,CPUロック解除状態から,CPUロック状態に遷 移させる関数.この関数が,CPUロック状態で呼ばれることはない.また,タ スクコンテキストから呼ばれることもない. (3-4) void i_unlock_cpu(void) 非タスクコンテキストにおいて,CPUロック状態から,CPUロック解除状態に遷 移させる関数.この関数が,CPUロック解除状態で呼ばれることはない.また, タスクコンテキストから呼ばれることもない. (4) タスクディスパッチャ (4-1) void dispatch(void) タスクディスパッチャ(以下,単にディスパッチャと言う)を明示的に呼ぶた めの関数.タスクコンテキストから呼ばれたサービスコール処理から,CPUロッ ク状態で呼ばれる. この関数が呼ばれると,関数を呼んだタスクのコンテキストを保存し, 実行 できるタスクの中で最高優先順位のタスク(schedtsk)のコンテキストを復帰 して実行状態とする.実行できるタスクがない場合(schedtsk が NULL の場 合)には,割込みを許可して,実行できるタスクができるまで待つ.ここで, 実行できるタスクができるのを待つ間に起動された割込みハンドラの出口で, ディスパッチャが呼ばれないように対策することが必要である.具体的には, 実行できるタスクができるのを待つ間,一時的に非タスクコンテキストに切り 換えるか,ディスパッチを保留するようにする. 新たに実行状態になったタスクが,タスク例外処理ルーチンの起動条件を満た していれば,タスク例外処理ルーチンを起動する.また,この関数を呼び出し たタスクが次に実行状態になった時,タスク例外処理ルーチンの起動条件を満 たしていれば,タスク例外処理ルーチンの起動を行う.タスク例外処理ルーチ ンの起動には,ターゲット非依存部が提供する calltex または call_texrtn を用いることができる. (4-2) void exit_and_dispatch(void) 現在実行中のコンテキストを捨て,ディスパッチャを呼び出すための関数.タ スクコンテキストから呼ばれたサービスコール(具体的には,ext_tsk)処理 またはカーネルの初期化処理から,CPUロック状態で呼ばれる. この関数が呼ばれると,関数を呼んだタスクのコンテキストを保存せず,実行 できるタスクの中で最高優先順位のタスク(schedtsk)のコンテキストを復帰 して実行状態とする.実行できるタスクがない場合(schedtsk が NULL の場 合)の処理は,dispatch と同様である. 新たに実行状態になったタスクが,タスク例外処理ルーチンの起動条件を満た していれば,タスク例外処理ルーチンを起動する. この関数は,カーネルの初期化処理からも呼ばれるために,非タスクコンテキ ストからも呼ばれても正しく処理できることが必要である.なお,この関数か らはリターンしない. (5) 割込みハンドラ/CPU例外ハンドラの出入口処理 (5-1) INTHDR_ENTRY(inthdr) (5-2) INT_ENTRY(inthdr) INTHDR_ENTRY(inthdr) は起動番地が inthdr の割込みハンドラを呼び出す出 入口処理ルーチンを生成するマクロ,INT_ENTRY(inthdr) は生成する出入口処 理ルーチンの先頭のラベルを得るためのマクロである.INT_ENTRY(inthdr) で 得られるラベルは,割込みハンドラ初期化ブロックに出入口処理ルーチンの先 頭番地を登録するために使われる.出入口処理ルーチンを生成する必要がない 場合には,INTHDR_ENTRY(inthdr) を単に extern 宣言に展開すればよい. 割込みハンドラの出入口処理は,実行コンテキストを非タスクコンテキストに 切り換え,スクラッチレジスタを保存して,割込みハンドラを呼び出す.割込 みハンドラから戻ると,元の実行コンテキストに戻すとともに,必要に応じて ディスパッチとタスク例外処理ルーチンの起動処理を行う.ディスパッチとタ スク例外処理ルーチンの起動処理は,具体的には次のように行う. (a) 以下の処理は,割込みハンドラがタスクコンテキスト実行中に起動された 場合で,reqflg が TRUE の時のみ行う. (b) enadsp が TRUE で,実行状態のタスク(runtsk)と実行できるタスクの 中で最高優先順位のタスク(schedtsk)が一致していない場合には,前者のタ スクのコンテキストを保存し,後者のタスクのコンテキストを復帰して実行状 態とする.実行できるタスクがない場合(schedtsk が NULL の場合)には, 割込みを許可して,実行できるタスクができるまで待つ.ここでも,実行でき るタスクができるのを待つ間に起動された割込みハンドラの出口で,タスクディ スパッチャが呼ばれないようにすることが必要であるが,出入口処理を非タス クコンテキストで実行していれば,特に対策する必要はない. (c) 実行状態のタスク((b) でタスクディスパッチを行った場合は,新たに実 行状態となったタスク)がタスク例外処理ルーチンの起動条件を満たしていれ ば,タスク例外処理ルーチンを起動する.また,(b) でタスクディスパッチを 行った場合は,それまで実行状態であったタスクが次に実行状態になった時, タスク例外処理ルーチンの起動条件を満たしていれば,タスク例外処理ルーチ ンの起動を行う.タスク例外処理ルーチンの起動には,ターゲット非依存部が 提供する calltex または call_texrtn を用いることができる. このマクロで生成するルーチンでは,上記の処理の一部のみを行い,残りの処 理は別に用意したルーチンに任せてもよい.具体的には,タスクディスパッチ とタスク例外処理ルーチンの起動処理は,別にルーチンとして用意するのが適 当であろう. (5-3) EXCHDR_ENTRY(exchdr) (5-4) EXC_ENTRY(exchdr) EXCHDR_ENTRY(exchdr) は起動番地が exchdr のCPU例外ハンドラを呼び出す出 入口処理ルーチンを生成するマクロ,EXC_ENTRY(exchdr) は生成する出入口処 理ルーチンの先頭のラベルを得るためのマクロである.EXC_ENTRY(exchdr) で 得られるラベルは,CPU例外ハンドラ初期化ブロックに出入口処理ルーチンの 先頭番地を登録するために使われる.出入口処理ルーチンを生成する必要がな い場合には,EXCHDR_ENTRY(exchdr) を単に extern 宣言に展開すればよい. CPU例外ハンドラの出入口処理は,実行コンテキストを非タスクコンテキスト に切り換え,スクラッチレジスタを保存して,CPU例外ハンドラを呼び出す. CPU例外ハンドラには,VP型のパラメータ p_excinf を渡す.このパラメータ は,CPU例外に関する情報を保存したスタック領域へのポインタであることを 想定しているが,具体的にはターゲット毎に定める. CPU例外ハンドラから戻ると,元の実行コンテキストに戻すとともに,必要に 応じてタスクディスパッチとタスク例外処理ルーチンの起動処理を行う.タス クディスパッチとタスク例外処理ルーチンの起動処理は,割込みハンドラの出 入口処理の場合と同様である(上記の (a)〜(c)). (6) タスクコンテキスト設定処理(cpu_context.h) ターゲット依存のタスクコンテキストを設定するために create_context と activate_context の2つの関数を用意する.2つの関数を呼び出すことで,タ スクのコンテキスト(具体的には,タスクコンテキストブロックの内容とタス クのスタック領域)をタスクが起動できる状態に設定する.2つの関数は呼ば れるタイミングが異なるだけで明確な役割分担はなく,どのような処理はどち らの関数で行わなければならないという制約はない. これらの関数の宣言およびマクロの定義は,cpu_context.h に含める.これは, cpu_config.h を処理する時点では TCB が定義されていないためである. (6-1) void create_context(TCB *tcb) タスクが休止状態に移行する時に呼ばれる.具体的には,タスクの生成時 (JSPカーネルでは,CRE_TSK でタスクを生成するため,タスク管理モジュー ルの初期化)とタスクの終了時(ext_tsk,ter_tsk)に呼ばれる. (6-2) void activate_context(TCB *tcb) タスクが実行できる状態に移行する時に呼ばれる.具体的には,act_tsk でタ スクを起動する時,タスクの終了時(ext_tsk,ter_tsk)に起動要求のキュー イングにより再起動する時,TA_ACT 属性を指定してタスクを生成した時(タ スク管理モジュールの初期化)に呼ばれる. (6-3) ACTIVATED_STACK_SIZE(オプション) ext_tsk がスタック上に確保するダミー領域のサイズを定義するためのマクロ. ダミー領域が必要ない場合は,このマクロを定義する必要はない. ext_tsk は,自タスクを終了させた後,自タスクに対して create_context を 呼ぶ.また,タスクの起動要求がキューイングされていた場合には,自タスク に対して activate_context も呼ぶ.create_context と activate_context は,対象タスクのスタック領域を書き換える場合があるが,これが ext_tsk (およびそこから呼ばれる関数)が使用しているスタック領域と重なった場合, 自分の使用しているスタック領域を自分で破壊する結果になる. ACTIVATE_STACK_SIZE を,create_context と activate_context が書き換え るスタック領域のサイズ(厳密には,スタックの底から何バイトめまでを書き 換えるか)にマクロ定義しておくと,ext_tsk 内でスタック上に定義したサイ ズのダミー領域を確保し,自分の使用しているスタック領域を破壊するのを防 ぐ. なお,これを実現するために,処理系依存の機能である alloca を用いている. gcc は alloca をサポートしているが,他のコンパイラを用いる場合には, alloca をサポートしているか確認が必要である.また,alloca を用いる場合 にインクルードファイルが必要な場合には,tool_config.h からインクルード する必要がある. (7) ターゲット依存の初期化/終了処理 (7-1) void cpu_initialize(void) プロセッサ依存の初期化処理.カーネルの初期化処理で,カーネル内の各モジュ ールを初期化する前に呼ばれる. (7-2) void sys_initialize(void) システム依存の初期化処理.カーネルの初期化処理で,cpu_initialize に続 いて呼ばれる. (7-3) void tool_initialize(void) 開発環境依存の初期化処理.カーネルの初期化処理で,sys_initialize に続 いて呼ばれる. 上の3つの関数は,カーネル起動処理(kernel_start 関数)の最初でこの順に 呼び出される.3つの関数を呼び出した後の時点で,CPUロック状態になってい なければならない. (7-4) void cpu_terminate(void); プロセッサ依存の終了時処理.カーネルの終了処理で呼ばれる. (7-5) sys_exit(void) システムの終了処理.カーネルの終了処理で,cpu_terminate に続いて呼ばれ る.この関数からはリターンしない.ROMモニタを持つシステムでは,ROMモニ タ呼出しで実現することを想定している. (7-6) call_atexit(void) 開発環境依存の終了処理.必要に応じて,atexit によって登録された関数の 実行や C++ におけるデストラクタの実行を行う. (8) 割込みハンドラ/CPU例外ハンドラの定義 (8-1) void define_inh(INHNO inhno, FP inthdr) 割込みハンドラ番号 inhno の起動番地を inthdr に設定する.割込み管理機 能の初期化処理から呼ばれる. (8-2) void define_exc(EXCNO excno, FP exchdr) CPU例外ハンドラ番号 excno の起動番地を exchdr に設定する.CPU例外ハン ドラ管理機能の初期化処理から呼ばれる. (9) CPU例外発生時点のシステム状態の参照 (9-1) BOOL exc_sense_context(VP p_excinf) CPU例外が発生したコンテキストが,タスクコンテキストの場合は FALSE,非 タスクコンテキストの場合は TRUE を返す関数.CPU例外ハンドラから呼ばれ たサービスコール処理から呼ばれる.p_excinf には,CPU例外ハンドラへの引 数がそのまま渡される. (9-2) BOOL exc_sense_lock(VP p_excinf) CPU例外が発生したコンテキストが,CPUロック状態の場合は TRUE,CPUロック 解除状態の時は FALSE を返す関数.CPU例外ハンドラから呼ばれたサービスコ ール処理から呼ばれる.p_excinf には,CPU例外ハンドラへの引数がそのまま 渡される. (10) TCB 中のフィールドのビット幅の定義(オプション) TCB 中のフィールドの配置は性能に大きく影響すると思われるため,ターゲッ ト依存にフィールドのビット幅を変更できるようにしている.具体的には,以 下の2つのフィールドのビット幅を変更できる.これらのマクロを定義しない 場合,最小ビット幅となる. (10-1) TBIT_TCB_TSTAT tstat(タスク状態)のビット幅 (10-2) TBIT_TCB_PRIORITY priority(優先度)フィールドのビット幅 32ビットプロセッサの場合には,これらを 8 に定義するのが効率的である. (11) ビットマップサーチにビットサーチ命令を使うための定義(オプション) プロセッサがビットサーチ命令を持つ場合,レディキューのビットマップサー チにその命令を用いた方が効率がよい.その場合,以下の関数およびマクロを ターゲット依存部で定義する. (11-1) CPU_BITMAP_SEARCH プロセッサのビットサーチ命令を用いる場合,このマクロを定義する.このマ クロを定義することにより,ターゲット非依存部から bitmap_search が取り 除かれる. (11-2) UINT bitmap_search(UINT bitmap) ビットサーチを行う関数.bitmap 内の 1 のビットの内,最も下位のものをサ ーチし,そのビット番号を返す.ビット番号は,最下位ビット(LSB)を 0 と する.bitmap の下位16ビットに,必ず 1 のビットがある(すなわち,bitmap に 0 が指定されることはない)ことを仮定してよい. 標準ライブラリにビットサーチ命令を用いた ffs がある場合,ffs を用いて bitmap_search を次のように定義すればよい. #define bitmap_search(bitmap) (ffs(bitmap) - 1) プロセッサの持つビットサーチ命令が,最も上位の 1 のビットをサーチする ものである場合には,次のマクロを定義して,ビットの割付けを変更すること ができる. (11-3) UINT PRIMAP_BIT(pri) タスク優先度の内部表現(最高優先度を 0 とする)を,それに対応するビッ トマップに変換する.デフォルトの定義は次の通り. #define PRIMAP_BIT(pri) (1 << (pri)) (12) ターゲット依存のサービスコール(オプション) 以下のサービスコールをターゲット依存にサポートする場合には,その処理ル ーチンをターゲット依存部で定義する. (12-1) chg_ixx (12-2) get_ixx (12-3) dis_int (12-4) ena_int (13) 性能評価用システム時刻関連の定義(オプション) (13-1) SUPPORT_VXGET_TIM ターゲット非依存部の vxget_timサービスコール処理を用いる場合に,このマ クロを定義する. (13-2) hw_timer.h ターゲット依存のタイマモジュールのインクルードファイル.ターゲット非依 存部の vxget_timサービスコール処理を用いる場合,ターゲット依存のタイマ モジュールが必要になる.そのためのインクルードファイルである hw_timer.h は,システムサービスのシステムクロックドライバで用いるもの と共通にしている. (14) カーネルの内部識別名のリネームとその解除(cpu_rename.h, cpu_unrename.h,sys_rename.h,sys_unrename.h) ターゲット依存部で用いている識別名(モジュール内に閉じた識別名を除く) を,μITRON4.0仕様に従って _kernel_ で始まるものにリネームする必要があ る. 具体的には,プロセッサ依存部で用いている識別子をリストアップしたファイ ルを cpu_rename.def に,システム依存部で用いている識別子をリストアップ したファイルを sys_rename.def に作成する.genrename 使って,これらのファ イルから,それぞれ cpu_rename.h と cpu_unrename.h,sys_rename.h と sys_unrename.h を生成する.xxx_rename.def から xxx_rename.h と xxx_unrename.h を生成するには,「$(KERNEL_DIR)/utils/genrename xxx」を 実行すればよい. また,cpu_config.h の先頭から cpu_rename.h を,sys_config.h の先頭から sys_rename.h をインクルードする. genrename が生成するファイルは次のような内容である.xxx_rename.def に xxxx という識別子が含まれている場合,xxx_rename.h には次のようなマクロ 定義が生成される. #define xxxx _kernel_xxxx #ifdef LABEL_ASM #define _xxxx __kernel_xxxx #endif /* LABEL_ASM */ ここで,LABEL_ASM は,アセンブリ言語レベルの識別名が,C言語レベルの識 別名の先頭に "_" が付いたものになる場合に定義すべきマクロである(定義 の方法については「システム構築方法の設定」を参照). また,xxx_unrename.h には次のようなマクロ定義解除が生成される. #undef xxxx #ifdef LABEL_ASM #undef _xxxx #endif /* LABEL_ASM */ (15) トレースログのためのマクロ定義(tool_config.h) カーネルのトレースログの取得は,開発環境依存部でトレースログのためのマ クロを定義することによって行う.トレースログのためのマクロは約150種類 あり,取得したいログ情報に対応するマクロを定義する.トレースログを取得 しない場合には,これらのマクロを空に定義すればよい. (16) その他 (16-1) TARGET_NAME 起動メッセージのターゲット名. (16-2) void sys_putc(char c) ターゲットシステムの低レベルの文字出力ルーチン.ROMモニタを持つシステ ムでは,ROMモニタ呼び出しで実現することを想定している. (16-3) OMIT_CALLTEX(オプション) ターゲット非依存部が calltex を提供する必要がない場合に,このマクロを 定義する.詳しくは,「タスク例外処理ルーチンの起動関数とその中で参照す る TCB のフィールド」の節を参照のこと. (16-4) LABEL_ALIAS(new_label, defined_label)(オプション,tool_config.h) new_label を defined_label と同じアドレスに定義するためのマクロ.この ようなマクロを実現できない場合には,定義を省略することができる.このマ クロ定義は,tool_config.h の中で行うのを標準とする. (16-5) COPYRIGHT_CPU(オプション) (16-6) COPYRIGHT_SYS(オプション) カーネル起動時のメッセージに,それぞれプロセッサ依存部およびシステム依 存部の著作権表示を追加するためのマクロ. (16-7) __STK_UNIT(オプション) (16-8) __MPF_UNIT(オプション) 標準では,スタック領域と固定長メモリプール領域は,VP型のサイズにアライ ンする.これを,より大きい単位でアラインさせる必要がある場合には, __STK_UNIT と __MPF_UNIT を,それぞれアラインさせる単位のデータ型に定 義する.ただし,__STK_UNIT および __MPF_UNIT のサイズは,2の巾乗でなけ ればならない. (16-9) __EMPTY_LABEL(x, y)(オプション,tool_config.h) 型 x のサイズ 0 の配列 y を定義するためのマクロ.サイズ 0 の配列を定義 できるコンパイラ(GNU開発環境はこれに該当)では定義を省略することがで きる.このマクロ定義は,tool_config.h の中で行うのを標準とする. 4.ターゲット依存部が用いることができるターゲット非依存部の変数・関数 (1) タスク管理関連の変数 (1-1) TCB *runtsk 実行状態のタスク(=プロセッサがコンテキストを持っているタスク)の TCB を指すポインタ.実行状態のタスクがない場合は NULL にする.サービスコー ルの処理中で,自タスク(サービスコールを呼び出したタスク)に関する情報 を参照する場合は runtsk を使う.カーネルの初期化処理以外で,この変数を 書き換えるのは,タスクディスパッチャ(すなわち,ターゲット依存部)のみ である. (1-2) TCB *schedtsk 実行できるタスクの中で最高優先順位のタスクの TCB を指すポインタ.実行 できるタスクがない場合は NULL となる.ディスパッチ禁止状態など,ディス パッチが保留されている間は,runtsk と一致しているとは限らない.この変 数を書き換えるのはスケジューラのみで,ターゲット依存部はこの変数を書き 換えてはならない. (1-3) BOOL reqflg 割込みハンドラ/CPU例外ハンドラの出口処理に,タスクディスパッチまたは タスク例外処理ルーチンの起動を要求することを示すフラグ.この変数はサー ビスコール処理(ターゲット非依存部)でセットし,割込みハンドラ/CPU例 外ハンドラの出口処理(ターゲット依存部)で参照/クリアする. (1-4) BOOL enadsp タスクディスパッチ許可状態である(すなわち,タスクディスパッチ禁止状態 でない)ことを示すフラグ.この変数はサービスコール(dis_dsp,ena_dsp, ターゲット依存に chg_ixx)処理の中で書き換える. また,タスクディスパッチャ(ターゲット依存部)の中で,実行できるタスク ができるのを待つ間に起動された割込みハンドラの出口でタスクディスパッチャ が呼ばれないようにするために,この変数を一時的に FALSE に設定すること ができる. (2) タスク例外処理ルーチンの起動関数とその中で参照する TCB のフィールド (2-1) void calltex(void) (2-2) void call_texrtn(void) タスク例外処理ルーチンの起動を行う関数.calltex は,実行状態のタスクが タスク例外処理ルーチンの起動条件を満たしていれば,call_texrtn を呼び出 す.call_texrtn は,タスク例外処理ルーチンの呼び出しを行う.タスク例外 処理ルーチンを呼び出す時は,一時的にCPUロックを解除する. これらの関数は,ディスパッチャや割込みハンドラ/CPU例外ハンドラの出口 処理から,CPUロック状態で呼ばれることを想定している.calltex を呼び出 すのが最も簡単であるが,実行効率を上げるためには,起動条件のチェックを アセンブリ言語で記述し,call_texrtn を呼び出した方がよい.チェックすべ き起動条件については,ターゲット非依存部の calltex のソースコードを参 照すること.またその場合には,OMIT_CALLTEX をマクロ定義することで,タ ーゲット非依存部から calltex が取り除かれる. (2-3) BOOL enatex (2-4) TEXPTN texptn call_texrtn を呼び出すために,起動条件のチェックをアセンブリ言語で記述 する場合には,TCB 内のこれらのフィールドを参照する必要がある. (3) システムログ機能 異常事象を通知するために,システムログ機能へのログ出力関数を用いること ができる.システムログ機能については,ユーザズマニュアルを参照すること. 5.システムサービス用のデータ型や関数など 5.1 システムインタフェースレイヤ(SIL)のための定義 ターゲット依存部で提供すべきシステムインタフェースレイヤ(SIL)のため の定義は次の通りである.これらの定義は,cpu_defs.hまたはsys_defs.h(ま たはそれらからインクルードされるファイル)に含める.また,関数の実体が 必要な場合,C言語の場合はcpu_config.cまたはsys_config.cに,アセンブリ 言語の場合はcpu_support.Sまたはsys_support.Sに記述する. (1) 微少時間待ち関連 (1-1) void sil_dly_nse(UINT dlytim) dlytimで指定される時間(単位: 1ナノ秒)待つ関数をターゲット依存部で提 供する. 実現方法はターゲット依存であるが,以下の関数をアセンブリ言語で記述した ものを,プロセッサ依存部に含めるのを標準的な方法とする.アセンブリ言語 で記述するのは,コンパイラの最適化に依存しないようにするためである.ま たこの関数は,できる限りメモリアクセスを行わないように実装すべきである. void sil_dly_nse(UINT dlytim) { if (dlytim > SIL_DLY_TIM1) { dlytim -= SIL_DLY_TIM1; while (dlytim > SIL_DLY_TIM2) { dlytim -= SIL_DLY_TIM2; } } } (1-2) SIL_DLY_TIM1(オプション) (1-3) SIL_DLY_TIM2(オプション) sil_dly_nseを上記の標準的な方法で実現した場合,この2つの定数をシステム 依存部でマクロ定義する.なお,この2つの定数の決定を助けるプログラムを 用意している.希望される方は,相談されたい. (2) 割込みロック状態の制御関連(オプション) (2-1) SIL_PRE_LOC (2-2) SIL_LOC_INT() (2-3) SIL_UNL_INT() ターゲット依存で割込みロック状態の制御方法を変更したい場合には,これら のマクロにその方法を定義する.これらマクロを定義しない場合には, ター ゲット非依存部において,カーネルのCPUロックの機能を用いて割込みロック 状態が実現される. (3) プロセッサのエンディアンの定義 (3-1) SIL_ENDIAN リトルエンディアンプロセッサではSIL_ENDIAN_LITTLE(=0),ビッグエンディ アンプロセッサではSIL_ENDIAN_BIG(=1)にマクロ定義する. (4) エンディアンの反転(オプション) (4-1) VH SIL_REV_ENDIAN_H(VH data) (4-2) VW SIL_REV_ENDIAN_W(VW data) エンディアンの反転を効率よく実現する方法がある場合には,これらのマクロ にその方法を定義する.これらのマクロを定義しない場合には,標準的な方法 でエンディアンの反転が行われる. (5) エンディアン反転付きのメモリ空間アクセス(オプション) エンディアンを反転してメモリを読出し/書込みする効率的な方法がある場合, 該当するメモリ空間アクセス関数をターゲット依存部で用意し,ターゲット非 依存部の標準的な定義を無効にするためのマクロを定義する. (5-1) VH sil_reh_bem(VP mem) OMIT_SIL_REH_BEM (5-2) void sil_wrh_bem(VP mem, VH data) OMIT_SIL_WRH_BEM (5-3) VW sil_rew_bem(VP mem) OMIT_SIL_REW_BEM (5-4) void sil_wrw_bem(VP mem, VW data) OMIT_SIL_WRW_BEM リトルエンディアンプロセッサでは,これらのメモリ空間アクセス関数をター ゲット依存部で用意し,右に示すマクロを定義する. (5-5) VH sil_reh_lem(VP mem) OMIT_SIL_REH_LEM (5-6) void sil_wrh_lem(VP mem, VH data) OMIT_SIL_WRH_LEM (5-7) VW sil_rew_lem(VP mem) OMIT_SIL_REW_LEM (5-8) void sil_wrw_lem(VP mem, VW data) OMIT_SIL_WRW_LEM ビッグエンディアンプロセッサでは,これらのメモリ空間アクセス関数をター ゲット依存部で用意し,右に示すマクロを定義する. (6) 標準のアクセス関数の無効化(オプション) (6-1) OMIT_SIL_ACCESS シミュレーション環境などで,すべてのメモリ空間アクセス関数をターゲット 依存部で用意する場合には,ターゲット非依存部の標準的な定義を無効にする ために,このマクロを定義する. 5.2 システムクロックドライバ用のデータ型や関数など ターゲット依存部で提供すべきシステムクロックドライバ用のデータ型や関数 などは次の通りである.これらの定義は,hw_timer.h(またはそれらからイン クルードされるファイル)に含める.関数の実体が必要な場合には,適切なファ イルを用意する. (1) INHNO_TIMER タイマ割込みハンドラのベクタ番号を定義したマクロを,ターゲット依存部で 提供する. (2) タイマの制御 (2-1) void hw_timer_initialize(void) タイマを初期化し,タイマ割込みを周期的に発生させる関数を,ターゲット依 存部で提供する.タイマ割込みの周期は,TIC_NUMEとTIC_DENOで指定された時 間と一致させる. (2-2) void hw_timer_int_clear(void) タイマ割込み要求をクリアする関数を,ターゲット依存部で提供する. (2-3) void hw_timer_terminate(void) タイマの動作を停止させ,タイマ割込みを発生しないようにする関数を,ター ゲット依存部で提供する. (3) 性能評価用システム時刻参照機能関連(オプション) ターゲット非依存部のvxget_timサービスコール処理を用いる場合に,以下の データ型や関数などをターゲット依存部で提供する. (3-1) CLOCK タイマ値の内部表現のためのデータ型. (3-2) CLOCK hw_timer_get_current(void) タイマの現在値を読み出し,内部表現で返す関数. (3-3) BOOL hw_timer_fetch_interrupt(void) タイマ割込み要求をチェックする関数.タイマ割込みが要求されている場合に TRUE,要求されていない場合にFALSEを返す. (3-4) UINT TO_USEC(CLOCK clock) タイマ値の内部表現を,1μ秒単位に変換するためのマクロ(または関数). hw_timer_get_currentで読み出した値を,タイマ割込み発生からの経過時間 (単位: 1μ秒)に変換するために用いる. (3-5) BOOL BEFORE_IREQ(CLOCK clock) 割込みを禁止した状態で,まずhw_timer_get_currentを呼び出し,続いて hw_timer_fetch_interruptを呼び出す場合を考える.hw_timer_get_current を呼び出した直後にタイマが周期に達し,タイマ割込みが要求されると, hw_timer_get_currentは周期に達する直前のタイマ値(これを,clockとする) を返し,hw_timer_fetch_interruptがTRUEを返すことになる.この状況でも正 しい現在時刻を得るために,clockがある一定値以上の場合には, hw_timer_fetch_interruptがTRUEを返しても,割込み発生前の値とみなすこと にする.BEFORE_IREQは,clockが割込み発生前の値とみなすべき場合にTRUEを, そうでない場合にFALSEを返すマクロ(または関数)である. 5.3 シリアルインタフェースドライバ用のデータ型や関数など ターゲット依存部で提供すべきシリアルインタフェースドライバ用のデータ型 や関数などは次の通りである.これらの定義は,別に記述がない限り, hw_serial.h(またはそこからインクルードされるファイル)に含め,必要な コンフィギュレーション情報をhw_serial.cfgに記述する.関数の実体が必要 な場合には,適切なファイルを用意する. シリアルインタフェースドライバの中で,ターゲットのシリアルI/Oデバイス に依存する部分を,シリアルI/Oデバイスドライバと呼ぶ.シリアルI/Oデバイ スドライバは,おおよそ,ITRONデバイスドライバ設計ガイドラインのPDICに 相当する.PDICに相当するファイルで,他のシステムにも共通に使える可能性 がある場合には,pdic/simple_sioディレクトリに置く. (1) TNUM_PORT シリアルインタフェースドライバがサポートするシリアルポート数を定義する マクロ.このマクロは,cpu_config.hまたはsys_config.h(またはそれらから インクルードされるファイル)で定義する. (2) シリアルI/Oデバイスの割込みハンドラとその登録 シリアルI/Oデバイスの割込みハンドラをターゲット依存部で提供し,それを カーネルに登録する静的APIをhw_serial.cfgに含める.シリアルI/Oデバイス の割込ハンドラのベクタ番号は,hw_serial.h(またはそこからインクルード されるファイル)でマクロ定義し,hw_serial.cfgからhw_serial.hをインクル ードする方法を標準とする. (3) void sio_initialize(void) シリアルI/Oデバイスドライバを初期化するルーチン.この関数は,シリアル インタフェースドライバのターゲット非依存部の初期化ルーチンから呼び出さ れる. (4) SIOPCB シリアルI/Oポート管理ブロックのデータ型(hw_serial.hには,型宣言だけ含 まれていればよい). (5) SIO_ERDY_SNDとSIO_ERDY_RCV 送信可能コールバックの識別番号をSIO_ERDY_SNDに,受信通知コールバックの 識別番号をSIO_ERDY_RCVにマクロ定義する.コールバックの禁止/許可を行な うサービスコール(sio_ena_cbrとsio_dis_cbr)で用いる. (6) デバイスサービスルーチン 以下のデバイスサービルルーチンは,(少なくとも)シリアルI/Oポートから の割込みが禁止された状態で呼び出される.また,タスクコンテキスト,非タ スクコンテキストのいずれで呼び出される場合もある(いずれで呼び出されて も動作するようにしなければならない). (6-1) SIOPCB *sio_opn_por(ID siopid, VP_INT exinf) siopidで指定されるシリアルI/Oポートをオープンする関数.exinfはシリアル I/Oポートに対する拡張情報で,コールバックを呼ぶ時にポートを区別するた めに渡す. (6-2) void sio_cls_por(SIOPCB *siopcb) siopcbで指定されるシリアルI/Oポートをクローズする関数. (6-3) BOOL sio_snd_chr(SIOPCB *siopcb, char c) siopcbで指定されるシリアルI/Oポートに,cで示される文字を送信する関数. 文字を送信レジスタに入れた場合にはTRUEを,前に送信した文字の送信が終わっ ていないために,文字を送信レジスタに入れられなかった場合にはFALSEを返 す. (6-4) INT sio_rcv_chr(SIOPCB *siopcb) siopcbで指定されるシリアルI/Oポートから文字を読む関数.文字を受信して いた場合,読んだ文字のコードは正の値として返し,文字を受信していない場 合には-1を返す. (6-5) sio_ena_cbr(SIOPCB *siopcb, UINT cbrtn) siopcbで指定されるシリアルI/Oポートからの,cbrtnで指定されるコールバッ クを許可する.cbrtnには,SIO_ERDY_SNDかSIO_ERDY_RCVを指定できる. (6-6) sio_dis_cbr(SIOPCB *siopcb, UINT cbrtn) siopcbで指定されるシリアルI/Oポートからの,cbrtnで指定されるコールバッ クを禁止する.cbrtnには,SIO_ERDY_SNDかSIO_ERDY_RCVを指定できる. (7) コールバックルーチン ターゲット依存部は,必要なタイミングで,シリアルインタフェースドライバ のターゲット非依存部に含まれる以下のコールバックルーチンを呼び出びださ なければならない.ただし,それぞれのコールバックが禁止されている時は, コールバックルーチンを呼び出してはならない. コールバックルーチンは,(少なくとも)シリアルI/Oポートからの割込みが 禁止された状態で,非タスクコンテキストで呼び出す.exinfには,シリアル I/Oポートのオープン時に指定された拡張情報を渡す. (7-1) void sio_ierdy_snd(VP_INT exinf) 送信可能コールバックルーチン.シリアルI/Oポートに対して文字が送信でき る状態になった場合に呼び出す.シリアルインタフェースドライバは,このコ ールバックルーチンの中で,sio_snd_chrを呼び出して次の文字を送信するか, 送信すべき文字がない場合には送信可能コールバックを禁止する. (7-2) void sio_ierdy_rcv(VP_INT exinf) 受信通知コールバックルーチン.シリアルI/Oポートから文字を受信した場合 に呼び出す.シリアルインタフェースドライバは,このコールバックルーチン の中で,必ずsio_rcv_chrを呼び出して受信した文字を取り出す. 5.4 システムログタスク用のための定義 ターゲット依存部で提供すべきシステムログタスクのための定義は次の通りで ある.これらの定義は,cpu_config.hまたはsys_config.h(またはそれらから インクルードされるファイル)に含める. (1) LOGTASK_PORTID システムログタスクが,システムログを出力するシリアルポートのIDを定義し たマクロをターゲット依存部で提供する. (2) システムログタスク関連の定義(オプション) システムログタスクに関する以下のマクロをターゲット依存部で提供する.こ れらのマクロをターゲット依存部で定義しない場合には,デフォルトの値が使 われる. (2-1) LOGTASK_PRIORITY システムログタスクの初期優先度 (2-2) LOGTASK_STACK_SIZE システムログタスクのスタックサイズ (2-3) LOGTASK_INTERVAL システムログタスクの動作間隔(単位: ミリ秒) 6.ターゲット依存部実装上のヒント (1) タスクディスパッチャの2通りの実装方針 タスクディスパッチャの実装方針として,コンテキストの保存・復帰とタスク 例外処理ルーチンの起動を一連のルーチンで行う方針(これを方針Aと呼ぶ) と,コンテキストの保存・実行するタスクの選択・コンテキストの復帰とタス ク例外処理ルーチンの起動をばらばらのルーチンで行う方針(これを方針Bと 呼ぶ)がある.方針Bは,保存するコンテキスト情報を状況に応じて必要最少 限にすることが容易になるという利点がある.ただし,シミュレーション環境 の場合,実現方法によっては方針Bが採れない可能性も考えられる. タスク例外処理ルーチンの起動箇所という観点からみた場合,2つの方針には 留意すべき違いがある.以下,例により説明する.タスク1とタスク2の2つの タスクがあり,タスク1の方が優先度が高いものとする.最初,タスク2が実行 中に割込みハンドラが起動され,その中からタスク1が起動された結果,タス ク2がタスク1によってプリエンプトされたものとする.ここで,タスク1がタ スク2に対してタスク例外処理ルーチンの起動を要求した後,待ち状態に入る サービスコールを発行し,その結果タスク2にディスパッチされる状況を考え る.この時,タスクディスパッチャは,タスク2に対してタスク例外処理ルー チンの起動処理を行う必要があるが,方式Aの場合には,タスク1から明示的に 呼ばれたディスパッチャの中でタスク例外処理ルーチンの起動が行われるのに 対して,方針Bの場合には,タスク2のコンテキストを復帰するルーチンへ分岐 した後,コンテキストを復帰する処理に続く処理としてタスク例外処理ルーチ ンの起動が行われる. JSPカーネルでは,方針Aを採るか方針Bを採るかをターゲット依存部に任せる こととする.そのために,タスク例外処理ルーチンの起動をタスクディスパッ チャに含める仕様としている. (2) 割込みハンドラの出入口処理 割込みハンドラの出入口処理の内容は,プロセッサの割込みアーキテクチャに より大きく異なるが,おおよその処理の流れは次の通りである.CPU例外ハン ドラの出入口処理も,引数を渡すことを除いては,おおよその処理の流れは同 様である.ただし,プロセッサが割込みとCPU例外で異なる扱いをする場合は, 実際の出入口処理はかなり異なったものとなる. ------------------------------------------------------------ レジスタの保存(主にスクラッチレジスタ) 割込みスタックへ切換え(最も外側のハンドラのみ) 登録された割込みハンドラの呼出し タスクスタックへ切換え(最も外側のハンドラのみ) if (最も外側のハンドラ && reqflg) { if (enadsp && runtsk != schedtsk) { タスクディスパッチ処理 タスク例外処理ルーチンの起動処理(calltex) } else { タスク例外処理ルーチンの起動処理(calltex) } } レジスタの復帰(主にスクラッチレジスタ) 割込み処理からのリターン ※「ハンドラ」は,割込みハンドラとCPU例外ハンドラの総称. ※「最も外側のハンドラ」は「戻り先がタスク」と言い換えることが できる. ------------------------------------------------------------ この中で,内側のif文がいずれの場合でもタスク例外処理ルーチンの起動処理 を行う必要があることから(ただし,タスク例外処理ルーチンの起動を行う対 象タスクは異なる),内側のif文は次のように最適化できる場合がある. ------------------------------------------------------------ if (enadsp && runtsk != schedtsk) { タスクディスパッチ処理 } タスク例外処理ルーチンの起動処理(calltex) ------------------------------------------------------------ 7.M68K(68LC040)用のターゲット依存部 (1) 前提 すべてのタスクをスーパーバイザモードで実行することとし,ユーザモードは 用いない. (2) 実行コンテキストとCPUロック状態 タスクコンテキストはマスタモード,非タスクコンテキストは割込みモードで 実行する.sense_context は,SR 中のマスタ/割込みモードビットを参照す る方法で実現する. IPM が 7 の時(NMI を除くすべての割込みが禁止される)かつその時に限り, CPUロック状態であるものとする.sense_lock は,SR 中の IPM を参照する方 法で実現する.NMI はカーネルの管理外の割込みなので,CPUロック状態で NMI が受け付けられるのは差し支えない. chg_ipm をサポートするかどうかを,SUPPORT_CHG_IPM を定義するかどうかで 変更できる.タスクコンテキストで IPM を変更する場合には,chg_ipm を使 わなければならない.chg_ipm をサポートしない場合には,タスクコンテキス トで IPM を変更することはできない.つまり,タスクコンテキストでは,IPM は常に 0 になっている. chg_ipm をサポートする場合でも,chg_ipm を使って IPM を 7 に変更するこ とは許さない.これは,chg_ipm と loc_cpu/unl_cpu の関係が複雑になるた めである.また,IPM が 1〜6 の時にも,タスクディスパッチは保留されない. IPM は,タスクディスパッチによって,新しく実行状態になったタスクへ引き 継がれる.そのため,タスクが実行中に,別のタスクによって IPM が変更さ れる場合がある.これは,ディスパッチャを方針Bで実装する場合には素直に 実装できるが,方針Aで実装する場合にはあちこちに IPM の設定処理が入る. 方針Aで実装する場合には,IPM が 1〜6 の時にもタスクディスパッチは保留 されるとする方が楽である. (3) 割込みハンドラ出入口処理 M68K(M68020以上)では,割込みハンドラの起動によって,使用するスタック が自動的に割込みスタックへ切り換わるため,割込みスタックへの切換え処理 は必要ない.最も外側のハンドラであるかどうかは,スタック上に積まれた SR 中のマスタ/割込みモードビットを参照して判定している.タスクディス パッチとタスク例外処理ルーチンの起動処理は,ret_int ルーチンに任せてい る. reqflg をチェックする前に割込みを禁止するのは,割込みを禁止しないと, reqflg をチェックした後に起動された割込みハンドラ内でディスパッチが要 求された場合に,ディスパッチが行われないためである. interrupt_entry: movem.l %d0-%d1/%a0-%a1, -(%sp) /* スクラッチレジスタを保存 */ jsr <割込みハンドラ> /* 割込みハンドラを呼び出す */ movem.l (%sp)+, %d0-%d1/%a0-%a1 /* スクラッチレジスタを復帰 */ btst.b #4, (%sp) /* 戻り先が割込みモードなら */ jbeq 1f /* すぐにリターン */ ori.w #0x0700, %sr /* 割込み禁止 */ tst.l reqflg /* reqflg が TRUE であれば */ jbne ret_int /* ret_int へ */ 1: rte (4) CPU例外ハンドラ出入口処理 M68Kでは,CPU例外ハンドラの起動によって割込みモードへの移行はおこらず, 使用するスタックは切り換わらない.そのため,CPU例外ハンドラ内で割込み モードに切り換えている.また,最も外側のハンドラであるかどうかを判定す るために,割込みモードに切り換える前の SR をスタック上に保存する.タス クディスパッチとタスク例外処理ルーチンの起動処理は,ret_exc ルーチンに 任せている. CPU例外ハンドラへの引数は,例外スタックフレームの先頭番地(すなわち, CPU例外ハンドラの出入口処理が呼ばれた直後のスタックポインタ)としてい る. reqflg をチェックする前に割込みを禁止するのは,割込みを禁止しないと, reqflg をチェックした後に起動された割込みハンドラ内でディスパッチが要 求された場合に,ディスパッチが行われないためである. exception_entry: movem.l %d0-%d1/%a0-%a1, -(%sp) /* スクラッチレジスタを保存 */ lea.l 16(%sp), %a0 /* 例外フレームの先頭を A0 に */ move.w %sr, %d0 /* SR を D0 に */ and.w #~0x1000, %sr /* 割込みモード */ move.l %d0, -(%sp) /* 元の SR をスタックに保存 */ move.l %a0, -(%sp) /* A0 を引数として渡す */ jsr /* CPU例外ハンドラを呼び出す */ addq.l #4, %sp /* 引数を捨てる */ move.l (%sp)+, %d0 and.w #0x1000, %d0 /* 元が割込みモードなら */ jbeq 1f /* すぐにリターン */ or.w #0x1700, %sr /* マスタモード・割込み禁止 */ tst.l reqflg /* reqflg が TRUE であれば */ jbne ret_exc /* ret_exc へ */ 1: movem.l (%sp)+, %d0-%d1/%a0-%a1 /* スクラッチレジスタを復帰 */ rte (5) 方針Aのディスパッチャ 以下のコードでは,chg_ipm はサポートしていない.また,採用しなかったコ ートであるため,動作テストをしていない. CTXB は「VP msp」のみを含む構造体とする.タスクのコンテキストは,次の 図のようにタスクのスタック上に保存する.スクラッチレジスタ(D0〜D1,A0 〜A1)とその他のレジスタを別々に積むのは,タスク例外処理ルーチンの起動 に都合がよいためである. * 小 +-----------------------------------+ ← TCB 中に保存されている MSP * ↑ | D2 | * +-----------------------------------+ * . . . . . . * +-----------------------------------+ * | D7 | * +-----------------------------------+ * | A2 | * +-----------------------------------+ * . . . . . . * +-----------------------------------+ * | A6 | * +-----------------------------------+ * | D0 | * +-----------------------------------+ * | D1 | * +-----------------------------------+ * | A0 | * +-----------------------------------+ * | A1 | * +-----------------+-----------------+ * | SR | PC (上16bit) | * +-----------------+-----------------+ * ↓ | PC (下16bit) | 例外情報 | * 大 +-----------------+-----------------+ ← ディスパッチャ起動前の MSP dispatch は,trap_dispatch を TRAP命令で呼ぶ関数とする. exit_and_dispatch: or.w #0x1000, %sr /* マスタモード */ jbra dispatch_1 trap_dispatch: movem.l %d0-%d1/%a0-%a1, -(%sp) /* スクラッチレジスタを保存 */ movem.l %d2-%d7/%a2-%a6, -(%sp) /* 残りのレジスタを保存 */ move.l runtsk, %a0 /* コンテキストを保存 */ move.l %sp, TCB_msp(%a0) dispatch_1: move.l schedtsk, %a0 move.l %a0, runtsk /* schedtsk を runtsk に */ jbeq dispatch_3 /* schedtsk があるか? */ move.l TCB_msp(%a0), %sp /* コンテキストを復帰 */ movem.l (%sp)+, %d2-%d7/%a2-%a6 /* レジスタを復帰 */ btst.b #TCB_enatex_bit, TCB_enatex(%a0) jbeq dispatch_2 /* enatex が FALSE ならリターン */ tst.l TCB_texptn(%a0) /* texptn が 0 ならリターン */ jbeq dispatch_2 jsr call_texrtn /* タスク例外処理ルーチンの呼出し */ dispatch_2: movem.l (%sp)+, %d0-%d1/%a0-%a1 /* スクラッチレジスタを復帰 */ rte dispatch_3: stop #0x2000 /* 割込み待ち(割込みモード) */ /* * ここで割込みモードに切り換えるのは,ここで発生する割込み処理 * にどのスタックを使うかという問題の解決と,割込みハンドラ内で * のタスクディスパッチの防止という2つの意味がある. */ or.w #0x1700, %sr /* マスタモード・割込み禁止 */ tst.l reqflg /* reqflg が FALSE なら */ jbeq dispatch_3 /* dispatch_3 へ */ clr.l reqflg /* reqflg をクリア */ jbra dispatch_1 ret_int: /* * ここでは,割込みモード・割込み禁止状態. */ move.l %a1, -(%sp) /* A1 を割込みスタックに保存 */ movec.l %msp, %a1 /* タスクスタックを A1 に */ move.l (%sp)+, -(%a1) /* A1 をタスクスタックに積む */ movem.l %d0-%d1/%a0, -(%a1) /* スクラッチレジスタを積む */ clr.l reqflg /* reqflg をクリア */ move.l runtsk, %a0 /* A0 ← runtsk */ tst.l enadsp /* enadsp が FALSE なら */ jbeq ret_int_3 /* ret_int_3 へ */ cmp.l schedtsk, %a0 /* runtsk と schedtsk が同じなら */ jbeq ret_int_3 /* ret_int_3 へ */ /* ディスパッチ処理 */ movem.l %d2-%d7/%a2-%a6, -(%a1) /* レジスタを保存 */ move.l %a1, TCB_msp(%a0) /* タスクスタックを保存 */ ret_int_1: move.l schedtsk, %a0 move.l %a0, runtsk /* schedtsk を runtsk に */ jbne ret_int_2 /* schedtsk があるか? */ ret_int_1x: stop #0x2000 /* 割込み待ち(割込みハンドラ内) */ or.w #0x0700, %sr /* 割込み禁止 */ tst.l reqflg /* reqflg が FALSE なら */ jbeq ret_int_1x /* ret_int_1x へ */ clr.l reqflg /* reqflg をクリア */ jbra ret_int_1 ret_int_2: move.l TCB_msp(%a0), %a1 /* タスクスタックを A1 に */ movem.l (%a1)+, %d2-%d7/%a2-%a6 /* レジスタを復帰 */ ret_int_3: btst.b #TCB_enatex_bit, TCB_enatex(%a0) jbeq ret_int_4 /* enatex が FALSE ならリターン */ tst.l TCB_texptn(%a0) /* texptn が 0 でなければ */ jbne ret_int_5 /* ret_int_5 へ */ ret_int_4 movem.l (%a1)+, %d0-%d1/%a0 /* スクラッチレジスタを復帰 */ move.l (%a1)+, -(%sp) /* A1 を割込みスタックに保存 */ movec.l %a1, %msp /* A1 をタスクスタックに */ move.l (%sp)+, %a1 /* A1 を割込みスタックから復帰 */ rte ret_int_5: move.w 16(%a1), %d0 /* 戻り先の SR を D0 に */ move.l TCB_exinf(%a0), -(%a1) /* exinf をタスクスタックに */ move.l TCB_texptn(%a0), -(%a1) /* texptn をタスクスタックに */ move.l #ret_tex, -(%a1) /* #ret_tex をタスクスタックに */ clr.l TCB_enatex(%a0) /* runtsk->enatex をクリア */ clr.l TCB_texptn(%a0) /* runtsk->texptn をクリア */ move.w #例外情報, -(%a1) /* 例外スタックフレームを作る */ move.l TCB_texrtn(%a0), -(%a1) move.w %d0, -(%a1) movec.l %a1, %msp /* A1 をタスクスタックに */ rte タスク例外処理ルーチン呼出し時のスタック * 小 +-----------------------------------+ * ↑ | ret_tex | * +-----------------------------------+ * | texptn | * +-----------------------------------+ * | exinf | * +-----------------------------------+ * | D0 | * +-----------------------------------+ * | D1 | * +-----------------------------------+ * | A0 | * +-----------------------------------+ * | A1 | * +-----------------+-----------------+ * | SR | PC (上16bit) | * +-----------------+-----------------+ * ↓ | PC (下16bit) | 例外情報 | * 大 +-----------------+-----------------+ ret_tex: addq.l #8, %sp /* 引数エリアを捨てる */ or.w #0x0700, %sr /* 割込み禁止 */ jsr call_texrtn /* タスク例外処理ルーチンの起動 */ movem.l (%sp)+, %d0-%d1/%a0-%a1 /* スクラッチレジスタを復帰 */ rte (6) 方針B(採用) ソースコードを参照. 8.ターゲット依存部実装上の注意点 以下は,ターゲット依存部を実装する上でミスしがちな点をリストアップした ものである. (1) タスク終了時 ext_tsk を呼ばずにタスクのメイン関数からリターンした場合,ext_tsk を呼 び出したのと同等の処理を行うようにしなければならない.タスク起動時に, メイン関数からのリターンアドレスを ext_tsk の番地に設定しておく方法を 推奨する. (2) タスクコンテキストでの割込みマスクの変更 chg_iXX をサポートする場合,タスク切替えの際に,chg_iXX によって設定し た割込みマスクの値(タスクコンテキストにおける割込みマスクの値)を新し いタスクに引き継ぐことを推奨する.特に,割込みの出口でタスク切替えを行 う箇所は注意が必要である.具体的には,以前に同じタスクが動いていた時の 割込みマスクがスタックに積まれている場合に,これをそのまま書き戻しては ならない. (3) タスク例外処理の実行コンテキスト タスク例外処理ルーチンはタスクコンテキストで実行されるため,タスク例外 処理ルーチン実行時にはスタックポインタがタスクスタックを指している必要 がある(特に割込みの出口処理で注意すること) . (4) CPU例外ハンドラ CPU例外ハンドラ実行時は,割込みマスクの値がCPU例外発生直前と同じになる ようにすること. (5) 実行すべきタスクがない場合の処理 実行すべきタスクがない(schedtsk が NULL)場合に,プロセッサを待ちモー ド(スリープモード)に移行させる処理と,割込みを許可する処理とは,不可 分に行なう必要がある.これを不可分に行なわない場合,割込みを許可した直 後に割込みが入り,その中でタスクが実行可能状態になると,実行すべきタス クがあるにもかかわらずプロセッサが待ちモードになってしまう. また,実行すべきタスクがなく,割込みを許可して割込みを待つ間は,runtsk を NULL に設定しなければならない.このように設定しないと,割込みハンド ラから iget_tid を呼び出した際の動作が仕様に合致しなくなる(μITRON4.0 仕様では,実行状態のタスクがない場合に,iget_tid は TSK_NONE を返すこ とになっており,iget_tid のコードは,runtsk が NULL の時に TSK_NONE を 返すようになっている). m68k の実装は(config/m68k/cpu_support.S より), dispatcher: move.l schedtsk, %a0 move.l %a0, runtsk /* schedtsk を runtsk に */ jbeq dispatcher_1 /* runtsk があるか? */ となっており,schedtsk が NULL の時に,runtsk を NULL にしてから,割込 み待ちに入る.しかしながら,この処理が抜けていると,schedtsk が NULL の時には,runtsk をすぐに更新しない.そのため,実行状態のタスクがない 場合に iget_tid を呼ぶと,前に実行されていたタスクのID が返る. 以上