$ $ TOPPERS Automotive Kernel $ Toyohashi Open Platform for Embedded Real-Time Systems $ Automotive Kernel $ $ Copyright (C) 2010 by Meika Sugimoto $ $ 上記著作権者は,以下の (1)〜(4) の条件か,Free Software Foundation $ によって公表されている GNU General Public License の Version 2 に記 $ 述されている条件を満たす場合に限り,本ソフトウェア(本ソフトウェア $ を改変したものを含む.以下同じ)を使用・複製・改変・再配布(以下, $ 利用と呼ぶ)することを無償で許諾する. $ (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 $ 権表示,この利用条件および下記の無保証規定が,そのままの形でソー $ スコード中に含まれていること. $ (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 $ 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 $ 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 $ の無保証規定を掲載すること. $ (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 $ 用できない形で再配布する場合には,次のいずれかの条件を満たすこ $ と. $ (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 $ 作権表示,この利用条件および下記の無保証規定を掲載すること. $ (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに $ 報告すること. $ (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 $ 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. $ $ 本ソフトウェアは,無保証で提供されているものである.上記著作権者お $ よびTOPPERSプロジェクトは,本ソフトウェアに関して,その適用可能性も $ 含めて,いかなる保証も行わない.また,本ソフトウェアの利用により直 $ 接的または間接的に生じたいかなる損害に関しても,その責任を負わない. $ $ カーネルコンフィギュレーション定義テンプレートファイルのインクルード $INCLUDE "kernel_config.tf"$ $FILE "kernel_cfg.c"$ /*$NL$ $SPC$*$TAB$kernel_cfg.c$NL$ $SPC$*$TAB$Generated time : $+CFG_VERSION$$NL$ $SPC$*$TAB$CFG Vertion : $CFG_VERSION$$NL$ $SPC$*/$NL$ $NL$ #include "osek_kernel.h"$NL$ #include "kernel_id.h"$NL$ #include "alarm.h"$NL$ #include "interrupt.h"$NL$ #include "resource.h"$NL$ #include "task.h"$NL$ $NL$ $NL$ $ スタックサイズを計算するためのマクロ定義 #define __STK_UNIT VP$NL$ #define __TCOUNT_STK_UNIT(sz) (((sz) + sizeof(__STK_UNIT) - 1) / sizeof(__STK_UNIT))$NL$ $NL$ $ $ タスクリストの再割り当て $ $ 拡張タスクの定義の後に基本タスクを割当てなければならないため, $ TASK.ID_LISTを作りなおす. $ $TASK_LIST = {}$ $EXTTSK_LIST = {}$ $FOREACH tskid TASK.ID_LIST$ $ イベントがあれば前に代入,なければ後ろに代入 $IF LENGTH(TASK.EVENT[tskid])$ $TASK_LIST = APPEND(TASK[tskid] , TASK_LIST)$ $EXTTSK_LIST = APPEND(TASK[tskid] , EXTTSK_LIST)$ $ELSE$ $TASK_LIST = APPEND(TASK_LIST , TASK[tskid])$ $END$ $END$ $ $ ISRカテゴリ1/2のリスト作成 $ $ISR1_LIST = {}$ $ISR2_LIST = {}$ $FOREACH isrid ISR.ID_LIST$ $ CATEGORY属性で判定 $IF EQ(ISR.CATEGORY[isrid] , "1")$ $ISR1_LIST = APPEND(ISR1_LIST , ISR[isrid])$ $ELSE$ $ISR2_LIST = APPEND(ISR2_LIST , ISR[isrid])$ $END$ $END$ $ $ オブジェクト数の定義 $ /* $SPC$オブジェクト数の定義 $SPC$*/$NL$ #define$TAB$TNUM_ALARM$TAB$$TAB$$LENGTH(ALARM.ID_LIST)$$NL$ #define$TAB$TNUM_COUNTER$TAB$$LENGTH(COUNTER.ID_LIST)$$NL$ #define$TAB$TNUM_ISR2$TAB$$TAB$$LENGTH(ISR2_LIST)$$NL$ $IF EQ(OS.USERESSCHEDULER[0] , "TRUE")$ #define$TAB$TNUM_RESOURCE$TAB$$LENGTH(RESOURCE.ID_LIST) + 1$$NL$ $ELSE$ #define$TAB$TNUM_RESOURCE$TAB$$LENGTH(RESOURCE.ID_LIST)$$NL$ $END$ #define$TAB$TNUM_TASK$TAB$$TAB$$LENGTH(TASK.ID_LIST)$$NL$ #define$TAB$TNUM_EXTTASK$TAB$$LENGTH(EXTTSK_LIST)$$NL$ $NL$ const UINT8 tnum_alarm = TNUM_ALARM;$NL$ const UINT8 tnum_counter = TNUM_COUNTER;$NL$ const UINT8 tnum_isr2 = TNUM_ISR2;$NL$ const UINT8 tnum_resource = TNUM_RESOURCE;$NL$ const UINT8 tnum_task = TNUM_TASK;$NL$ const UINT8 tnum_exttask = TNUM_EXTTASK;$NL$ $NL$ $NL$ /****** Object OS ******/$NL$ $NL$ $ OSオブジェクトが複数定義されていないかのチェック $IF LENGTH(OS.ID_LIST) == 0$ $ERROR$ $FORMAT("OS Object not defined.")$ $END$ $ELSE$ $IF LENGTH(OS.ID_LIST) > 1$ $ERROR$ $FORMAT("OS Object can define once.")$ $END$ $END$ $END$ $ $ ATK1ではSTATUSはEXTENDEDしか使用できない $ (ヴィッツ製SGではエラーにしていないが,厳密にチェックをすることとした $ $IF EQ(OS.STATUS[0] , "STANDARD")$ $ERROR$ $FORMAT("Object OS parameter STATUS must set EXTENDED.")$ $END$ $END$ /****** Object TASK ******/$NL$ $NL$ $ $ リソース優先度の算出 $ $ タスクの実行時優先度を決定するために必要であるため,先に処理を行う. $ (リソースの実体の出力は後で行う) $ $ タスクの優先度に異常があるとロジック上問題があるが,タスク生成部での $ エラーチェックでエラーとなるので問題ない. $ $RESOURCE_PRIORITY = {}$ $FOREACH resid RESOURCE.ID_LIST$ $PRIORITY_MAX = 0$ $IF !EQ(RESOURCE.RESOURCEPROPERTY , "LINKED")$ $FOREACH tskid TASK_LIST$ $IF (LENGTH(FIND(TASK.RESOURCE[tskid] , resid))) && (TASK.PRIORITY[tskid] > PRIORITY_MAX)$ $PRIORITY_MAX = VALUE(FORMAT("TPRI_MINTASK + %1%" , TASK.PRIORITY[tskid]) , TASK.PRIORITY[tskid])$ $END$ $END$ $FOREACH isrid ISR.ID_LIST$ $IF (LENGTH(FIND(ISR.RESOURCE[isrid] , resid))) && ((ISR.PRIORITY[isrid] + TPRI_MINISR) > PRIORITY_MAX)$ $PRIORITY_MAX = VALUE(FORMAT("TPRI_MINISR + %1%" , ISR.PRIORITY[isrid]) , ISR.PRIORITY[isrid] + TPRI_MINISR)$ $END$ $END$ $END$ $RESOURCE_PRIORITY[resid] = PRIORITY_MAX$ $END$ $ /// LINKEDはここでなめて参照を解決して算出 $ $ タスク管理情報生成部 $ $FOREACH tskid TASK.ID_LIST$ $ タスク優先度のチェックはコンフィギュレータ側(実装部の整合性チェック)でチェック可能 $ $IF TASK.PRIORITY[tskid] > TPRI_MAXTASK$ $ $ERROR$ $ $FORMAT("Task %1%'s PRIORITY over range[%2% - %3%]" , tskid , +TPRI_MINTASK , +TPRI_MAXTASK)$ $ $END$ $ $END$ $ スタックサイズのチェック $IF (TASK.STACKSIZE[tskid] == 0) || (TASK.STACKSIZE[tskid] > UINT32_MAX)$ $ERROR$ $FORMAT("TASK %1%'s STACKSIZE over range[%2% - %3%] or '0'." , tskid , 1 , UINT32_MAX)$ $END$ $END$ $ 最大起動要求回数のチェック $IF (LENGTH(TASK.EVENT[tskid]) != 0) && (TASK.ACTIVATION[tskid] > 1)$ $ 拡張タスクは'1'でならなければならない $ERROR$ $FORMAT("Task %1%'s ACTIVATION is %2% , but because %1% is extended task , ACTIVATION must be 1." , tskid , +TASK.ACTIVATION[tskid])$ $END$ $ELSE$ $IF TASK.ACTIVATION[tskid] > UINT8_MAX$ $ 基本タスクは1-UINT8_MAX $ERROR$ $FORMAT("Task %1%'s ACTIVATION over %1% , you can set [1 - %2%]" , tskid , +UINT8_MAX)$ $END$ $END$ $END$ $ 自動起動設定のチェックはコンフィギュレータ側(実装部の整合性チェック)でチェック可能 $ イベント参照のチェックはコンフィギュレータ側(実装部の整合性チェック)でチェック可能 $ リソースはコンフィギュレータ側(実装部の整合性チェック)でチェック可能 $END$ $ $ タスク設定出力 $ $COUNT = 0$ /* タスクIDの定義 */$NL$ $FOREACH tskid TASK_LIST$ const TaskType $tskid$ = $COUNT$;$NL$ $COUNT = COUNT + 1$ $END$ $NL$ /* タスクの外部宣言の定義 */$NL$ $FOREACH tskid TASK_LIST$ extern void TASKNAME( $tskid$ )( void );$NL$ $END$ $NL$ /* スタックを共有しないタスクのスタック領域の定義 */$NL$ $FOREACH tskid TASK_LIST$ $IF EQ(TASK.SCHEDULE[tskid] , "FULL") || LENGTH(TASK.EVENT[tskid])$ static __STK_UNIT _stack_$tskid$[__TCOUNT_STK_UNIT($TASK.STACKSIZE[tskid]$)];$NL$ $END$ $END$ $NL$ /* スタックを共有するタスクのスタック領域の定義 */$NL$ $ NONPRIかつ,イベントを持たない同一優先度のタスクがスタックを共有できる $ 設定できる優先度のリストを作成する $MAX_PRIORITY_RANGE = { 0,1, ... ,255 }$ $PRIORITY_RANGE = {}$ $STACKSIZE_PER_PRIORITY = {}$ $FOREACH priority MAX_PRIORITY_RANGE$ $IF (+TPRI_MINTASK <= priority) && (priority <= +TPRI_MAXTASK)$ $PRIORITY_RANGE = APPEND(PRIORITY_RANGE , priority)$ $END$ $END$ $ 優先度順に最大値を算出 $FOREACH priority PRIORITY_RANGE$ $STACKSIZE_PER_PRIORITY[priority] = 0$ $FOREACH tskid TASK_LIST$ $IF (TASK.PRIORITY[tskid] == priority) && (EQ(TASK.SCHEDULE[tskid] , "NON") && !LENGTH(TASK.EVENT[tskid])) && (TASK.STACKSIZE[tskid] > STACKSIZE_PER_PRIORITY[priority])$ $STACKSIZE_PER_PRIORITY[priority] = TASK.STACKSIZE[tskid]$ $END$ $END$ $END$ /* サイズが0でないものを出力 */ $FOREACH priority PRIORITY_RANGE$ $IF STACKSIZE_PER_PRIORITY[priority] != 0$ static __STK_UNIT _stack_priority_$priority$[__TCOUNT_STK_UNIT( $STACKSIZE_PER_PRIORITY[priority]$)];$NL$ $END$ $END$ $NL$ /* タスクの初期優先度 */$NL$ const Priority tinib_inipri[TNUM_TASK] = $NL$ {$NL$ $JOINEACH tskid TASK_LIST " , \n"$ $TAB$TPRI_MINTASK + $TASK.PRIORITY[tskid]$$TAB$/* $tskid$ */ $END$ $NL$ }; $NL$ $NL$ /* タスクの実行優先度 */$NL$ const Priority tinib_exepri[TNUM_TASK] = $NL$ {$NL$ $JOINEACH tskid TASK_LIST " , \n"$ $TASK_EXEPRI = TPRI_MINTASK + TASK.PRIORITY[tskid]$ $ NONプリエンプティブタスクは最大値を設定 $IF EQ(TASK.SCHEDULE[tskid] , "NON")$ $TASK_EXEPRI = TPRI_MINTASK + TPRI_MAXTASK$ $ELSE$ $ INTERFALリソースを持っていれば,その中リソースの優先度を設定する. $IF LENGTH(TASK.RESOURCE[tskid])$ $TASK_EXEPRI = TPRI_MINTASK + TASK.PRIORITY[tskid]$ $FOREACH tsk_resid TASK.RESOURCE[tskid]$ $IF EQ(RESOURCE.RESOURCEPROPERTY[tsk_resid] , "INTERNAL")$ $TASK_EXEPRI = RESOURCE_PRIORITY[tsk_resid]$ $END$ $END$ $END$ $END$ $TAB$TPRI_MINTASK + $TASK_EXEPRI$$TAB$/* $tskid$ */ $END$ $NL$ }; $NL$ $NL$ /* タスクの最大起動要求数 */$NL$ const UINT8 tinib_maxact[TNUM_TASK] = $NL$ {$NL$ $JOINEACH tskid TASK_LIST " , \n"$ $TAB$(($+TASK.ACTIVATION[tskid]$) - 1)$TAB$/* $tskid$ */ $END$ $NL$ }; $NL$ $NL$ /* 自動起動属性 */ const AppModeType tinib_autoact[TNUM_TASK] = $NL$ {$NL$ $JOINEACH tskid TASK_LIST " , \n"$ $IF EQ(TASK.AUTOSTART[tskid] , "TRUE")$ $TAB$( $JOINEACH appmode TASK.AUTOSTART.TRUE.APPMODE[tskid] " | "$ $appmode$ $END$ )$TAB$/* $tskid$ */ $ELSE$ $TAB$0x00000000 $END$ $END$ $NL$ }; $NL$ $NL$ /* タスクの起動番地 */$NL$ const FP tinib_task[TNUM_TASK] = $NL$ {$NL$ $JOINEACH tskid TASK_LIST " , \n"$ $TAB$TASKNAME( $tskid$ )$TAB$/* $tskid$ */ $END$ $NL$ }; $NL$ $NL$ /* タスクのスタック領域 */$NL$ const __STK_UNIT tinib_stk[TNUM_TASK] = $NL$ {$NL$ $JOINEACH tskid TASK_LIST " , \n"$ $IF EQ(TASK.SCHEDULE[tskid] , "FULL") || LENGTH(TASK.EVENT[tskid])$ $TAB$(__STK_UNIT)_stack_$tskid$$TAB$/* $tskid$ */ $ELSE$ $TAB$(__STK_UNIT)_stack_priority_$TASK.PRIORITY[tskid]$$TAB$/* $tskid$ , priority : $TASK.PRIORITY[tskid]$ */ $END$ $END$ $NL$ }; $NL$ $NL$ /* タスクのスタックサイズ */$NL$ const UINT16 tinib_stksz[TNUM_TASK] = $NL$ {$NL$ $JOINEACH tskid TASK_LIST " , \n"$ $IF EQ(TASK.SCHEDULE[tskid] , "FULL") || LENGTH(TASK.EVENT[tskid])$ $TAB$$+TASK.STACKSIZE[tskid]$$TAB$/* $tskid$ */ $ELSE$ $TAB$$+TASK.PRIORITY[tskid]$$TAB$/* $tskid$ */ $END$ $END$ $NL$ }; $NL$ $NL$ /* TCBの定義 */$NL$ UINT8 tcb_tstat[TNUM_TASK];$NL$ Priority tcb_curpri[TNUM_TASK];$NL$ DEFINE_CTXB(TNUM_TASK);$NL$ TaskType tcb_next[TNUM_TASK];$NL$ EventMaskType tcb_curevt[TNUM_EXTTASK];$NL$ EventMaskType tcb_waievt[TNUM_EXTTASK];$NL$ UINT8 tcb_actcnt[TNUM_TASK];$NL$ ResourceType tcb_lastres[TNUM_TASK];$NL$ $NL$ $NL$ $ $ カウンタ及びアラームのオブジェクト定義はコンフォーマンスクラスに依存しない $ $INCLUDE "kernel.tf"$ $FILE "kernel_cfg.c"$ /****** Object RESOURCE ******/$NL$ $ RESSCHEDULERの設定で始まりのIDが変わる $RESID_INCREMENT = 0$ $IF EQ(OS.USERESSCHEDULER[0] , "TRUE")$ $RESID_INCREMENT = 1$ $END$ /* リソースIDの定義 */$NL$ $NL$ $FOREACH resid RESOURCE.ID_LIST$ const ResourceType $resid$ = $+resid + RESID_INCREMENT$;$NL$ $END$ $NL$ const Priority resinib_ceilpri[TNUM_RESOURCE] =$NL$ {$NL$ $IF EQ(OS.USERESSCHEDULER[0] , "TRUE")$ $TAB$TPRI_SCHEDULER $END$ $IF LENGTH(RESOURCE.ID_LIST)$ $SPC$,$SPC$$NL$ $JOINEACH resid RESOURCE.ID_LIST " , \n"$ $TAB$$RESOURCE_PRIORITY[resid]$$TAB$/* $resid$ */ $END$ $END$ $NL$}; $NL$ Priority rescb_prevpri[TNUM_RESOURCE];$NL$ ResourceType rescb_prevres[TNUM_RESOURCE];$NL$ $NL$ $NL$ /****** Object EVENT ******/$NL$ $NL$ $NUM_EVTMASK_AUTO = 0$ $ASSIGNABLE_AUTO_EVTMASK = EVTMASK_BITS$ $FOREACH evtid EVENT.ID_LIST$ $ AUTOの場合 $IF EQ(EVENT.MASK[evtid] , "AUTO")$ $IF NUM_EVTMASK_AUTO < ASSIGNABLE_AUTO_EVTMASK$ const EventMaskType $evtid$ = (1U << $NUM_EVTMASK_AUTO$);$NL$ $NUM_EVTMASK_AUTO = NUM_EVTMASK_AUTO + 1$ $ELSE$ $ERROR$ $FORMAT("Total of AUTO EVENT is over. Auto assigned event can define until %1%." , ASSIGNABLE_AUTO_EVTMASK)$ $END$ $END$ $ELSE$ $ AUTO以外 const EventMaskType $evtid$ = $FORMAT("0x%x" , +EVENT.MASK[evtid])$;$NL$ $IF +EVENT.MASK[evtid] == 0x00000000$ $WARNING$ $FORMAT("Event %1% is 0x00000000 , can't wait and set event." , evtid)$ $END$ $END$ $END$ $ 参照されないイベントのチェック $REFERED = 0$ $FOREACH ext_tskid EXTTSK_LIST$ $IF LENGTH(FIND(TASK.EVENT[ext_tskid] , evtid)) != 0$ $REFERED = 1$ $END$ $END$ $IF REFERED == 0$ $WARNING$ $FORMAT("Event %1% is no referenced from any task." , evtid)$ $END$ $END$ $END$ $NL$ $NL$ /****** Object ISR ******/$NL$ $NL$ $ $ ISR定義情報生成部 $ $ エラーチェック部 $USED_ENTRY = {}$ $FOREACH isrid ISR.ID_LIST$ $ 割込み範囲のチェック $IF !LENGTH(FIND(ISR_PRIORITY_LIST , +ISR.PRIORITY[isrid]))$ $ERROR$ $FORMAT("ISR %1%'s PRIORITY(%2%) is no in range[%3% - %4%]." , isrid , ISR.PRIORITY[isrid] , AT(ISR_PRIORITY_LIST , 0) , AT(ISR_PRIORITY_LIST , (LENGTH(ISR_PRIORITY_LIST) - 1)))$ $END$ $END$ $ 割込みエントリが範囲内にあるかチェック $IF !LENGTH(FIND(ISR_ENTRY_LIST , +ISR.ENTRY[isrid]))$ $ERROR$ $FORMAT("ISR %1%'s ENTRY(%2%) is no in range[%3% - %4%]." , isrid , ISR.ENTRY[isrid] , AT(ISR_ENTRY_LIST , 0) , AT(ISR_ENTRY_LIST , (LENGTH(ISR_ENTRY_LIST) - 1)))$ $END$ $END$ $ 割込みエントリが重複していないかのチェック $IF LENGTH(FIND(USED_ENTRY , ISR.ENTRY[isrid]))$ $ERROR$ $FORMAT("ISR %1%'s ENTRY(%2%) is duplicated." , isrid , ISR.ENTRY[isrid])$ $END$ $END$ $ 使用されている割込みエントリの追加 $USED_ENTRY = APPEND(USED_ENTRY , ISR.ENTRY[isrid])$ $END$ $ カテゴリ2 ISR割込み優先度の最大値がカテゴリ1割込み優先度の最大値を超えていないかチェック $ 値の算出 $ISR1_MIN_PRIORITY = AT(ISR_PRIORITY_LIST , (LENGTH(ISR_PRIORITY_LIST) - 1))$ $FOREACH isr1id ISR1_LIST$ $IF ISR.PRIORITY[isr1id] < ISR1_MIN_PRIORITY$ $ISR1_MIN_PRIORITY = ISR.PRIORITY[isr1id]$ $END$ $END$ $ISR2_MAX_PRIORITY = 0$ $FOREACH isr2id ISR2_LIST$ $IF ISR.PRIORITY[isr2id] > ISR2_MAX_PRIORITY$ $ISR2_MAX_PRIORITY = ISR.PRIORITY[isr2id]$ $END$ $END$ $ 値の比較 $IF ((LENGTH(ISR1_LIST) != 0) && (LENGTH(ISR2_LIST) != 0) && (ISR2_MAX_PRIORITY >= ISR1_MIN_PRIORITY))$ $ERROR$ $FORMAT("Max value of Category 2 ISR(%1%) is greater than min value of Category 1 ISR(%2%)." , ISR2_MAX_PRIORITY , ISR1_MIN_PRIORITY)$ $END$ $END$ $NL$ #define IPL_MAXISR2$TAB$$ISR2_MAX_PRIORITY$$NL$ const IPL ipl_maxisr2 = IPL_MAXISR2;$NL$ $NL$ const Priority isrinib_intpri[TNUM_ISR2] =$NL$ {$NL$ $JOINEACH isr2id ISR2_LIST " , \n"$ $TAB$(TPRI_MINISR + $ISR.PRIORITY[isr2id]$)$TAB$/* $isr2id$ */ $END$ $NL$}; $NL$ $NL$ ResourceType isrcb_lastres[TNUM_ISR2];$NL$ $NL$ $NL$ /****** Object APPMODE ******/$NL$ /* 出力する情報はない */$NL$ $NL$ $NL$ /* オブジェクト初期化関数の生成 */$NL$ void object_initialize(void)$NL$ {$NL$ $IF LENGTH(ALARM.ID_LIST)$ $TAB$alarm_initialize();$NL$ $END$ $IF LENGTH(ISR.ID_LIST)$ $TAB$interrupt_initialize();$NL$ $END$ $IF LENGTH(RESOURCE.ID_LIST)$ $TAB$resource_initialize();$NL$ $END$ $IF LENGTH(TASK.ID_LIST)$ $TAB$task_initialize();$NL$ $END$ }$NL$ $NL$ $ $ 依存部出力部 $ $INCLUDE "sys.tf"$ $INCLUDE "cpu.tf"$ $ EOF