source: cfg_itronx+oil_gcc/toppers/oil/cfg1_out.cpp@ 54

Last change on this file since 54 was 54, checked in by ertl-ishikawa, 12 years ago

cfg+oil対応コンフィギュレータを追加

File size: 15.1 KB
Line 
1/*
2 * TOPPERS Software
3 * Toyohashi Open Platform for Embedded Real-Time Systems
4 *
5 * Copyright (C) 2007-2009 by TAKAGI Nobuhisa
6 * Copyright (C) 2010 by Meika Sugimoto
7 *
8 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
9 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
10 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
11 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
12 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
13 * スコード中に含まれていること.
14 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
15 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
16 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
17 * の無保証規定を掲載すること.
18 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
19 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
20 * と.
21 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
22 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
23 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
24 * 報告すること.
25 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
26 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
27 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
28 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
29 * 免責すること.
30 *
31 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
32 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
33 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
34 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
35 * の責任を負わない.
36 *
37 */
38#include <cstdlib>
39#include <cerrno>
40#include <iostream>
41#include <fstream>
42#include <sstream>
43#include <iterator>
44#include <algorithm>
45#include <stack>
46#include "toppers/text.hpp"
47#include "toppers/diagnostics.hpp"
48#include "toppers/c_expr.hpp"
49#include "toppers/global.hpp"
50#include "toppers/macro_processor.hpp"
51#include "toppers/s_record.hpp"
52#include "toppers/nm_symbol.hpp"
53#include "toppers/oil/cfg1_out.hpp"
54#include "toppers/oil/preprocess.hpp"
55#include "toppers/oil/configuration_manager.hpp"
56#include <boost/spirit/include/classic_spirit.hpp>
57#include <boost/filesystem/path.hpp>
58
59using namespace toppers::oil::oil_definition;
60using namespace toppers::configuration_manager;
61
62namespace toppers
63{
64 namespace oil
65 {
66 namespace
67 {
68 struct block_t
69 {
70 std::string type;
71 std::string id;
72 text_line line;
73 };
74 }
75
76 //! cfg_out クラスの実装詳細
77 struct cfg1_out::implementation
78 {
79 protected:
80 output_file ofile_;
81 oil_def *oil_def_array;
82 std::string cfg1_out_list_;
83 std::string includes_;
84 std::vector< block_t > block_table_;
85
86 std::tr1::shared_ptr< s_record > srec_;
87 std::tr1::shared_ptr< nm_symbol > syms_;
88 bool little_endian_;
89 std::size_t base_;
90 cfg1_def_table const* def_table_;
91 config_manage oil_configuration;
92
93 implementation( std::string const& filename, std::ios_base::openmode omode, cfg1_def_table const* def_table = 0 )
94 : ofile_( filename, omode ), little_endian_( true ), base_( 1 ), def_table_( def_table )
95 {
96 }
97 virtual ~implementation()
98 {
99 }
100 virtual void do_load_cfg( std::string const& input_file, codeset_t codeset, std::vector<std::string> const& obj_info );
101 virtual void do_generate_includes() const
102 {
103 }
104 virtual void do_generate_cfg1_def() const
105 {
106 ofile_ << "const uint32_t TOPPERS_cfg_magic_number = 0x12345678;\n"
107 "const uint32_t TOPPERS_cfg_sizeof_signed_t = sizeof(signed_t);\n"
108 "const uint32_t TOPPERS_cfg_sizeof_pointer = sizeof(const volatile void*);\n"
109 "const unsigned_t TOPPERS_cfg_CHAR_BIT = CHAR_BIT;\n"
110 "const unsigned_t TOPPERS_cfg_CHAR_MAX = CHAR_MAX;\n"
111 "const unsigned_t TOPPERS_cfg_CHAR_MIN = CHAR_MIN;\n"
112 "const unsigned_t TOPPERS_cfg_SCHAR_MAX = SCHAR_MAX;\n"
113 "const unsigned_t TOPPERS_cfg_SHRT_MAX = SHRT_MAX;\n"
114 "const unsigned_t TOPPERS_cfg_INT_MAX = INT_MAX;\n"
115 "const unsigned_t TOPPERS_cfg_LONG_MAX = LONG_MAX;\n"
116 "\n";
117
118 if ( def_table_ != 0 ) // 「値取得シンボルテーブル」
119 {
120 for ( cfg1_def_table::const_iterator iter( def_table_->begin() ), last( def_table_->end() );
121 iter != last;
122 ++iter )
123 {
124 // 式の最初に # があれば、それはマクロ定義の判定
125 // ★注意★ #@ で始まる書式は廃止 2010/07/23
126 bool is_pp = ( iter->expression[ 0 ] == '#' );
127 if ( !iter->value1.empty() || !iter->value2.empty() ) // (CSVの)4番目または5番目の値があれば...
128 {
129 is_pp = true;
130 }
131
132 std::string type = ( iter->is_signed ? "signed_t" : "unsigned_t" );
133 std::string definition = "const " + type + " ";
134 definition += "TOPPERS_cfg_" + iter->name;
135 if ( is_pp )
136 {
137 std::string expression = iter->expression.substr( iter->expression[ 0 ] == '#' ? 1 : 0 );
138 std::string value1 = ( !iter->value1.empty() ? iter->value1 : "1" );
139 std::string value2 = ( !iter->value2.empty() ? iter->value2 : "0" );
140 definition +=
141 " = \n"
142 "#if " + expression + "\n"
143 "(" + value1 + ");\n"
144 "#else\n"
145 "(" + value2 + ");\n"
146 "#endif\n";
147 }
148 else if ( iter->expression[ 0 ] == '@' ) // '@'で始まればアドレス
149 {
150 definition = "const volatile void* const TOPPERS_cfg_" + iter->name + " = (" + ( iter->expression.c_str() + 1 ) + ");\n";
151 }
152 else
153 {
154 definition +=
155 " = ( " + type + " )" + iter->expression + ";\n";
156 }
157 ofile_ << definition;
158 }
159 }
160 }
161 virtual void do_assign_params();
162 virtual implementation* do_clone() const
163 {
164 return new implementation( *this );
165 }
166
167 void preprocess( std::string const& input_file, codeset_t codeset, text& txt );
168
169 friend class cfg1_out;
170 };
171
172
173 /*!
174 * \brief コンストラクタ
175 * \param[in] filename cfg1_out.c または cfg1_out.srec 若しくはそれらの代替名
176 * \param[in] def_table cfg1_out.c 生成用の定義テーブル
177 */
178 cfg1_out::cfg1_out( std::string const& filename, cfg1_def_table const* def_table )
179 : pimpl_( new implementation( filename, std::ios_base::out, def_table ) )
180 {
181 }
182
183 /*!
184 * \brief コピーコンストラクタ
185 * \param[in] other コピー元
186 */
187 cfg1_out::cfg1_out( cfg1_out const& other )
188 : pimpl_( other.pimpl_->do_clone() )
189 {
190 }
191
192 //! デストラクタ
193 cfg1_out::~cfg1_out()
194 {
195 delete pimpl_;
196 pimpl_ = 0;
197 }
198
199 /*!
200 * \brief システムコンフィギュレーションファイルのロード
201 * \param[in] input_file 入力ファイル名
202 * \param[in] codeset 文字コード
203 * \param[in] obj_info オブジェクト情報の連想配列
204 */
205 void cfg1_out::load_cfg( std::string const& input_file, codeset_t codeset,
206 std::vector<std::string> const* obj_info )
207 {
208 return pimpl_->do_load_cfg( input_file, codeset, *obj_info );
209 }
210
211 //! 前処理
212 void cfg1_out::implementation::preprocess( std::string const& input_file, codeset_t codeset, text& txt )
213 {
214 boost::any print_depend = global( "print-dependencies" );
215 if ( !print_depend.empty() )
216 {
217 std::set< std::string > depend, onces;
218 oil::preprocess( input_file, txt, codeset, &depend, &onces );
219
220 // 依存関係の出力(GNU makeに適した形式)
221 std::string target_file = boost::any_cast< std::string& >( print_depend );
222 std::cout << target_file << ": " << input_file << ' ';
223 std::copy( depend.begin(), depend.end(), std::ostream_iterator< std::string >( std::cout, " " ) );
224 std::cout << std::endl;
225 exit();
226 }
227 else
228 {
229 std::set< std::string > onces;
230 oil::preprocess( input_file, txt, codeset, 0, &onces );
231 }
232 }
233
234 /*!
235 * \brief システムコンフィギュレーションファイルのロード処理の実体
236 * \param[in] input_file 入力ファイル名
237 * \param[in] codeset 文字コード
238 * \param[in] obj_info オブジェクト情報の連想配列
239 */
240 void cfg1_out::implementation::do_load_cfg( std::string const& input_file,
241 codeset_t codeset, std::vector<std::string> const& obj_info )
242 {
243
244 text txt;
245 // システムコンフィギュレーションファイルの解析
246 std::ostringstream oss, includes_oss;
247
248 preprocess( input_file, codeset, txt );
249
250 // OIL情報の読み出し
251 if(oil_configuration.read_configuration(&txt , obj_info) == true)
252 {
253 oil_def_array = oil_configuration.get_obj_def();
254 oil_configuration.validate_and_assign_default_configuration();
255 }
256
257 // データメンバへの反映
258 std::string cfg1_list_temp( oss.str() );
259 std::string includes_temp( includes_oss.str() );
260
261 cfg1_out_list_.swap( cfg1_list_temp );
262 includes_.swap( includes_temp );
263 }
264
265 /*!
266 * \brief cfg1_out.c の内容生成
267 * \param[in] type 配列 cfg1_out[] の要素型。空ポインタの場合は uint32_t として扱われる。
268 */
269 void cfg1_out::generate( char const* type ) const
270 {
271 if ( type == 0 )
272 {
273 type = "uint32_t";
274 }
275 pimpl_->ofile_ << "/* cfg1_out.c */\n"
276 "#define TOPPERS_CFG1_OUT 1\n"
277 "#include \"osek_kernel.h\"\n"
278 "#include \"target_cfg1_out.h\"\n";
279 pimpl_->do_generate_includes();
280 pimpl_->ofile_ << pimpl_->includes_ << '\n';
281
282 // int128_tは故意に無視
283 // int128_tに揃えると処理が重くなりすぎるため
284 pimpl_->ofile_ << "\n#ifdef INT64_MAX\n"
285 " typedef int64_t signed_t;\n"
286 " typedef uint64_t unsigned_t;\n"
287 "#else\n"
288 " typedef int32_t signed_t;\n"
289 " typedef uint32_t unsigned_t;\n"
290 "#endif\n";
291
292 pimpl_->ofile_ << "\n#include <target_cfg1_out.h>\n\n";
293
294 pimpl_->do_generate_cfg1_def();
295 pimpl_->ofile_ << pimpl_->cfg1_out_list_ << '\n';
296 }
297
298 /*!
299 * \brief #include指令の並びを取得する
300 * \return #include指令の並び
301 *
302 * このメンバ関数は、
303 * \code
304 * #include <...>
305 * #include "..."
306 * \endcode
307 * といった#include指令の並びを文字列として返す。
308 */
309 std::string const& cfg1_out::get_includes() const
310 {
311 return pimpl_->includes_;
312 }
313
314 /*!
315 * \brief Sレコードのロード
316 */
317 void cfg1_out::load_srec()
318 {
319 std::ifstream srec_ifs( ( pimpl_->ofile_.file_name() + ".srec" ).c_str() );
320 if ( !srec_ifs.is_open() )
321 {
322 fatal( _( "cannot open file `%1%\'" ), pimpl_->ofile_.file_name() + ".srec" );
323 }
324 pimpl_->srec_ = std::tr1::shared_ptr< s_record >( new s_record( srec_ifs ) );
325
326 std::ifstream syms_ifs( ( pimpl_->ofile_.file_name() + ".syms" ).c_str() );
327 if ( !syms_ifs.is_open() )
328 {
329 fatal( _( "cannot open file `%1%\'" ), pimpl_->ofile_.file_name() + ".syms" );
330 }
331 pimpl_->syms_ = std::tr1::shared_ptr< nm_symbol >( new nm_symbol( syms_ifs ) );
332
333 nm_symbol::entry nm_entry = pimpl_->syms_->find( "TOPPERS_cfg_magic_number" );
334 if ( nm_entry.type < 0 )
335 {
336 fatal( _( "magic number is not found in `%1%\'" ), ( pimpl_->ofile_.file_name() + ".srec/.syms" ) );
337 }
338 unsigned long magic[ 4 ];
339 magic[ 0 ] = ( *pimpl_->srec_ )[ nm_entry.address + 0 ];
340 magic[ 1 ] = ( *pimpl_->srec_ )[ nm_entry.address + 1 ];
341 magic[ 2 ] = ( *pimpl_->srec_ )[ nm_entry.address + 2 ];
342 magic[ 3 ] = ( *pimpl_->srec_ )[ nm_entry.address + 3 ];
343 unsigned long magic_number = ( magic[ 0 ] << 24 ) | ( magic[ 1 ] << 16 ) | ( magic[ 2 ] << 8 ) | magic[ 3 ];
344 if ( magic_number == 0x12345678 )
345 {
346 pimpl_->little_endian_ = false;
347 }
348 else if ( magic_number == 0x78563412 )
349 {
350 pimpl_->little_endian_ = true;
351 }
352 else
353 {
354 fatal( _( "magic number is not found in `%1%\'" ), ( pimpl_->ofile_.file_name() + ".srec/.syms" ) );
355 }
356 pimpl_->do_assign_params();
357 }
358
359 /*!
360 * \brief "cfg1_out.srec" から読み取った情報の参照
361 */
362 std::tr1::shared_ptr< s_record > cfg1_out::get_srec() const
363 {
364 return pimpl_->srec_;
365 }
366
367 /*!
368 * \brief "cfg1_out.syms" から読み取った情報の参照
369 */
370 std::tr1::shared_ptr< nm_symbol > cfg1_out::get_syms() const
371 {
372 return pimpl_->syms_;
373 }
374
375 cfg1_out::cfg1_def_table const* cfg1_out::get_def_table() const
376 {
377 return pimpl_->def_table_;
378 }
379
380 /*!
381 * \brief オブジェクトごとにOILオブジェクト情報をまとめる
382 * \return 静的API情報
383 *
384 * この関数は、"tsk"や"sem"といった種別をキーとして、その種別に分類される静的API情報の連想配列を生成する。
385 */
386 cfg1_out::cfg_obj_map cfg1_out::merge() const
387 {
388 cfg_obj_map result;
389
390 result = oil_definition::merge(pimpl_->oil_def_array , result);
391
392 return result;
393
394 }
395
396 /*!
397 * \brief リトルエンディアンかどうかの判定
398 * \retval true リトルエンディアン
399 * \retval false ビッグエンディアン
400 * \attention load_srec 呼び出し前は正しい結果を得られない。
401 */
402 bool cfg1_out::is_little_endian() const
403 {
404 return pimpl_->little_endian_;
405 }
406
407 /*!
408 * \brief 静的APIのパラメータにSレコードから取得した値を代入する
409 */
410 void cfg1_out::implementation::do_assign_params()
411 {
412 }
413
414 /*!
415 * \brief --id-input-fileオプションで指定したファイルの読み込み
416 * \id_map 読み込んだデータの格納先
417 */
418 void cfg1_out::load_id_input_file( std::map< std::string, std::pair< long, bool > >& id_map )
419 {
420 std::string id_input_file( get_global< std::string >( "id-input-file" ) );
421 if ( id_input_file.empty() )
422 {
423 return;
424 }
425
426 std::ifstream ifs( id_input_file.c_str() );
427 while ( ifs )
428 {
429 std::string linebuf;
430 std::getline( ifs, linebuf );
431 if ( ifs.bad() )
432 {
433 fatal( _( "I/O error" ) );
434 }
435 if ( linebuf.empty() || linebuf == "\r" )
436 {
437 break;
438 }
439
440 std::istringstream iss( linebuf );
441 std::string name;
442 iss >> name;
443 if ( iss.fail() )
444 {
445 fatal( _( "id file `%1%\' is invalid" ), id_input_file );
446 }
447
448 long value;
449 iss >> value;
450 if ( iss.fail() )
451 {
452 fatal( _( "id file `%1%\' is invalid" ), id_input_file );
453 }
454
455 if ( id_map.find( name ) != id_map.end() )
456 {
457 fatal( _( "`%1%\' is duplicated" ), name );
458 }
459 else
460 {
461 id_map[ name ] = std::make_pair( value, false );
462 }
463 }
464 }
465 }
466}
Note: See TracBrowser for help on using the repository browser.