1#!/usr/bin/perl -s 2 3############################################################################## 4# 5# Project: TwlSDK - header generator - 6# File: header_generator_ioreg.TWL.pl 7# 8# Copyright 2007-2008 Nintendo. All rights reserved. 9# 10# These coded instructions, statements, and computer programs contain 11# proprietary information of Nintendo of America Inc. and/or Nintendo 12# Company Ltd., and are protected by Federal copyright law. They may 13# not be disclosed to third parties or copied or duplicated in any form, 14# in whole or in part, without the prior written consent of Nintendo. 15# 16# $Date:: 2008-10-20#$ 17# $Rev: 9005 $ 18# $Author: okubata_ryoma $ 19############################################################################## 20 21# 22# Header file macro generation script 23# 24# How to use: 25# conv.pl [-v] [-dup] filename1.csv [filename2.csv ...] 26# 27# This outputs the header file(s) filename1.h (filename2.h) from the CSV file for which macro definitions are listed. 28# 29# 30# See (SDKRoot)/docs/private/how-to-make-headers.txt for CSV file format. 31# 32# 33 34use Text::ParseWords; 35 36# 37# Global variables 38# 39$line_no = 0; 40%name_hash = (); 41@hash_array = (); 42 43 44 45 46# 47# verbose output 48# 49sub verbose { 50 if ($verbose_mode == 1) { 51 print STDERR @_; 52 } 53} 54 55 56 57 58# 59# Remove spaces at beginning and end of field. 60# 61sub trim { 62 my @out = @_; 63 for (@out) { 64 s/^\s+//; 65 s/\s+$//; 66 } 67 return @out; 68} 69 70 71 72 73# 74# CSV parsing routine 75# 76sub parse_csv { 77 my @fields = quotewords(",", 0, shift @_); 78 @fields = trim(@fields); 79 80 my $tmp; 81 # Remove the "...." at the end of the line 82 while(defined($tmp = pop @fields) && $tmp =~ /^$/ ) { 83 ; 84 } 85 push @fields, $tmp; 86 87 return @fields; 88} 89 90 91 92 93# 94# Preprocessor 95# 96sub preprocess { 97 return parse_csv(shift @_); 98} 99 100 101 102 103# 104# Check for duplicate macro names 105# 106 107sub check_macro_duplicate { 108 my $name = shift @_; 109 my $condition = shift @_; 110 my $no = shift @_; 111 112 if ($condition ne "") { 113 return 0; 114 } 115 116 if (exists $name_hash{$name}) { 117 if ($duplicate_ok == 1) { 118 print STDERR "WARNING: generating duplicate macro \'$name\' in line $no\n"; 119 } else { 120 die "ERROR: duplicate macro \'$name\' in line $no"; 121 } 122 return 1; 123 } else { 124 $name_hash{$name} = 1; 125 return 0; 126 } 127} 128 129 130 131# 132# Analyze 133# 134sub analyze { 135 my @fields = @_; 136 137 my $fields; 138 my $tmphash; 139 my $address, $condition, $name, $bitwidth, $rw, $category, $volatile; 140 $tmphash = {}; 141 142 $address = shift @fields; 143 die "ERROR: Illegal address \'$address\' in line $line_no\n" unless ($address =~ /^0x[0-9A-Fa-f]+$/); 144 145 $condition = shift @fields; 146 die "ERROR: Illegal condition name \'$condition\' in line $line_no\n" unless ($address =~ /^[A-Za-z0-9_()&|!]+$/); 147 148 $name = shift @fields; 149 die "ERROR: Illegal macro name \'$name\' in line $line_no\n" unless ($name =~ /^[A-Za-z0-9_]+$/); 150 check_macro_duplicate($name, $condition, $line_no); 151 152 153 $bitwidth = shift @fields; 154 if ($bitwidth eq "8") { 155 $mask_format = "0x%02x"; 156 } elsif ($bitwidth eq "16") { 157 $mask_format = "0x%04x"; 158 } elsif ($bitwidth eq "32") { 159 $mask_format = "0x%08x"; 160 } elsif ($bitwidth eq "64") { 161 $mask_format = "0x%016x"; 162 } else { 163 die "ERROR: Illegal bitwidth \'$bitwidth\' in line $line_no\n"; 164 } 165 166 167 $rw = shift @fields; 168 $category = shift @fields; 169 $volatile = shift @fields; 170 171 $tmphash->{"condition"} = $condition; 172 $tmphash->{"name"} = $name; 173 $tmphash->{"offset"} = $address; 174 $tmphash->{"bitwidth"} = $bitwidth; 175 $tmphash->{"rw"} = $rw; 176 if ($rw eq "r") { 177 $tmphash->{"const"} = "const"; 178 } else { 179 $tmphash->{"const"} = ""; 180 } 181 182 $tmphash->{"category"} = $category; 183 184 if ($volatile eq "volatile") { 185 $tmphash->{"volatile"} = "v"; 186 } elsif ($volatile eq "permanent") { 187 $tmphash->{"volatile"} = ""; 188 } else { 189 die "ERROR: specify volatile/permanent in line $line_no\n"; 190 } 191 192 @{$tmphash->{"option"}} = splice @fields, 0; 193 194 $tmphash->{"mask_format"} = $mask_format; 195 $tmphash->{"line_no"} = $line_no; 196 return $tmphash; 197} 198 199 200# 201# Add elements to array 202# If there are duplicates, link them as linear list 203# 204sub push_fields { 205 my $hash = shift @_; 206 my $array_num; 207 my $tmp_hash; 208 209 # If the same name is already registered, add it to hash table as linear list 210 if ( exists($index_name_hash{ $hash->{"name"} }) ) { 211 $array_num = $index_name_hash{ $hash->{"name"} }; # Get index of corresponding array 212 # Add so that (condition eq "") comes to the end of linear list 213 $tmp_hash = $hash_array[ $array_num ]; 214 if ( $tmp_hash->{"condition"} eq "") { 215 $hash->{"next"} = $tmp_hash; 216 $hash_array[ $array_num] = $hash; 217 return; 218 } 219 220 while ( exists($tmp_hash->{"next"}) ) { 221 if ($tmp_hash->{"next"}->{"condition"} eq "") { 222 $hash->{"next"} = $tmp_hash->{"next"}; 223 $tmp_hash->{"next"} = $hash; 224 return; 225 } 226 $tmp_hash = $tmp_hash->{"next"}; 227 } 228 $tmp_hash->{"next"} = $hash; 229 } else { 230 $array_num = @hash_array; 231 $index_name_hash{ $hash->{"name"} } = $array_num; 232 push @hash_array, $hash; 233 } 234} 235 236 237# 238# Category information collection 239# 240sub collect_category { 241 my %cat_hash; 242 my $hash; 243 foreach $hash (@hash_array) { 244 $cat_hash{$hash->{"category"}} = 1; 245 } 246 return (keys %cat_hash); 247} 248 249# 250# Merge condition 251# 252sub merge_condition { 253 my $cond1 = shift @_; 254 my $cond2 = shift @_; 255 my $name = shift @_; 256 257 my $merged_cond; 258 259 if ( $cond1 eq "" || $cond2 eq "") { 260 $merged_cond = ""; 261 return $merged_cond; 262 } 263 264 if ( "$cond1" eq "!$cond2" || "!$cond1" eq "$cond2" ) { 265 $merge_cond = ""; 266 } else { 267 $merged_cond = "$cond1 || $cond2"; 268 } 269 270 return $merged_cond; 271} 272 273 274# 275# Get offset definition of register 276# 277sub cull_register_offset_def { 278 my $hash = shift @_; 279 280 my $offset_name; 281 my @tmp_hash; 282 my @def_array = (); 283 my $i, $k; 284 285 $i = 0; 286 while ( 1 ) { 287 288 { 289 $offset_name = "REG_$hash->{'name'}_OFFSET"; 290 $hash->{"offset_def"} = $offset_name; 291 $hash->{"address_def"} = "REG_$hash->{'name'}_ADDR"; 292 # Keep this variable definition because it is used later 293 $hash->{"valname_def"} = "REG_$hash->{'category'}_$hash->{'name'}"; 294 $hash->{"valname_def_new"} = "reg_$hash->{'category'}_$hash->{'name'}"; 295 } 296 297 $tmp_hash[$i]->{"condition"} = $hash->{"condition"}; 298 $tmp_hash[$i]->{"name"} = $hash->{"name"}; 299 $tmp_hash[$i]->{"offset_def"} = $hash->{"offset_def"}; 300 $tmp_hash[$i]->{"offset"} = $hash->{"offset"}; 301 $tmp_hash[$i]->{"address_def"} = $hash->{"address_def"}; 302 $tmp_hash[$i]->{"valname_def"} = $hash->{"valname_def"}; 303 $tmp_hash[$i]->{"valname_def_new"} = $hash->{"valname_def_new"}; 304 305 my $val = "(*($hash->{'const'} REGType$hash->{'bitwidth'}$hash->{'volatile'} *) $hash->{'address_def'})"; 306 307 $tmp_hash[$i]->{"reg_type"} = $val; 308 309 my $find_flg = 0; 310 311 #If reg_type and offset are identical, merge condition 312 foreach $k (@def_array) { 313 if ( $k->{'condition'} eq "" ) { 314 # Field without conditions should come last, so if it exists ahead already, condition setting is wrong 315 print STDERR "WARNING: illegal condition in \'$k->{'name'}\'\n"; 316 } 317 318 if ( ($k->{"reg_type"} eq $tmp_hash[$i]->{"reg_type"}) && ($k->{"offset"} eq $tmp_hash[$i]->{"offset"}) ) 319 { 320 $k->{'condition'} = merge_condition( $k->{'condition'}, $tmp_hash[$i]->{'condition'}, $k->{'name'} ); 321 $find_flg = 1; 322 last; 323 } 324 } 325 if ($find_flg == 0) { 326 push @def_array, $tmp_hash[$i]; 327 $i++; 328 } 329 330 # If still in the list, process the next 331 if (exists($hash->{"next"})) { 332 $hash = $hash->{"next"}; 333 } else { 334 last; 335 } 336 } 337 338 return @def_array; 339} 340 341 342# 343# Output 344# 345sub output { 346 my $output_filename = shift @_; 347 my $category = shift @_; 348 349 # Open output file 350 351 open OUT, ">$output_filename" or die "ERROR: Cannot create file \'$output_filename\'\n"; 352 my $handle = OUT; 353# my $handle = STDOUT; 354 355 my $include_guard = $output_filename; 356 $include_guard =~ s/[.\/]/_/g; 357 $include_guard = uc($include_guard). "_"; 358 359 # 360 # Output 361 # 362 print $handle <<ENDDOC; 363/*---------------------------------------------------------------------------* 364 Project: TwlSDK - IO Register List - 365 File: $output_filename 366 367 Copyright 2007-2008 Nintendo. All rights reserved. 368 369 These coded instructions, statements, and computer programs contain 370 proprietary information of Nintendo of America Inc. and/or Nintendo 371 Company Ltd., and are protected by Federal copyright law. They may 372 not be disclosed to third parties or copied or duplicated in any form, 373 in whole or in part, without the prior written consent of Nintendo. 374 375 *---------------------------------------------------------------------------*/ 376// 377// I was generated automatically, don't edit me directly!!! 378// 379#ifndef $include_guard 380#define $include_guard 381 382#ifndef SDK_ASM 383#include <nitro/types.h> 384#include <twl/hw/ARM9/mmap_global.h> 385#endif 386 387#ifdef __cplusplus 388extern "C" { 389#endif 390 391/* 392 * Definition of Register offsets, addresses and variables. 393 */ 394 395 396ENDDOC 397 my $hash, $tmp_hash; 398 399 foreach $hash (@hash_array) { 400 next if ($hash->{"category"} ne $category); 401 402 print $handle "/* $hash->{'name'} */\n\n"; 403 404 my @reg_array = cull_register_offset_def($hash); # Optimize duplicate items 405 my $nest_state = 0; 406 407 foreach $tmp_hash (@reg_array) 408 { 409 if ($tmp_hash->{"condition"} ne "") { 410 if ($nest_state == 0) { 411 $nest_state = 1; 412 printf $handle "#if %s\n\n", $tmp_hash->{'condition'}; 413 } elsif ($nest_state == 1) { 414 printf $handle "\n#elif %s\n\n", $tmp_hash->{'condition'}; 415 } 416 } elsif ($nest_state == 1) { 417 printf $handle "\n#else\n\n"; 418 } 419 420 printf $handle "#define %-50s %s\n", $tmp_hash->{'offset_def'}, $tmp_hash->{'offset'}; 421 printf $handle "#define %-50s %s\n", $tmp_hash->{"address_def"}, "(HW_REG_BASE + $tmp_hash->{'offset_def'})"; 422 printf $handle "#define %-50s %s\n", $tmp_hash->{"valname_def_new"}, $tmp_hash->{"reg_type"}; 423 424 if ($nest_state == 1) { 425 printf $handle "// endif %s\n", $tmp_hash->{"condition"} 426 } 427 } 428 429 printf $handle "\n"; 430 if ($nest_state == 1) { 431 printf $handle "#endif\n\n"; 432 } 433 } 434 435 print $handle <<ENDDOC; 436 437/* 438 * Definitions of Register fields 439 */ 440 441ENDDOC 442 my $hash; 443 my $nest_state; 444 445 foreach $hash (@hash_array) { 446 next if ($hash->{"category"} ne $category); 447 448 $nest_state = 0; 449 450 printf $handle "\n"; 451 print $handle "/* $hash->{'name'} */\n"; 452 453 while ( 1 ) { 454 if ($hash->{"condition"} ne "") { 455 if ($nest_state == 0) { 456 $nest_state = 1; 457 printf $handle "#if %s\n", $hash->{'condition'}; 458 } elsif ($nest_state == 1) { 459 printf $handle "#elif %s\n", $hash->{'condition'}; 460 } 461 } elsif ($nest_state == 1) { 462 printf $handle "#else\n"; 463 } 464 465 my $no = $hash->{"line_no"}; 466 467 my @array = @{$hash->{"option"}}; 468 469 my $field_macro_func = "#define $hash->{'valname_def'}_FIELD("; 470 my $field_macro_flag = 0; 471 my $field_macro_body = " (u$hash->{'bitwidth'})( \\\n"; 472 473 my $fieldname, $fieldshift, $fieldsize; 474 while($fieldname = shift @array) { 475 my $shift_macro; 476 477 die "ERROR: Field option not good in line $no\n" if (!defined($fieldshift = shift @array)); 478 die "ERROR: Field option not good in line $no\n" if (!defined($fieldsize = shift @array)); 479 480 print $handle "\n"; 481 482 # Output REG_XXX_XXXXX_SHIFT 483 { 484 my $name = "$hash->{'valname_def'}_" . $fieldname . "_SHIFT"; 485 check_macro_duplicate($name, $hash->{'condition'}, $no); 486 $shift_macro = $name; 487 printf $handle "#define %-50s %s\n", $name, $fieldshift; 488 } 489 490 # Output REG_XXX_XXXXX_SIZE 491 { 492 my $name = "$hash->{'valname_def'}_" . $fieldname . "_SIZE"; 493 check_macro_duplicate($name, $hash->{'condition'}, $no); 494 printf $handle "#define %-50s %s\n", $name, $fieldsize; 495 } 496 497 # Output REG_XXX_XXXXX_MASK 498 { 499 my $width = $hash->{"bitwidth"}; 500 my $mask_val = 1 << $fieldshift; 501 my $tmp = $mask_val; 502 my $i; 503 for ($i = 0; $i < $fieldsize - 1; $i++) { 504 $mask_val = $mask_val << 1; 505 $mask_val = $mask_val + $tmp; 506 } 507 my $name = "$hash->{'valname_def'}_" . $fieldname . "_MASK"; 508 check_macro_duplicate($name, $hash->{'condition'}, $no); 509 printf $handle "#define %-50s $hash->{'mask_format'}\n", $name, $mask_val; 510 } 511 512 # Create one line worth of definition of REG_XXX_XXXXX_FIELD 513 my $fn = lc($fieldname); 514 if ($field_macro_flag == 1) { 515 $field_macro_func = $field_macro_func . ", " . $fn; 516 $field_macro_body = $field_macro_body . " | \\\n" . " ((u32)($fn) << $shift_macro)"; 517 } else { 518 $field_macro_func = $field_macro_func . " " . $fn; 519 $field_macro_body = $field_macro_body . " ((u32)($fn) << $shift_macro)"; 520 $field_macro_flag = 1; 521 } 522 } 523 524 if ($field_macro_flag == 1) { 525 # Output REG_XXX_XXXXX_FIELD 526 $field_macro_func .= " ) \\\n"; 527 $field_macro_func .= $field_macro_body; 528 print $handle "\n#ifndef SDK_ASM\n"; 529 print $handle $field_macro_func, ")\n"; 530 print $handle "#endif\n\n" 531 532 } 533 if ($nest_state == 1) { 534 printf $handle "// endif %s\n", $hash->{"condition"}; 535 if ( !exists($hash->{"next"})) { 536 printf $handle "#endif \n\n"; 537 } 538 } 539 540 # If still in the list, display the next 541 if (exists($hash->{'next'})) { 542 $hash = $hash->{'next'}; 543 } else { 544 last; 545 } 546 } 547 } 548 549 print $handle <<ENDDOC; 550 551#ifdef __cplusplus 552} /* extern "C" */ 553#endif 554 555/* $include_guard */ 556#endif 557ENDDOC 558 559 verbose("done.\n"); 560} 561 562# 563# Set command line option 564# 565 566 567# If -v or -verbose is specified, verbose mode 568if ($v == 1 || $verbose == 1) { 569 $verbose_mode = 1; 570 verbose("verbose mode on\n"); 571} else { 572 $verbose_mode = 0; 573} 574 575# If -nodup is specified, duplicate macro names are not allowed 576if ($nodup == 1) { 577 $duplicate_ok = 0; 578} else { 579 $duplicate_ok = 1; 580} 581 582 583 584 585# 586# Main routine 587# 588foreach $filename (@ARGV) { 589 $line_no = 0; 590 @hash_array = (); 591 592 open INPUTFILE, "$filename" or die "ERROR: Cannot open file \'$filename\'\n"; 593 594 my $line; 595 while($line = <INPUTFILE>) { 596 $line_no++; 597 $line =~ s/\"//g; 598 $line =~ s/\#.*//; 599 next if ($line =~ /^[\s,]*$/); 600 601 @fields = preprocess($line); 602 push @hash_array, analyze(@fields); 603 } 604 verbose("$line_no lines read\n"); 605 606 my @categories = collect_category(); 607 my $category; 608 my @headerfile_array = (); 609 610 611 foreach $category (@categories) { 612 my $output_filename = $filename; 613 if (($output_filename =~ s/\.csv/\.h/) == 0) { 614 $output_filename .= ".h"; 615 } 616 $output_filename =~ s/\.h/_$category.h/; 617 618 push @headerfile_array, $output_filename; 619 620 verbose("Output filename is $output_filename\n"); 621 output($output_filename, $category); 622 } 623 624 my $master_filename = $filename; 625 if (($master_filename =~ s/\.csv/\.h/) == 0) { 626 $master_filename .= ".h"; 627 } 628 629 open MASTER, ">$master_filename" or die "ERROR: Cannot create file \'$master_filename$'\n"; 630 631 my $include_guard = $master_filename; 632 $include_guard =~ s/[.\/]/_/g; 633 $include_guard = uc($include_guard). "_"; 634 635 print MASTER <<ENDDOC; 636/*---------------------------------------------------------------------------* 637 Project: TwlSDK - IO Register List - 638 File: $master_filename 639 640 Copyright 2007-2008 Nintendo. All rights reserved. 641 642 These coded instructions, statements, and computer programs contain 643 proprietary information of Nintendo of America Inc. and/or Nintendo 644 Company Ltd., and are protected by Federal copyright law. They may 645 not be disclosed to third parties or copied or duplicated in any form, 646 in whole or in part, without the prior written consent of Nintendo. 647 648 *---------------------------------------------------------------------------*/ 649 650#ifndef $include_guard 651#define $include_guard 652 653#ifdef __cplusplus 654extern "C" { 655#endif 656 657ENDDOC 658 659 foreach $header_file (@headerfile_array) { 660 print MASTER "#include <$header_file>\n" 661 } 662 663 print MASTER <<ENDDOC; 664 665#ifdef __cplusplus 666} /* extern "C" */ 667#endif 668 669/* $include_guard */ 670#endif 671ENDDOC 672 673 674} 675 676 677 678 679 680