# -*- coding: utf-8 -*- # # TOPPERS/ASP Kernel # Toyohashi Open Platform for Embedded Real-Time Systems/ # Advanced Standard Profile Kernel # # Copyright (C) 2015 by FUJI SOFT INCORPORATED, JAPAN # Copyright (C) 2015,2016 by Embedded and Real-Time Systems Laboratory # Graduate School of Information Science, Nagoya Univ., JAPAN # # 上記著作権者は,以下の(1)~(4)の条件を満たす場合に限り,本ソフトウェ # ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改 # 変・再配布(以下,利用と呼ぶ)することを無償で許諾する. # (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作 # 権表示,この利用条件および下記の無保証規定が,そのままの形でソー # スコード中に含まれていること. # (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使 # 用できる形で再配布する場合には,再配布に伴うドキュメント(利用 # 者マニュアルなど)に,上記の著作権表示,この利用条件および下記 # の無保証規定を掲載すること. # (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使 # 用できない形で再配布する場合には,次のいずれかの条件を満たすこ # と. # (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著 # 作権表示,この利用条件および下記の無保証規定を掲載すること. # (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに # 報告すること. # (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損 # 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること. # また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理 # 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを # 免責すること. # # 本ソフトウェアは,無保証で提供されているものである.上記著作権者お # よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的 # に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ # アの利用により直接的または間接的に生じたいかなる損害に関しても,そ # の責任を負わない. # # $Id$ # # # コンフィギュレータのパス2の生成スクリプト # # # タイムスタンプファイルの指定 # $timeStampFileName = "kernel_cfg.timestamp" # # kernel_cfg.hの先頭部分の生成 # $kernelCfgH = GenFile.new("kernel_cfg.h") $kernelCfgH.add(< "a#{@obj_s}inib_table"} end def generate() # AID_@OBJの処理 numAutoObjid = 0 $cfgData["AID_#{@OBJ}".to_sym].each do |key, params| numAutoObjid += params["no#{@obj}".to_sym] end numObjid = $cfgData[@api].size + numAutoObjid # kernel_cfg.hの生成 $kernelCfgH.add("#define TNUM_#{@OBJ}ID\t#{numObjid}") # オブジェクトのID番号のマクロ定義の生成 $cfgData[@api].sort.each do |key, params| $kernelCfgH.add("#define #{params[@objid]}\t#{params[@objid].val}") end $kernelCfgH.add() # オブジェクトのID番号を保持する変数 if $USE_EXTERNAL_ID $cfgData[@api].sort.each do |key, params| $kernelCfgC.add("const ID #{params[@objid]}_id" \ " = #{params[@objid].val};") end $kernelCfgC.add() end # 静的に生成されたオブジェクトの数 $kernelCfgC.add("#define TNUM_S#{@OBJ}ID\t#{$cfgData[@api].size}") # オブジェクトID番号の最大値 $kernelCfgC.add("const ID _kernel_tmax_#{@obj}id" \ " = (TMIN_#{@OBJ}ID + TNUM_#{@OBJ}ID - 1);") $kernelCfgC.add2("const ID _kernel_tmax_s#{@obj}id" \ " = (TMIN_#{@OBJ}ID + TNUM_S#{@OBJ}ID - 1);") # データ構造 if $cfgData[@api].size > 0 # 事前準備(エラーチェック,メモリ領域の生成) $cfgData[@api].sort.each do |key, params| prepare(key, params) end # オブジェクト全体に対して必要なメモリ領域の生成(オプション) if respond_to?(:generateData) generateData() end # オブジェクト初期化ブロックの生成 $kernelCfgC.add("const #{@OBJ_S}INIB _kernel_#{@obj_s}inib_table" \ "[TNUM_S#{@OBJ}ID] = {") $cfgData[@api].sort.each_with_index do |(key, params), index| $kernelCfgC.add(",") if index > 0 $kernelCfgC.append("\t{ " + generateInib(key, params) + " }") end $kernelCfgC.add $kernelCfgC.add2("};") else $kernelCfgC.add2("TOPPERS_EMPTY_LABEL(const #{@OBJ_S}INIB, " \ "_kernel_#{@obj_s}inib_table);") end # 動的生成オブジェクト用のオブジェクト初期化ブロック @inibList.each do |type, array| if numAutoObjid > 0 $kernelCfgC.add2("#{type} _kernel_#{array}[#{numAutoObjid}];") else $kernelCfgC.add2("TOPPERS_EMPTY_LABEL(#{type}, _kernel_#{array});") end end if numObjid > 0 # オブジェクト管理ブロックの生成 $kernelCfgC.add2("#{@OBJ_S}CB _kernel_#{@obj_s}cb_table" \ "[TNUM_#{@OBJ}ID];") # オブジェクト初期化関数の追加 $initializeFunctions.push("_kernel_initialize_#{@object}();") else $kernelCfgC.add2("TOPPERS_EMPTY_LABEL(#{@OBJ_S}CB, " \ "_kernel_#{@obj_s}cb_table);") end end end # # 通知ハンドラの生成関数 # def generateNotifyHandler(key, params, objid) # パラメータを変数に格納 nfymode = params[:nfymode] nfymode1 = nfymode & 0x0f nfymode2 = nfymode & ~0x0f par1 = params[:par1] par2 = params[:par2] # 通知処理のパラメータ数による補正処理 if nfymode == $TNFY_HANDLER || nfymode1 == $TNFY_SETVAR \ || nfymode1 == $TNFY_SETFLG \ || nfymode1 == $TNFY_SNDDTQ # 通知処理のパラメータが2つの場合 numpar = 2 epar1 = params[:par3] epar2 = params[:par4] else # 通知処理のパラメータが1つの場合 numpar = 1 epar1 = params[:par2] epar2 = params[:par3] end # パラメータ数のチェック if (numpar == 2 && par2.nil?) || (nfymode2 != 0 && epar1.nil?) \ || (nfymode2 == $TENFY_SETFLG && epar2.nil?) # パラメータが足りない場合 error_api(params, "too few parameters for nfymode `#{nfymode}' " \ "in %apiname of %#{objid}") elsif (nfymode2 == 0 && !epar1.nil?) \ || (nfymode2 != $TENFY_SETFLG && !epar2.nil?) # パラメータが多すぎる場合 error_api(params, "too many parameters for nfymode `#{nfymode}' " \ "in %apiname of %#{objid}") elsif nfymode == $TNFY_HANDLER # タイムイベントハンドラの呼出し funcname = "(NFYHDR)(#{par2})" else # 通知ハンドラの関数名 funcname = "_kernel_nfyhdr_#{params[objid]}" # エラー通知のための変数のアドレスとオブジェクトIDを格納する # 変数の生成(エラーチェックのために必要) if nfymode2 == $TENFY_SETVAR || nfymode2 == $TENFY_INCVAR $kernelCfgC.add2("intptr_t *const #{funcname}_p_evar =" \ " (intptr_t *)(#{epar1});") elsif nfymode2 == $TENFY_ACTTSK || nfymode2 == $TENFY_WUPTSK $kernelCfgC.add2("const ID #{funcname}_etskid = #{epar1};") elsif nfymode2 == $TENFY_SIGSEM $kernelCfgC.add2("const ID #{funcname}_esemid = #{epar1};") elsif nfymode2 == $TENFY_SETFLG $kernelCfgC.add2("const ID #{funcname}_eflgid = #{epar1};") elsif nfymode2 == $TENFY_SNDDTQ $kernelCfgC.add2("const ID #{funcname}_edtqid = #{epar1};") end # 関数の先頭部分の生成 $kernelCfgC.add("static void") $kernelCfgC.add("#{funcname}(intptr_t exinf)") $kernelCfgC.add("{") if nfymode2 == 0 # エラー通知がない場合 errorCode = "(void) " else # エラー通知がある場合 $kernelCfgC.add2("\tER\tercd;") errorCode = "ercd = " end # イベント通知処理の処理 if nfymode1 == $TNFY_SETVAR && nfymode2 == 0 # 変数の設定 $kernelCfgC.add("\t*((intptr_t *) exinf) = (#{par2});") elsif nfymode1 == $TNFY_INCVAR && nfymode2 == 0 # 変数のインクリメント $kernelCfgC.add("\t(void) loc_cpu();") $kernelCfgC.add("\t*((intptr_t *) exinf) += 1;") $kernelCfgC.add("\t(void) unl_cpu();") elsif nfymode1 == $TNFY_ACTTSK # タスクの起動 $kernelCfgC.add("\t#{errorCode}act_tsk((ID) exinf);") elsif nfymode1 == $TNFY_WUPTSK # タスクの起床 $kernelCfgC.add("\t#{errorCode}wup_tsk((ID) exinf);") elsif nfymode1 == $TNFY_SIGSEM # セマフォの返却 $kernelCfgC.add("\t#{errorCode}sig_sem((ID) exinf);") elsif nfymode1 == $TNFY_SETFLG # イベントフラグのセット $kernelCfgC.add("\t#{errorCode}set_flg(((ID) exinf), #{par2});") elsif nfymode1 == $TNFY_SNDDTQ # データキューへの送信 $kernelCfgC.add("\t#{errorCode}psnd_dtq(((ID) exinf), #{par2});") else error_illegal_id("E_PAR", params, :nfymode, objid) end if nfymode2 != 0 # エラー通知処理の処理 $kernelCfgC.add("\tif (ercd != E_OK) {") if nfymode2 == $TENFY_SETVAR # 変数の設定 $kernelCfgC.add("\t\t*#{funcname}_p_evar = (intptr_t) ercd;") elsif nfymode2 == $TENFY_INCVAR # 変数のインクリメント $kernelCfgC.add("\t\t(void) loc_cpu();") $kernelCfgC.add("\t\t*#{funcname}_p_evar += 1;") $kernelCfgC.add("\t\t(void) unl_cpu();") elsif nfymode2 == $TENFY_ACTTSK # タスクの起動 $kernelCfgC.add("\t\t(void) act_tsk(#{funcname}_etskid);") elsif nfymode2 == $TENFY_WUPTSK # タスクの起床 $kernelCfgC.add("\t\t(void) wup_tsk(#{funcname}_etskid);") elsif nfymode2 == $TENFY_SIGSEM # セマフォの返却 $kernelCfgC.add("\t\t(void) sig_sem(#{funcname}_esemid);") elsif nfymode2 == $TENFY_SETFLG # イベントフラグのセット $kernelCfgC.add("\t\t(void) set_flg(#{funcname}_eflgid, #{epar2});") elsif nfymode2 == $TENFY_SNDDTQ # データキューへの送信 $kernelCfgC.add("\t\t(void) psnd_dtq(#{funcname}_edtqid," \ " (intptr_t) ercd);") else error_illegal_id("E_PAR", params, :nfymode, objid) end $kernelCfgC.add("\t}") end # 関数の末尾部分の生成 $kernelCfgC.add2("}") end return(funcname) end # # 各機能モジュールのコンフィギュレーション # $initializeFunctions = [] IncludeTrb("kernel/task.trb") IncludeTrb("kernel/semaphore.trb") IncludeTrb("kernel/eventflag.trb") IncludeTrb("kernel/dataqueue.trb") IncludeTrb("kernel/pridataq.trb") IncludeTrb("kernel/mutex.trb") IncludeTrb("kernel/mempfix.trb") IncludeTrb("kernel/cyclic.trb") IncludeTrb("kernel/alarm.trb") IncludeTrb("kernel/interrupt.trb") IncludeTrb("kernel/exception.trb") # # 非タスクコンテキスト用のスタック領域 # $kernelCfgC.comment_header("Stack Area for Non-task Context") if $cfgData[:DEF_ICS].size == 0 # DEF_ICSがない場合のデフォルト値の設定 if $DEFAULT_ISTK.nil? # スタック領域の自動割付け istksz = AllocStack("_kernel_istack", "DEFAULT_ISTKSZ") istk = "_kernel_istack" else istksz = "DEFAULT_ISTKSZ" istk = "DEFAULT_ISTK" end else # 静的API「DEF_ICS」が複数ある(E_OBJ)[NGKI3216] if $cfgData[:DEF_ICS].size > 1 error("E_OBJ: too many DEF_ICS") end # DEF_ICSがある場合の処理 params = $cfgData[:DEF_ICS][1] # パラメータが省略された時のデフォルト値の設定 params[:istk] ||= "NULL" # istkszがターゲット定義の最小値(TARGET_MIN_ISTKSZ,未定義の場合は1) # よりも小さい場合(E_PAR)[NGKI3254] if params[:istksz] < $TARGET_MIN_ISTKSZ error_wrong("E_PAR", params, :istksz, "too small") end if params[:istk] == "NULL" # スタック領域の自動割付け istksz = AllocStack("_kernel_istack", params[:istksz]) istk = "_kernel_istack" else # istkszがスタック領域のサイズとして正しくない場合(E_PAR)[NGKI3222] if (params[:istksz] & ($CHECK_STKSZ_ALIGN - 1)) != 0 error_wrong("E_PAR", params, :istksz, "not aligned") end istksz = "(#{params[:istksz]})" istk = "(void *)(#{params[:istk]})" end end $kernelCfgC.add(< 1) error("E_OBJ: too many DEF_KMM") end # DEF_KMMがある場合の処理 params = $cfgData[:DEF_KMM][1] # パラメータが省略された時のデフォルト値の設定 params[:kmm] ||= "NULL" # kmmszが0の場合(E_PAR) if params[:kmmsz] == 0 error_wrong("E_PAR", params, :kmmsz, "zero") end if params[:kmm] == "NULL" # カーネルが割り付けるメモリ領域の自動割付け $kernelCfgC.add("static MB_T _kernel_memory" \ "[TOPPERS_COUNT_SZ(#{params[:kmmsz]}, sizeof(MB_T))];") kmmsz = "TOPPERS_ROUND_SZ(#{params[:kmmsz]}, sizeof(MB_T))" kmm = "_kernel_memory" else # kmmszがカーネルが割り付けるメモリ領域のサイズとして正しくない場合 # (E_PAR) if (params[:kmmsz] & ($CHECK_MB_ALIGN - 1)) != 0 error_wrong("E_PAR", params, :kmmsz, "not aligned") end kmmsz = "(#{params[:kmmsz]})" kmm = "(void *)(#{params[:kmm]})" end end $kernelCfgC.add(<