source: cfg_itronx+oil_gcc/toppers/itronx/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: 35.5 KB
Line 
1/*
2 * TOPPERS Software
3 * Toyohashi Open Platform for Embedded Real-Time Systems
4 *
5 * Copyright (C) 2007-2011 by TAKAGI Nobuhisa
6 *
7 * 上記著作権者は,以下の(1)〜(4)の条件を満たす場合に限り,本ソフトウェ
8 * ア(本ソフトウェアを改変したものを含む.以下同じ)を使用・複製・改
9 * 変・再配布(以下,利用と呼ぶ)することを無償で許諾する.
10 * (1) 本ソフトウェアをソースコードの形で利用する場合には,上記の著作
11 * 権表示,この利用条件および下記の無保証規定が,そのままの形でソー
12 * スコード中に含まれていること.
13 * (2) 本ソフトウェアを,ライブラリ形式など,他のソフトウェア開発に使
14 * 用できる形で再配布する場合には,再配布に伴うドキュメント(利用
15 * 者マニュアルなど)に,上記の著作権表示,この利用条件および下記
16 * の無保証規定を掲載すること.
17 * (3) 本ソフトウェアを,機器に組み込むなど,他のソフトウェア開発に使
18 * 用できない形で再配布する場合には,次のいずれかの条件を満たすこ
19 * と.
20 * (a) 再配布に伴うドキュメント(利用者マニュアルなど)に,上記の著
21 * 作権表示,この利用条件および下記の無保証規定を掲載すること.
22 * (b) 再配布の形態を,別に定める方法によって,TOPPERSプロジェクトに
23 * 報告すること.
24 * (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
25 * 害からも,上記著作権者およびTOPPERSプロジェクトを免責すること.
26 * また,本ソフトウェアのユーザまたはエンドユーザからのいかなる理
27 * 由に基づく請求からも,上記著作権者およびTOPPERSプロジェクトを
28 * 免責すること.
29 *
30 * 本ソフトウェアは,無保証で提供されているものである.上記著作権者お
31 * よびTOPPERSプロジェクトは,本ソフトウェアに関して,特定の使用目的
32 * に対する適合性も含めて,いかなる保証も行わない.また,本ソフトウェ
33 * アの利用により直接的または間接的に生じたいかなる損害に関しても,そ
34 * の責任を負わない.
35 *
36 */
37#include <cstdlib>
38#include <cerrno>
39#include <iostream>
40#include <fstream>
41#include <sstream>
42#include <iterator>
43#include <algorithm>
44#include <stack>
45#include "toppers/text.hpp"
46#include "toppers/diagnostics.hpp"
47#include "toppers/c_expr.hpp"
48#include "toppers/global.hpp"
49#include "toppers/macro_processor.hpp"
50#include "toppers/s_record.hpp"
51#include "toppers/nm_symbol.hpp"
52#include "toppers/misc.hpp"
53#include "toppers/itronx/cfg1_out.hpp"
54#include "toppers/itronx/preprocess.hpp"
55#include <boost/spirit/include/classic.hpp>
56#include <boost/filesystem/path.hpp>
57#include <boost/lexical_cast.hpp>
58
59namespace toppers
60{
61 namespace itronx
62 {
63 namespace
64 {
65 struct block_t
66 {
67 std::string type;
68 std::string id;
69 text_line line;
70 };
71 }
72
73 //! cfg_out クラスの実装詳細
74 struct cfg1_out::implementation
75 {
76 protected:
77 output_file ofile_;
78 std::vector< static_api > static_api_array_;
79 std::string cfg1_out_list_;
80 std::string includes_;
81 std::string domid_defs_;
82 std::vector< block_t > block_table_;
83 std::vector< std::pair< std::string, long > > clsid_table_;
84 std::vector< std::pair< std::string, long > > domid_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
92 implementation( std::string const& filename, std::ios_base::openmode omode, cfg1_def_table const* def_table = 0 )
93 : ofile_( filename, omode ), little_endian_( true ), base_( 1 ), def_table_( def_table )
94 {
95 }
96 virtual ~implementation()
97 {
98 }
99 virtual void do_load_cfg( std::string const& input_file, codeset_t codeset, std::map< std::string, static_api::info > const& info_map );
100 virtual void do_generate_includes() const
101 {
102 }
103 virtual void do_generate_cfg1_def() const
104 {
105 ofile_ << "const uint32_t TOPPERS_cfg_magic_number = 0x12345678;\n"
106 "const uint32_t TOPPERS_cfg_sizeof_signed_t = sizeof(signed_t);\n"
107 "const uint32_t TOPPERS_cfg_sizeof_pointer = sizeof(const volatile void*);\n"
108 "const unsigned_t TOPPERS_cfg_CHAR_BIT = CHAR_BIT;\n"
109 "const unsigned_t TOPPERS_cfg_CHAR_MAX = CHAR_MAX;\n"
110 "const unsigned_t TOPPERS_cfg_CHAR_MIN = CHAR_MIN;\n"
111 "const unsigned_t TOPPERS_cfg_SCHAR_MAX = SCHAR_MAX;\n"
112 "const unsigned_t TOPPERS_cfg_SHRT_MAX = SHRT_MAX;\n"
113 "const unsigned_t TOPPERS_cfg_INT_MAX = INT_MAX;\n"
114 "const unsigned_t TOPPERS_cfg_LONG_MAX = LONG_MAX;\n"
115 "\n";
116
117 if ( def_table_ != 0 ) // 「値取得シンボルテーブル」
118 {
119 for ( cfg1_def_table::const_iterator iter( def_table_->begin() ), last( def_table_->end() );
120 iter != last;
121 ++iter )
122 {
123 // 式の最初に # があれば、それはマクロ定義の判定
124 // ★注意★ #@ で始まる書式は廃止 2010/07/23
125 bool is_pp = ( iter->expression[ 0 ] == '#' );
126 if ( !iter->value1.empty() || !iter->value2.empty() ) // (CSVの)4番目または5番目の値があれば...
127 {
128 is_pp = true;
129 }
130
131 std::string type = ( iter->is_signed ? "signed_t" : "unsigned_t" );
132 std::string definition = "const " + type + " ";
133 definition += "TOPPERS_cfg_" + iter->name;
134 if ( is_pp )
135 {
136 std::string expression = iter->expression.substr( iter->expression[ 0 ] == '#' ? 1 : 0 );
137 std::string value1 = ( !iter->value1.empty() ? iter->value1 : "1" );
138 std::string value2 = ( !iter->value2.empty() ? iter->value2 : "0" );
139 definition +=
140 " = \n"
141 "#if " + expression + "\n"
142 "(" + value1 + ");\n"
143 "#else\n"
144 "(" + value2 + ");\n"
145 "#endif\n";
146 }
147 else if ( iter->expression[ 0 ] == '@' ) // '@'で始まればアドレス
148 {
149 definition = "const volatile void* const TOPPERS_cfg_" + iter->name + " = (" + ( iter->expression.c_str() + 1 ) + ");\n";
150 }
151 else
152 {
153 definition +=
154 " = ( " + type + " )" + iter->expression + ";\n";
155 }
156 ofile_ << definition;
157 }
158 }
159 }
160 virtual void do_assign_params();
161 virtual implementation* do_clone() const
162 {
163 return new implementation( *this );
164 }
165
166 void preprocess( std::string const& input_file, codeset_t codeset, text& txt );
167
168 friend class cfg1_out;
169 };
170
171
172 /*!
173 * \brief コンストラクタ
174 * \param[in] filename cfg1_out.c または cfg1_out.srec 若しくはそれらの代替名
175 * \param[in] def_table cfg1_out.c 生成用の定義テーブル
176 */
177 cfg1_out::cfg1_out( std::string const& filename, cfg1_def_table const* def_table )
178 : pimpl_( new implementation( filename, std::ios_base::out, def_table ) )
179 {
180 }
181
182 /*!
183 * \brief コピーコンストラクタ
184 * \param[in] other コピー元
185 */
186 cfg1_out::cfg1_out( cfg1_out const& other )
187 : pimpl_( other.pimpl_->do_clone() )
188 {
189 }
190
191 //! デストラクタ
192 cfg1_out::~cfg1_out()
193 {
194 delete pimpl_;
195 pimpl_ = 0;
196 }
197
198 /*!
199 * \brief システムコンフィギュレーションファイルのロード
200 * \param[in] input_file 入力ファイル名
201 * \param[in] codeset 文字コード
202 * \param[in] info_map 静的API情報の連想配列
203 */
204 void cfg1_out::load_cfg( std::string const& input_file, codeset_t codeset, std::map< std::string, static_api::info > const& info_map )
205 {
206 return pimpl_->do_load_cfg( input_file, codeset, info_map );
207 }
208
209 //! 前処理
210 void cfg1_out::implementation::preprocess( std::string const& input_file, codeset_t codeset, text& txt )
211 {
212 boost::any print_depend = global( "print-dependencies" );
213 if ( !print_depend.empty() )
214 {
215 std::set< std::string > depend, onces;
216 itronx::preprocess( input_file, txt, codeset, &depend, &onces );
217
218 // 依存関係の出力(GNU makeに適した形式)
219 std::string target_file = boost::any_cast< std::string& >( print_depend );
220 std::cout << target_file << ": " << input_file << ' ';
221 std::copy( depend.begin(), depend.end(), std::ostream_iterator< std::string >( std::cout, " " ) );
222 std::cout << std::endl;
223 exit();
224 }
225 else
226 {
227 std::set< std::string > onces;
228 itronx::preprocess( input_file, txt, codeset, 0, &onces );
229 }
230 }
231
232 /*!
233 * \brief システムコンフィギュレーションファイルのロード処理の実体
234 * \param[in] input_file 入力ファイル名
235 * \param[in] codeset 文字コード
236 * \param[in] info_map 静的API情報の連想配列
237 */
238 void cfg1_out::implementation::do_load_cfg( std::string const& input_file, codeset_t codeset, std::map< std::string, static_api::info > const& info_map )
239 {
240 text txt;
241 preprocess( input_file, codeset, txt );
242
243 // システムコンフィギュレーションファイルの解析
244 std::ostringstream oss, includes_oss;
245 std::vector< static_api > api_array;
246 long serial = 0;
247 std::stack< block_t > block_stack;
248 std::vector< block_t > block_table;
249 std::string current_class, current_domain;
250 long domain_serial = 1;
251 std::map< std::string, std::pair< long, bool > > id_map;
252 std::vector< std::pair< std::string, long > > clsid_table;
253 std::vector< std::pair< std::string, long > > domid_table;
254
255 for ( text::const_iterator iter( txt.begin() ), last( txt.end() ); iter != last; ++iter )
256 {
257 using namespace boost::spirit::classic;
258 parse_info< text::const_iterator > info;
259
260 info = parse( iter, last, ( ch_p( '#' ) >> *( anychar_p - eol_p ) >> eol_p ) ); // 前処理指令の検出
261 if ( info.hit ) // 前処理指令ならば...
262 {
263 if ( std::size_t col = info.stop.get_col() )
264 {
265 if ( info.stop.get_row()->buf.find_first_not_of( " \t" ) < col )
266 {
267 error( _( "illegal character `%1%\' is found" ), '#' );
268 }
269 }
270 text::const_iterator stop = info.stop;
271 std::string directive;
272 info = parse( iter, last, ( ch_p( '#' ) >> ( +alnum_p )[ assign_a( directive ) ] >> *( anychar_p - eol_p ) >> eol_p ) );
273 if ( info.hit )
274 {
275 if ( directive == "include" )
276 {
277 std::string directive_line_str( iter, info.stop );
278 if ( *directive_line_str.rbegin() == '\n' )
279 {
280 directive_line_str.erase( directive_line_str.size() - 1 );
281 }
282 includes_oss << directive_line_str << '\n';
283 oss << "/* " << directive_line_str << " */\n";
284 }
285 else if ( directive == "if" || directive == "ifdef" || directive == "ifndef"
286 || directive == "else" || directive == "elif" || directive == "endif" )
287 {
288 oss << '\n' << std::string( iter, stop );
289 }
290 else if ( directive != "pragma" ) // コンフィギュレータが処理すべき#pragma指令はこの時点では除去されている
291 {
292 error( iter.line(), _( "`#%1%\' is not supported" ), directive );
293 }
294 }
295 else
296 {
297 oss << std::string( iter, stop );
298 }
299 iter = boost::prior( stop );
300 }
301 else // 前処理指令ではなく...
302 if ( !std::isspace( static_cast< unsigned char >( *iter ) ) )
303 {
304 while ( iter != last )
305 {
306 int ch = static_cast< unsigned char >( *iter );
307 if ( !std::isspace( ch ) )
308 {
309 break;
310 }
311 }
312
313 std::string block_type;
314 std::string id;
315 std::string idexp;
316 c_const_expr_parser const c_const_expr_p;
317 info = parse( iter, last,
318 (
319 str_p( "DOMAIN" )[ assign_a( block_type ) ]
320 >> '(' >> c_ident_p[ assign_a( id ) ] >> ')' >> '{'
321 )
322 | (
323 str_p( "CLASS" )[ assign_a( block_type ) ]
324 >> '(' >> c_const_expr_p[ assign_a( id ) ] >> ')' >> '{'
325 )
326 | (
327 str_p( "KERNEL_DOMAIN" )[ assign_a( block_type ) ] >> '{'
328 ),
329 space_p );
330 if ( info.hit ) // CLASS or DOMAINブロック開始ならば...
331 {
332 block_t b;
333 b.type = block_type;
334 b.id = id;
335 b.line = iter.line();
336 idexp = id; // 字面としてのIDを保存
337
338 if ( block_type == "CLASS" )
339 {
340 if ( !get_global< bool >( "has-class" ) )
341 {
342 error( "cannot use `%1%'", "CLASS" );
343 }
344 }
345 if ( block_type == "DOMAIN" || block_type == "KERNEL_DOMAIN" )
346 {
347 if ( !get_global< bool >( "has-domain" ) )
348 {
349 error( "cannot use `%1%'", block_type );
350 }
351 }
352 // カーネルドメインを通常のドメインと同じように扱えるように変形
353 if ( block_type == "KERNEL_DOMAIN" )
354 {
355 block_type = "DOMAIN";
356 id = "TDOM_KERNEL";
357 b.type = block_type;
358 b.id = id;
359 }
360 else if ( block_type == "DOMAIN" ) // ドメインIDの仮登録
361 {
362 bool hit = false;
363 for ( std::vector< std::pair< std::string, long > >::const_iterator iter( domid_table.begin() ), last( domid_table.end() );
364 iter != last;
365 ++iter )
366 {
367 if ( iter->first == id )
368 {
369 hit = true;
370 break;
371 }
372 }
373 if ( !hit )
374 {
375 domid_table.push_back( std::make_pair( id, 0L ) );
376 }
377 }
378 else if ( block_type == "CLASS" ) // クラスIDの登録
379 {
380 // クラスIDに式を使えるようにしたため、識別子に使える形式に変換する必要がある
381 std::tr1::uint64_t hash = 0;
382 for ( const char* s = id.c_str(); *s != '\0'; ++s )
383 {
384 hash = ( ( hash << 1 ) | ( hash >> 63 ) ) ^ static_cast< unsigned char >( *s );
385 }
386 id = boost::str( boost::format( "%02x_%016x_%u" ) % *id.c_str() % hash % id.size() );
387 b.id = id;
388
389 bool hit = false;
390 for ( std::vector< std::pair< std::string, long > >::const_iterator iter( clsid_table.begin() ), last( clsid_table.end() );
391 iter != last;
392 ++iter )
393 {
394 if ( iter->first == id )
395 {
396 hit = true;
397 break;
398 }
399 }
400 if ( !hit )
401 {
402 clsid_table.push_back( std::make_pair( id, 0L ) );
403 }
404 }
405
406 // 入れ子判定
407 if ( block_type == "CLASS" && !current_class.empty()
408 || block_type == "DOMAIN" && !current_domain.empty() )
409 {
410 fatal( iter.line(), _( "`%1%\' is nested" ), block_type );
411 }
412
413 block_stack.push( b );
414 block_table.push_back( b );
415
416 if ( block_type == "CLASS" )
417 {
418 oss << "\n#ifndef TOPPERS_cfg_valueof_" << id << "_DEFINED\n"
419 "#define TOPPERS_cfg_valueof_" << id << "_DEFINED 1\n";
420 oss << boost::format( "\n#line %1% \"%2%\"\n" ) % ( iter.line().line ) % dir_delimiter_to_slash( iter.line().file );
421
422 current_class = idexp;
423 oss << "const unsigned_t TOPPERS_cfg_valueof_" << id << " = " << idexp << ";\n";
424 }
425 if ( block_type == "DOMAIN" )
426 {
427 oss << "\n#ifndef TOPPERS_cfg_valueof_" << id << "_DEFINED\n"
428 "#define TOPPERS_cfg_valueof_" << id << "_DEFINED 1\n";
429 oss << boost::format( "\n#line %1% \"%2%\"\n" ) % ( iter.line().line ) % dir_delimiter_to_slash( iter.line().file );
430
431 current_domain = id;
432 oss << "const unsigned_t TOPPERS_cfg_valueof_" << id << " = ";
433 if ( id == "TDOM_KERNEL" )
434 {
435 oss << "-1" << ";\n";
436 }
437 else
438 {
439 oss << id << ";\n";
440 }
441 }
442 oss << "\n#endif\n";
443
444 oss << "#define TOPPERS_cfg_inside_of_" << id << "\n";
445
446 iter = boost::prior( info.stop );
447 }
448 else if ( *info.stop == '}' ) // ブロック末尾ならば...
449 {
450 if ( block_stack.empty() )
451 {
452 fatal( iter.line(), _( "syntax error" ) );
453 }
454 block_t b = block_stack.top();
455 block_stack.pop();
456
457 oss << "\n#ifndef TOPPERS_cfg_inside_of_" << b.id << "\n";
458 oss << boost::format( "\n#line %1% \"%2%\"\n" ) % ( iter.line().line ) % dir_delimiter_to_slash( iter.line().file );
459 oss << "#error syntax error\n"
460 "#endif\n";
461 oss << "#undef TOPPERS_cfg_inside_of_" << b.id << "\n"
462 "\n";
463
464 if ( b.type == "CLASS" )
465 {
466 current_class.clear();
467 }
468 if ( b.type == "DOMAIN" )
469 {
470 current_domain.clear();
471 }
472 iter = info.stop;
473 }
474 else
475 {
476 static_api api;
477 if ( api.parse( iter, last, info_map, false, codeset ) ) // 静的APIならば...
478 {
479 if ( !current_class.empty() )
480 {
481 api.set_class( current_class );
482 oss << "const unsigned_t TOPPERS_cfg_valueof_CLASS_" << serial << " = " << current_class << ";";
483 }
484 if ( !current_domain.empty() )
485 {
486 api.set_domain( current_domain );
487 oss << "const unsigned_t TOPPERS_cfg_valueof_DOMAIN_" << serial << " = " << current_domain << ";";
488 }
489
490 api_array.push_back( api );
491
492 oss << boost::format( "\n#line %1% \"%2%\"\n" ) % api.line().line % dir_delimiter_to_slash( api.line().file );
493 oss << "const unsigned_t TOPPERS_cfg_static_api_" << serial << " = " << serial << ";\n";
494
495 if ( !api.params().empty() && api.begin()->symbol[0] == '#' ) // オブジェクト識別名
496 {
497 std::string object_id( api.begin()->text );
498 bool valid_object_id = true;
499 if ( !object_id.empty() && ( std::isalpha( static_cast< unsigned char >( object_id[ 0 ] ) ) || object_id[ 0 ] == '_' ) )
500 {
501 for ( std::string::const_iterator id_iter( object_id.begin() + 1 ), id_last( object_id.end() );
502 id_iter != id_last;
503 ++id_iter )
504 {
505 if ( !( std::isalnum( static_cast< unsigned char >( *id_iter ) ) || *id_iter == '_' ) )
506 {
507 valid_object_id = false;
508 }
509 }
510 }
511 else
512 {
513 valid_object_id = false;
514 }
515 if ( !valid_object_id )
516 {
517 error( _( "`%1%\' is illegal object identifier" ), object_id );
518 }
519 else
520 {
521 oss << "#define " << object_id << "\t(<>)\n"; // でたらめな字句(基本ソース文字集合のみで構成)に定義することで、誤使用を検出する
522 oss << boost::format( "\n#line %1% \"%2%\"\n" ) % ( api.line().line ) % dir_delimiter_to_slash( api.line().file );
523 }
524 }
525 for ( static_api::iterator api_iter( api.begin() ), api_last( api.end() );
526 api_iter != api_last;
527 ++api_iter )
528 {
529 if ( ( api_iter->symbol[0] == '.' ) || ( api_iter->symbol[0] == '+' ) )
530 // 整数定数式パラメータのみ出力
531 {
532 char const* type;
533 if ( api_iter->symbol[0] == '.' )
534 {
535 type = "unsigned_t";
536 }
537 else
538 {
539 type = "signed_t";
540 }
541 oss << "const " << type << " ";
542
543 // 省略可能パラメータ情報の末尾にある ? を除去
544 std::string parameter_name( api_iter->symbol.c_str() + 1 );
545 if ( *parameter_name.rbegin() == '\?' )
546 {
547 parameter_name.resize( parameter_name.size() - 1 );
548 }
549 // 末尾の ... を除去 & order を付加
550 if ( parameter_name.size() > 3 && parameter_name.substr( parameter_name.size() - 3 ) == "..." )
551 {
552 parameter_name.resize( parameter_name.size() - 3 );
553 parameter_name += boost::lexical_cast< std::string >( api_iter->order );
554 }
555
556 oss << "TOPPERS_cfg_valueof_" << parameter_name << "_" << serial << " = ( " << type << " )( " << api_iter->text << " ); ";
557
558 // 暫定値を設定
559 char* endptr;
560 errno = 0;
561 unsigned long value = std::strtoul( api_iter->text.c_str(), &endptr, 0 );
562 if ( errno == 0 && *endptr == '\0' )
563 {
564 api_iter->value = value;
565 }
566 }
567 else if ( api_iter->symbol[0] == '$' ) // 文字列定数式パラメータ
568 {
569 // 省略可能パラメータ情報の末尾にある ? を除去
570 std::string parameter_name( api_iter->symbol.c_str() + 1 );
571 if ( *parameter_name.rbegin() == '\?' )
572 {
573 parameter_name.resize( parameter_name.size() - 1 );
574 }
575 // 末尾の ... を除去 & order を付加
576 if ( parameter_name.size() > 3 && parameter_name.substr( parameter_name.size() - 3 ) == "..." )
577 {
578 parameter_name.resize( parameter_name.size() - 3 );
579 parameter_name += boost::lexical_cast< std::string >( api_iter->order );
580 }
581
582 oss << "const char TOPPERS_cfg_valueof_" << parameter_name << "_" << serial << "[] = " << api_iter->text << "; ";
583 }
584 }
585 }
586 else
587 {
588 fatal( iter.line(), _( "syntax error" ) );
589 }
590
591 ++serial;
592 iter = boost::prior( iter );
593 }
594 }
595 }
596
597 for ( std::vector< block_t >::const_iterator iter( block_table.begin() ), last( block_table.end() );
598 iter != last;
599 ++iter )
600 {
601 oss << "\n#ifdef TOPPERS_cfg_inside_of_" << iter->id << "\n";
602 oss << "#error missing \'}\'\n"
603 "#endif\n";
604 }
605
606 // 統合仕様書1.1.0における2.14.2 TOPPERS共通データ型の規定により、ACPTNは32ビット符号無し整数型である。
607 // これにより、ドメインの最大数は32個でなければならない。
608 const std::size_t domain_max = 32;
609 if ( domid_table.size() > domain_max )
610 {
611 fatal( _( "there are too many %1% ids" ), "domain" );
612 }
613
614 std::string domid_defs_temp;
615
616 if ( get_global< bool >( "has-domain" ) )
617 {
618 load_id_input_file( id_map ); // --id-input-fileによるドメインIDの読み込み
619
620 std::string domids[ domain_max ];
621
622 // 一周目は、--id-input-fileオプションを反映
623 for ( std::vector< std::pair< std::string, long > >::iterator iter( domid_table.begin() ), last( domid_table.end() );
624 iter != last;
625 ++iter )
626 {
627 std::map< std::string, std::pair< long, bool > >::iterator hit = id_map.find( iter->first );
628 if ( hit != id_map.end() )
629 {
630 long domid = hit->second.first; // --id-input-fileオプションで指定された値
631 if ( domid > 32 )
632 {
633 fatal( _( "%1% id `%2%' is too large" ), "domain", hit->first );
634 }
635 domids[ domid - 1 ] = hit->first;
636 }
637 }
638 // 二周目は、残りのドメインIDを割り付ける
639 for ( std::vector< std::pair< std::string, long > >::iterator iter( domid_table.begin() ), last( domid_table.end() );
640 iter != last;
641 ++iter )
642 {
643 if ( id_map.find( iter->first ) == id_map.end() )
644 {
645 for ( int i = 0; i < sizeof( domids ) / sizeof( domids[ 0 ] ); i++ )
646 {
647 if ( domids[ i ].empty() )
648 {
649 domids[ i ] = iter->first;
650 break;
651 }
652 }
653 }
654 }
655 domid_table.clear();
656 for ( std::size_t i = 0; i < sizeof( domids ) / sizeof( domids[ 0 ] ); i++ )
657 {
658 domid_table.push_back( std::make_pair( domids[ i ], long( i + 1 ) ) );
659 }
660
661 // cfg1_out.c出力用のコードを生成
662 for ( std::vector< std::pair< std::string, long > >::iterator iter( domid_table.begin() ), last( domid_table.end() );
663 iter != last;
664 ++iter )
665 {
666 if ( !iter->first.empty() )
667 {
668 domid_defs_temp += ( boost::format( "#define %1%\t%2%\n" ) % iter->first % iter->second ).str();
669 }
670 }
671 }
672
673 // データメンバへの反映
674 std::string cfg1_list_temp( oss.str() );
675 std::string includes_temp( includes_oss.str() );
676
677 clsid_table_.swap( clsid_table );
678 domid_table_.swap( domid_table );
679 domid_defs_.swap( domid_defs_temp );
680 cfg1_out_list_.swap( cfg1_list_temp );
681 includes_.swap( includes_temp );
682 static_api_array_.swap( api_array );
683 block_table_.swap( block_table );
684 }
685
686 /*!
687 * \brief cfg1_out.c の内容生成
688 * \param[in] type 配列 cfg1_out[] の要素型。空ポインタの場合は uint32_t として扱われる。
689 */
690 void cfg1_out::generate( char const* type ) const
691 {
692 if ( type == 0 )
693 {
694 type = "uint32_t";
695 }
696 pimpl_->ofile_ << "/* cfg1_out.c */\n"
697 "#define TOPPERS_CFG1_OUT 1\n"
698 "#include \"kernel/kernel_int.h\"\n";
699 pimpl_->do_generate_includes();
700 pimpl_->ofile_ << pimpl_->includes_ << '\n';
701
702 // int128_tは故意に無視
703 // int128_tに揃えると処理が重くなりすぎるため
704 pimpl_->ofile_ << "\n#ifdef INT64_MAX\n"
705 " typedef int64_t signed_t;\n"
706 " typedef uint64_t unsigned_t;\n"
707 "#else\n"
708 " typedef int32_t signed_t;\n"
709 " typedef uint32_t unsigned_t;\n"
710 "#endif\n";
711
712 pimpl_->ofile_ << "\n#include <target_cfg1_out.h>\n\n";
713
714 pimpl_->do_generate_cfg1_def();
715 pimpl_->ofile_ << '\n' << pimpl_->domid_defs_ << '\n';
716 pimpl_->ofile_ << pimpl_->cfg1_out_list_ << '\n';
717 }
718
719 /*!
720 * \brief 静的API配列の参照
721 * \return 内部で保持している静的API配列への参照
722 */
723 std::vector< static_api > const& cfg1_out::get_static_api_array() const
724 {
725 return pimpl_->static_api_array_;
726 }
727
728 /*!
729 * \brief ドメインIDテーブルの参照
730 * \return 内部で保持しているドメインIDテーブルへの参照
731 */
732 std::vector< std::pair< std::string, long > > const& cfg1_out::get_domid_table() const
733 {
734 return pimpl_->domid_table_;
735 }
736
737 /*!
738 * \brief クラスIDテーブルの参照
739 * \return 内部で保持しているクラスIDテーブルへの参照
740 */
741 std::vector< std::pair< std::string, long > > const& cfg1_out::get_clsid_table() const
742 {
743 return pimpl_->clsid_table_;
744 }
745
746 /*!
747 * \brief #include指令の並びを取得する
748 * \return #include指令の並び
749 *
750 * このメンバ関数は、
751 * \code
752 * #include <...>
753 * #include "..."
754 * \endcode
755 * といった#include指令の並びを文字列として返す。
756 */
757 std::string const& cfg1_out::get_includes() const
758 {
759 return pimpl_->includes_;
760 }
761
762 /*!
763 * \brief Sレコードのロード
764 */
765 void cfg1_out::load_srec()
766 {
767 std::ifstream srec_ifs( ( pimpl_->ofile_.file_name() + ".srec" ).c_str() );
768 if ( !srec_ifs.is_open() )
769 {
770 fatal( _( "cannot open file `%1%\'" ), pimpl_->ofile_.file_name() + ".srec" );
771 }
772 pimpl_->srec_ = std::tr1::shared_ptr< s_record >( new s_record( srec_ifs ) );
773
774 std::ifstream syms_ifs( ( pimpl_->ofile_.file_name() + ".syms" ).c_str() );
775 if ( !syms_ifs.is_open() )
776 {
777 fatal( _( "cannot open file `%1%\'" ), pimpl_->ofile_.file_name() + ".syms" );
778 }
779 pimpl_->syms_ = std::tr1::shared_ptr< nm_symbol >( new nm_symbol( syms_ifs ) );
780
781 nm_symbol::entry nm_entry = pimpl_->syms_->find( "TOPPERS_cfg_magic_number" );
782 if ( nm_entry.type < 0 )
783 {
784 fatal( _( "magic number is not found in `%1%\'" ), ( pimpl_->ofile_.file_name() + ".srec/.syms" ) );
785 }
786 unsigned long magic[ 4 ];
787 magic[ 0 ] = ( *pimpl_->srec_ )[ nm_entry.address + 0 ];
788 magic[ 1 ] = ( *pimpl_->srec_ )[ nm_entry.address + 1 ];
789 magic[ 2 ] = ( *pimpl_->srec_ )[ nm_entry.address + 2 ];
790 magic[ 3 ] = ( *pimpl_->srec_ )[ nm_entry.address + 3 ];
791 unsigned long magic_number = ( magic[ 0 ] << 24 ) | ( magic[ 1 ] << 16 ) | ( magic[ 2 ] << 8 ) | magic[ 3 ];
792 if ( magic_number == 0x12345678 )
793 {
794 pimpl_->little_endian_ = false;
795 }
796 else if ( magic_number == 0x78563412 )
797 {
798 pimpl_->little_endian_ = true;
799 }
800 else
801 {
802 fatal( _( "magic number is not found in `%1%\'" ), ( pimpl_->ofile_.file_name() + ".srec/.syms" ) );
803 }
804 pimpl_->do_assign_params();
805 }
806
807 /*!
808 * \brief "cfg1_out.srec" から読み取った情報の参照
809 */
810 std::tr1::shared_ptr< s_record > cfg1_out::get_srec() const
811 {
812 return pimpl_->srec_;
813 }
814
815 /*!
816 * \brief "cfg1_out.syms" から読み取った情報の参照
817 */
818 std::tr1::shared_ptr< nm_symbol > cfg1_out::get_syms() const
819 {
820 return pimpl_->syms_;
821 }
822
823 cfg1_out::cfg1_def_table const* cfg1_out::get_def_table() const
824 {
825 return pimpl_->def_table_;
826 }
827
828 /*!
829 * \brief カーネルオブジェクトごとに静的API情報をまとめる
830 * \return 静的API情報
831 *
832 * この関数は、"tsk"や"sem"といった種別をキーとして、その種別に分類される静的API情報の連想配列を生成する。
833 */
834 cfg1_out::static_api_map cfg1_out::merge() const
835 {
836 static_api_map result;
837 for ( std::vector< static_api >::const_iterator iter( pimpl_->static_api_array_.begin() ), last( pimpl_->static_api_array_.end() );
838 iter != last;
839 ++iter )
840 {
841 static_api::info const* info = iter->get_info();
842 if ( info != 0 )
843 {
844 result[ info->type ].push_back( *iter );
845 }
846 }
847 return result;
848 }
849
850 /*!
851 * \brief リトルエンディアンかどうかの判定
852 * \retval true リトルエンディアン
853 * \retval false ビッグエンディアン
854 * \attention load_srec 呼び出し前は正しい結果を得られない。
855 */
856 bool cfg1_out::is_little_endian() const
857 {
858 return pimpl_->little_endian_;
859 }
860
861 /*!
862 * \brief 静的APIのパラメータにSレコードから取得した値を代入する
863 */
864 void cfg1_out::implementation::do_assign_params()
865 {
866 std::vector< toppers::itronx::static_api > temp_array;
867
868 for ( std::vector< static_api >::size_type serial = 0, n = static_api_array_.size(); serial < n; ++serial )
869 {
870 toppers::itronx::static_api api( static_api_array_.at( serial ) );
871
872 nm_symbol::entry nm_entry = syms_->find( boost::str( boost::format( "TOPPERS_cfg_static_api_%d" ) % serial ) );
873 if ( nm_entry.type == -1 )
874 {
875 continue;
876 }
877
878 // sizeof( signed_t )
879 std::size_t const sizeof_signed_t = static_cast< std::size_t >( srec_->get_value( syms_->find( "TOPPERS_cfg_sizeof_signed_t" ).address, 4, little_endian_ ) );
880
881 for ( toppers::itronx::static_api::iterator api_iter( api.begin() ),
882 api_last( api.end() );
883 api_iter != api_last;
884 ++api_iter )
885 {
886 if ( ( api_iter->symbol[0] == '.' ) || ( api_iter->symbol[0] == '+' ) || ( api_iter->symbol[0] == '*' ) )
887 // 整数定数式パラメータのみ値を取得
888 {
889 std::string parameter_name( api_iter->symbol.c_str() + 1 );
890
891 // 省略可能パラメータ情報の末尾にある ? を除去
892 if ( *parameter_name.rbegin() == '\?' )
893 {
894 parameter_name.resize( parameter_name.size() - 1 );
895 }
896
897 std::string symbol = boost::str( boost::format( "TOPPERS_cfg_valueof_%s_%d" ) % parameter_name % serial );
898 nm_symbol::entry nm_entry = syms_->find( symbol );
899 if ( nm_entry.type == -1 )
900 {
901 continue;
902 }
903 const std::size_t size = sizeof_signed_t;
904 std::tr1::intmax_t value = srec_->get_value( nm_entry.address, size, little_endian_ );
905
906 if ( api_iter->symbol[0] == '+' )
907 {
908 value = make_signed( static_cast< std::tr1::uint32_t >( value ) );
909 }
910 api_iter->value = value;
911 }
912 else if ( api_iter->symbol[0] == '$' ) // 文字列定数式パラメータ
913 {
914 std::string parameter_name( api_iter->symbol.c_str() + 1 );
915
916 // 省略可能パラメータ情報の末尾にある ? を除去
917 if ( *parameter_name.rbegin() == '\?' )
918 {
919 parameter_name.resize( parameter_name.size() - 1 );
920 }
921
922 std::string symbol = boost::str( boost::format( "TOPPERS_cfg_valueof_%s_%d" ) % parameter_name % serial );
923 nm_symbol::entry nm_entry = syms_->find( symbol );
924 if ( nm_entry.type == -1 )
925 {
926 continue;
927 }
928 std::string string;
929 string.reserve( 256 );
930 char c;
931 for ( long i = 0; ( c = static_cast< char >( srec_->get_value( nm_entry.address + i, 1, little_endian_ ) ) ) != '\0'; i++ )
932 {
933 string.push_back( c );
934 }
935
936 api_iter->string = string;
937 }
938 }
939 temp_array.push_back( api );
940 }
941 static_api_array_.swap( temp_array );
942 }
943
944 /*!
945 * \brief --id-input-fileオプションで指定したファイルの読み込み
946 * \id_map 読み込んだデータの格納先
947 */
948 void cfg1_out::load_id_input_file( std::map< std::string, std::pair< long, bool > >& id_map )
949 {
950 std::string id_input_file( get_global< std::string >( "id-input-file" ) );
951 if ( id_input_file.empty() )
952 {
953 return;
954 }
955
956 std::ifstream ifs( id_input_file.c_str() );
957 while ( ifs )
958 {
959 std::string linebuf;
960 std::getline( ifs, linebuf );
961 if ( ifs.bad() )
962 {
963 fatal( _( "I/O error" ) );
964 }
965 if ( linebuf.empty() || linebuf == "\r" )
966 {
967 break;
968 }
969
970 std::istringstream iss( linebuf );
971 std::string name;
972 iss >> name;
973 if ( iss.fail() )
974 {
975 fatal( _( "id file `%1%\' is invalid" ), id_input_file );
976 }
977
978 long value;
979 iss >> value;
980 if ( iss.fail() )
981 {
982 fatal( _( "id file `%1%\' is invalid" ), id_input_file );
983 }
984
985 if ( id_map.find( name ) != id_map.end() )
986 {
987 fatal( _( "`%1%\' is duplicated" ), name );
988 }
989 else
990 {
991 id_map[ name ] = std::make_pair( value, false );
992 }
993 }
994 }
995
996 }
997}
Note: See TracBrowser for help on using the repository browser.