#!/usr/bin/env ruby # -*- coding: utf-8 -*- # # TOPPERS Configurator by Ruby # # 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: cfg.rb 32 2016-01-31 14:45:59Z ertl-hiro $ # if ($0 == __FILE__) TOOL_ROOT = File.expand_path(File.dirname(__FILE__)) + "/" $LOAD_PATH.unshift(TOOL_ROOT) end require "pp" require "csv" require "optparse" require "pstore" require "common/GenFile.rb" require "common/StrVal.rb" require "common/SRecord.rb" # # 定数定義 # # 共通 VERSION = "1.0.0" # cfg1_out関係 CFG1_PREFIX = "TOPPERS_cfg_" CFG1_MAGIC_NUM = "TOPPERS_magic_number" CFG1_SIZEOF_SIGNED = "TOPPERS_sizeof_signed_t" CFG1_OUT_C = "cfg1_out.c" CFG1_OUT_DB = "cfg1_out.db" CFG1_OUT_SREC = "cfg1_out.srec" CFG1_OUT_SYMS = "cfg1_out.syms" CFG1_OUT_TIMESTAMP = "cfg1_out.timestamp" # cfg2_out関係 CFG2_OUT_DB = "cfg2_out.db" # # エラー発生有無フラグ # $errorFlag = false # # エラー/警告表示関数 # # 一般的なエラー表示(処理を中断) def error_exit(message, location = "") location += " " if location != "" abort("#{location}error: #{message}") end # 一般的なエラー表示(処理を継続) def error(message, location = "") location += " " if location != "" STDERR.puts("#{location}error: #{message}") $errorFlag = true end # 一般的な警告表示 def warning(message, location = "") location += " " if location != "" STDERR.puts("#{location}warning: #{message}") end # システムコンフィギュレーションファイルの構文解析時のエラー $no_parse_error = 0 def parse_error(cfgFile, message) error(message, "#{cfgFile.getFileName()}:#{cfgFile.getLineNo}:") if ($no_parse_error += 1) >= 10 error_exit("too many errors emitted, stopping now") end end # 静的API処理時のエラー def error_api(params, message) error(message, "#{params[:_file_]}:#{params[:_line_]}:") end # 静的API処理時のエラー(エラーコード付き) def error_ercd(errorCode, params, message) error_api(params, "#{errorCode}: #{message}") end # 静的API処理時の警告 def warning_api(params, message) warning(message, "#{params[:_file_]}:#{params[:_line_]}:") end # パラメータのエラー def error_wrong(errorCode, params, symbol, wrong) error_ercd(errorCode, params, "#{symbol.to_s} `#{params[symbol]}'" \ " is #{wrong} in #{params[:apiname]}") end def error_wrong_id(errorCode, params, symbol, objid, wrong) error_ercd(errorCode, params, "#{symbol.to_s} `#{params[symbol]}'" \ " is #{wrong} in #{params[:apiname]} of #{params[objid]}") end def error_wrong_sym(errorCode, params, symbol, symbol2, wrong) error_ercd(errorCode, params, "#{symbol.to_s} `#{params[symbol]}'" \ " is #{wrong} in #{params[:apiname]}" \ " of #{symbol2.to_s} `#{params[symbol2]}'") end # パラメータ不正のエラー def error_illegal(errorCode, params, symbol) error_ercd(errorCode, params, "illegal #{symbol.to_s} `#{params[symbol]}'" \ " in #{params[:apiname]}") end def error_illegal_id(errorCode, params, symbol, objid) error_ercd(errorCode, params, "illegal #{symbol.to_s} `#{params[symbol]}'" \ " in #{params[:apiname]} of #{params[objid]}") end def error_illegal_sym(errorCode, params, symbol, symbol2) error_ercd(errorCode, params, "illegal #{symbol.to_s} `#{params[symbol]}'" \ " in #{params[:apiname]} of #{symbol2.to_s} `#{params[symbol2]}'") end # # Stringクラスの拡張(二重引用符で囲まれた文字列の作成/展開) # class String # # 二重引用符で囲まれた文字列の作成 # def quote result = "" self.chars do |c| case c when "'" result += "\\\'" when "\"" result += "\\\"" when "\0" result += "\\0" when "\a" result += "\\a" when "\b" result += "\\b" when "\f" result += "\\f" when "\n" result += "\\n" when "\r" result += "\\r" when "\t" result += "\\t" when "\v" result += "\\v" when "\\" result += "\\\\" else result += c end end return("\"" + result + "\"") end # # 二重引用符で囲まれた文字列の展開 # def unquote if /^\"(.*)\"$/m =~ self str = $1 result = "" while (/^(.*)\\(.*)$/m =~ str) result += $1 str = $2 case str when /^[aA](.*)$/m result += "\a" str = $1 when /^[bB](.*)$/m result += "\b" str = $1 when /^[fF](.*)$/m result += "\f" str = $1 when /^[nN](.*)$/m result += "\n" str = $1 when /^[rR](.*)$/m result += "\r" str = $1 when /^[tT](.*)$/m result += "\t" str = $1 when /^[vV](.*)$/m result += "\v" str = $1 when /^[xX]([0-9a-fA-F][0-9a-fA-F]?)(.*)$/m result += $1.hex str = $2 when /^([0-7][0-7]?[0-7]?)(.*)$/m result += $1.oct str = $2 when /^\\(.*)$/m result += "\\" str = $1 end end return(result + str) else return(self.dup) end end end # # シンボルファイルの読み込み # # 以下のメソッドは,GNUのnmが生成するシンボルファイルに対応している. # 別のツールに対応する場合には,このメソッドを書き換えればよい. # def ReadSymbolFile(symbolFileName) begin symbolFile = File.open(symbolFileName) rescue Errno::ENOENT, Errno::EACCES => ex abort(ex.message) end symbolAddress = {} symbolFile.each do |line| # スペース区切りで分解 fields = line.split(/\s+/) # 3列になっていない行は除外 if (fields.size == 3) symbolAddress[fields[2]] = fields[0].hex end end symbolFile.close return(symbolAddress) end # # 値取得シンボルをグローバル変数として定義する # def DefineSymbolValue $symbolValueTable.each do |symbolName, symbolData| if symbolData.has_key?(:VALUE) eval("$#{symbolName} = " \ "StrVal.new(\"#{symbolName}\", #{symbolData[:VALUE]})") end end end # # インクルードパスからファイルを探す # def SearchFilePath(fileName) if File.exist?(fileName) # 指定したファイルパスに存在する return fileName elsif /^\./ =~ fileName # 相対パスを指定していて見つからなかった場合,存在しないものとする #(意図しないファイルが対象となることを防止) return nil else # 各インクルードパスからファイル存在チェック $includePaths.each do |includePath| path = includePath + "/" + fileName # 見つかったら相対パスを返す if File.exist?(path) return path end end return nil end end # # 指定した生成スクリプト(trbファイル)を検索してloadする # def IncludeTrb(fileName) filePath = SearchFilePath(fileName) if filePath.nil? error_exit("`#{fileName}' not found") else load(filePath) end end # # パス3の処理 # def Pass3 # # パス2から引き渡される情報をファイルから読み込む # db = PStore.new(CFG2_OUT_DB) db.transaction(true) do $apiDefinition = db[:apiDefinition] $symbolValueTable = db[:symbolValueTable] $cfgFileInfo = db[:cfgFileInfo] $includeFiles = db[:includeFiles] $cfgData = db[:cfgData] $asmLabel = db[:asmLabel] $bLittleEndian = db[:bLittleEndian] end # # 値取得シンボルをグローバル変数として定義する # DefineSymbolValue() # # 生成スクリプト(trbファイル)を実行する # $trbFileNames.each do |trbFileName| IncludeTrb(trbFileName) end end # # 生成スクリプト(trbファイル)向けの関数 # def SYMBOL(symbol) if !$romSymbol.nil? && $romSymbol.has_key?($asmLabel + symbol) return $romSymbol[$asmLabel + symbol] else return nil end end def BCOPY(startIData, startData, size) if !$romImage.nil? copyData = $romImage.get_data(startIData, size) $romImage.set_data(startData, copyData) end end def PEEK(address, size) if !$romImage.nil? return $romImage.get_value(address, size, false) else return nil end end # # グローバル変数の初期化 # $kernel = nil $pass = nil $includePaths = [] $trbFileNames = [] $apiTableFileNames = [] $symvalTableFileNames = [] $romImageFileName = nil $romSymbolFileName = nil $dependencyFileName = nil $idInputFileName = nil $idOutputFileName = nil # # オプションの処理 # opt = OptionParser.new(banner="Usage: cfg.rb [options] CONFIG-FILE", 40) opt.version = VERSION opt.on("-k KERNEL", "--kernel KERNEL", "kernel profile name") do |val| $kernel = val end opt.on("-p NUM", "--pass NUM", "processing pass number") do |val| $pass = val end opt.on("-I PATH", "--include-path PATH", "include directory path") do |val| $includePaths.push(val) end opt.on("-T TRB-FILE", "--trb-file TRB-FILE", "generation script (trb file)") do |val| $trbFileNames.push(val) end opt.on("--api-table API-TABLE-FILE", "static API table file") do |val| $apiTableFileNames.push(val) end opt.on("--symval-table SYMVAL-TABLE-FILE", "symbol-value table file") do |val| $symvalTableFileNames.push(val) end opt.on("--rom-image SREC-FILE", "rom image file (s-record)") do |val| $romImageFileName = val end opt.on("--rom-symbol SYMS-FILE", "rom symbol table file (nm)") do |val| $romSymbolFileName = val end opt.on("--id-input-file ID-FILE", "ID input file") do |val| $idInputFileName = val end opt.on("--id-output-file ID-FILE", "ID output file") do |val| $idOutputFileName = val end opt.on("--external-id", "generate object ID variables") do $USE_EXTERNAL_ID = true end opt.on("-M [DEPEND-FILE]", "--print-dependencies [DEPEND-FILE]", "dependency file") do |val| $dependencyFileName = val.nil? ? "" : val end opt.on("-O", "--omit-output-db", "omit DB file output") do $omitOutputDb = true end opt.on("-v", "--version", "show version number") do abort(opt.ver) end opt.on("-h", "--help", "show help (this)") do abort(opt.help) end begin $configFileNames = opt.parse(ARGV) rescue OptionParser::ParseError abort(opt.help) end # # オプションのチェック # # 依存関係出力モード if $pass.nil? # パスの指定は必須 STDERR.puts("`--pass' option is mandatory") abort(opt.help) elsif /^[123]$/ !~ $pass STDERR.puts("pass number `#{$pass}' is not valid") abort(opt.help) end # パス1では,静的APIテーブルは必須 if ($pass == "1" && $apiTableFileNames.empty?) STDERR.puts("`--api-table' option must be specified in pass 1") abort(opt.help) end # パス1以外では,生成スクリプト(trbファイル)が必須 if ($pass != "1" && $trbFileNames.empty?) STDERR.puts("`--trb-file' must be specified except in pass 1") abort(opt.help) end # # 指定されたシンボルファイルの読み込み # if !$romSymbolFileName.nil? if File.exist?($romSymbolFileName) $romSymbol = ReadSymbolFile($romSymbolFileName) else error_exit("`#{$romSymbolFileName}' not found") end end # # 指定されたSレコードファイルの読み込み # if !$romImageFileName.nil? if File.exist?($romImageFileName) $romImage = SRecord.new($romImageFileName) else error_exit("`#{$romImageFileName}' not found") end end # # パスに従って各処理を実行 # case $pass when "1" load("pass1.rb") Pass1() when "2" load("pass2.rb") Pass2() when "3" Pass3() else error_exit("invalid pass: #{$pass}") end # エラー発生時はabortする if $errorFlag if ($0 == __FILE__) abort() else # simplecov対応 raise() end end # # 作成したすべてのファイルを出力する # GenFile.output # # タイムスタンプファイルの生成 # if !$timeStampFileName.nil? File.open($timeStampFileName, "w").close end