e32tools/armasm2as.pl
changeset 40 68f68128601f
parent 39 fa9d7d89d3d6
child 41 1600211976c3
equal deleted inserted replaced
39:fa9d7d89d3d6 40:68f68128601f
     1 # Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 # All rights reserved.
       
     3 # This component and the accompanying materials are made available
       
     4 # under the terms of "Eclipse Public License v1.0"
       
     5 # which accompanies this distribution, and is available
       
     6 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 #
       
     8 # Initial Contributors:
       
     9 # Nokia Corporation - initial contribution.
       
    10 #
       
    11 # Contributors:
       
    12 # Mike Kinghan, mikek@symbian.org, for Symbian Foundation
       
    13 #
       
    14 # Description:
       
    15 # e32toolp\e32util\armasm2as.pl
       
    16 # Convert an ARMASM assembler source or include file to AS format
       
    17 # Syntax:
       
    18 # perl armasm2as.pl <input> <output>
       
    19 # 
       
    20 #
       
    21 
       
    22 if (scalar(@ARGV)!=2) {
       
    23 	die "perl armasm2as.pl <input> <output>\n";
       
    24 }
       
    25 my ($infile, $outfile) = @ARGV;
       
    26 open IN, $infile or die "Can't open $infile for input\n";
       
    27 my $gccfile;
       
    28 my @input;
       
    29 while (<IN>) {
       
    30 	push @input, $_;
       
    31 	next if defined($gccfile);
       
    32 	next if (/^\s*$/);
       
    33 	if (/^\s*\@/) {
       
    34 		$gccfile = 1;	# If first non-blank line starts with @, assume already in GCC format
       
    35 	} else {
       
    36 		$gccfile = 0;
       
    37 	}
       
    38 }
       
    39 close IN;
       
    40 my @output;
       
    41 my $outref = \@output;
       
    42 if ($gccfile) {
       
    43 	$outref = \@input;
       
    44 } else {
       
    45 	process(\@input, \@output);
       
    46 }
       
    47 open OUT, ">$outfile" or die "Can't open $outfile for write\n";
       
    48 print OUT @$outref;
       
    49 close OUT;
       
    50 
       
    51 
       
    52 
       
    53 sub process($$) {
       
    54 	my $level=0;
       
    55 	my @block;
       
    56 	my ($inref, $outref) = @_;
       
    57 	foreach $line (@$inref) {
       
    58 		$line=~s/\s*$//;
       
    59 		my $comment;
       
    60 		if ($line =~ /\;(.*)$/o) {
       
    61 			$comment = $1;
       
    62 			$line =~ s/\;(.*)$//o;
       
    63 			if ($line =~ /^\s*$/o and $level==0) {
       
    64 				push @$outref, "$line\@$comment\n";
       
    65 				next;
       
    66 			}
       
    67 			$comment = "\t\@$comment";
       
    68 		}
       
    69 		if ($line =~ /^\s+PRESERVE8/) {
       
    70 			next;
       
    71 		}
       
    72 		if ($level == 1) {
       
    73 			if ($line =~ /^\s+MEND/i) {
       
    74 				process_macro(\@block, $outref);
       
    75 				$level = 0;
       
    76 			} else {
       
    77 				push @block, $line;
       
    78 			}
       
    79 			next;
       
    80 		} elsif ($level == 0) {
       
    81 			if ($line =~ /^\s+MACRO\s*$/i) {
       
    82 				@block = ();
       
    83 				$level = 1;
       
    84 				next;
       
    85 			}
       
    86 		}
       
    87 		if ($line =~ /^\s+GBLL\s+(\S+)/i) {
       
    88 			push @$outref, "\t.set\t$1, 0$comment\n";
       
    89 			next;
       
    90 		}
       
    91 		if ($line =~ /^\s+GBLA\s+(\S+)/i) {
       
    92 			push @$outref, "\t.set\t$1, 0$comment\n";
       
    93 			next;
       
    94 		}
       
    95 		if ($line =~ /^\s+INCLUDE\s+(\S+)/i) {
       
    96 			my $arg = $1;
       
    97 			if ($arg =~ /(\w+)\.inc/io) {
       
    98 				$arg = $1.'.ginc';
       
    99 			}
       
   100 			push @$outref, "\t.include\t\"$arg\"$comment\n";
       
   101 			next;
       
   102 		}
       
   103 		if ($line =~ /^\s+IMPORT\s+(\S+)/i) {
       
   104 			push @$outref, "\t.extern\t$1$comment\n";
       
   105 			next;
       
   106 		}
       
   107 		if ($line =~ /^\s+EXPORT\s+(\S+)/i) {
       
   108 			push @$outref, "\t.global\t$1$comment\n";
       
   109 			next;
       
   110 		}
       
   111 		if ($line =~ /^\s+ELSE/i or $line =~ /^\s+\|/i ) {
       
   112 			push @$outref, "\t.else$comment\n";
       
   113 			next;
       
   114 		}
       
   115 		if ($line =~ /^\s+ENDIF/i or $line =~ /^\s+\]/i) {
       
   116 			push @$outref, "\t.endif$comment\n";
       
   117 			next;
       
   118 		}
       
   119 		if ($line =~ /^\s+LTORG/i) {
       
   120 			push @$outref, "\t.ltorg$comment\n";
       
   121 			next;
       
   122 		}
       
   123 		if ($line =~ /^\s+END$/i) {
       
   124 			next;
       
   125 		}
       
   126 		if ($line =~ /^\s+\!\s*(\d+)\,\s*(.*?)$/) {
       
   127 			my $msg = $2;
       
   128 			push @$outref, "\t.print $msg\n\t.err$comment\n";
       
   129 			next;
       
   130 		}
       
   131 		if ($line =~ /^\s+INIT_LOGICAL_SYMBOL\s+(\w+)(.*?)$/) {
       
   132 			process_init_logical_symbol($1, $2, $outref, $comment);
       
   133 			next;
       
   134 		}
       
   135 		if ($line =~ /^\s+INIT_NUMERIC_SYMBOL\s+(\w+)\s*\,\s*(.*?)$/) {
       
   136 			process_init_numeric_symbol($1, $2, $outref, $comment);
       
   137 			next;
       
   138 		}
       
   139 		if ($line =~ /^\s+AREA\s+(.*?)$/) {
       
   140 			process_area($1, $outref, $comment);
       
   141 			next;
       
   142 		}
       
   143 		if ($line =~ /^\s+\%\s+(.*?)$/) {
       
   144 			my $expr = process_numeric_expr($1, $outref);
       
   145 			push @$outref, "\t.space $expr$comment\n";
       
   146 			next;
       
   147 		}
       
   148 		if ($line =~ /^\s+ALIGN\s*(.*?)$/) {
       
   149 			process_align($1, $outref, $comment);
       
   150 			next;
       
   151 		}
       
   152 
       
   153 		# Strip label if there is one
       
   154 		my $label;
       
   155 		if ($line =~ /^(\S+)\s*(.*?)$/) {
       
   156 			$label = $1;
       
   157 			$line = $2;
       
   158 		} else {
       
   159 			$line =~ s/^\s*//;
       
   160 		}
       
   161 		if ($line =~ /^SETL\s+(\S+)/i) {
       
   162 			my $val = $1;
       
   163 			my $expr = process_logical_expr($val, $outref);
       
   164 			push @$outref, "\t.set\t$label,$expr$comment\n";
       
   165 			next;
       
   166 		}
       
   167 		if ($line =~ /^SETA\s+(.*?)$/i) {
       
   168 			my $val = $1;
       
   169 			my $expr = process_numeric_expr($val, $outref);
       
   170 			push @$outref, "\t.set\t$label,$expr$comment\n";
       
   171 			next;
       
   172 		}
       
   173 		if ($line =~ /^(EQU|\*)\s+(.*?)$/i) {
       
   174 			my $val = $2;
       
   175 			my $expr = process_numeric_expr($val, $outref);
       
   176 			push @$outref, "\t.equ\t$label,$expr$comment\n";
       
   177 			next;
       
   178 		}
       
   179 		if ($line =~ /^(if|\[)\s+(.*?)$/i) {
       
   180 			my $cond = $2;
       
   181 			if ($cond =~ /^\s*(\:LNOT\:)?\s*\:DEF\:\s*(.*?)$/i) {
       
   182 				my $n = $1;
       
   183 				my $sym = $2;
       
   184 				if ($sym =~ /^(\w|\\|\:)+$/) {
       
   185 					if (uc($n) eq ':LNOT:') {
       
   186 						push @$outref, "\t.ifndef\t$sym$comment\n";
       
   187 					} else {
       
   188 						push @$outref, "\t.ifdef\t$sym$comment\n";
       
   189 					}
       
   190 					next;
       
   191 				}
       
   192 			}
       
   193 			my $expr = process_logical_expr($cond, $outref);
       
   194 			push @$outref, "\t.if $expr$comment\n";
       
   195 			next;
       
   196 		}
       
   197 		if ($line =~ /^(\=|DCB)\s*(.*?)$/) {
       
   198 			process_dcb($label, $2, $outref, $comment);
       
   199 			next;
       
   200 		}
       
   201 		if ($line =~ /^DCW\s*(.*?)$/) {
       
   202 			process_dcw($label, $1, $outref, $comment);
       
   203 			next;
       
   204 		}
       
   205 		if ($line =~ /^DCD\s*(.*?)$/) {
       
   206 			process_dcd($label, $1, $outref, $comment);
       
   207 			next;
       
   208 		}
       
   209 		if ($line =~ /^ROUT\s*$/) {
       
   210 			$line = '';
       
   211 		}
       
   212 		if ($line =~ /^(\w+)\s+\%(\w+)\s*$/o) {
       
   213 			# ARMASM local label reference
       
   214 			my $inst = $1;
       
   215 			my $llab = $2;
       
   216 			if ($llab =~ /F\w?(\d+)/o) {
       
   217 				$line = "$inst $1f";
       
   218 			} elsif ($llab =~ /B\w?(\d+)/o) {
       
   219 				$line = "$inst $1b";
       
   220 			} else {
       
   221 				die "Can't determine local label direction\n";
       
   222 			}
       
   223 		}
       
   224 		if ($line =~ /^(\w+)\s+(\w+)\s*\,\s*\%(\w+)\s*$/o) {
       
   225 			# ARMASM local label reference
       
   226 			my $inst = $1;
       
   227 			my $op1 = $2;
       
   228 			my $llab = $3;
       
   229 			if ($llab =~ /F\w?(\d+)/o) {
       
   230 				$line = "$inst $op1\, $1f";
       
   231 			} elsif ($llab =~ /B\w?(\d+)/o) {
       
   232 				$line = "$inst $op1\, $1b";
       
   233 			} else {
       
   234 				die "Can't determine local label direction\n";
       
   235 			}
       
   236 		}
       
   237 
       
   238 		$line = process_numeric_expr($line, $outref);
       
   239 		if (defined($label)) {
       
   240 			push @$outref, "$label\:\t$line$comment\n";
       
   241 		} else {
       
   242 			push @$outref, "\t$line$comment\n";
       
   243 		}
       
   244 	}
       
   245 }
       
   246 
       
   247 
       
   248 sub process_macro($$) {
       
   249 	my ($inref, $outref) = @_;
       
   250 	my $line;
       
   251 	while(1) {
       
   252 		$line = shift @$inref;
       
   253 		last if ($line !~ /^\s*$/);
       
   254 	}
       
   255 	unless ($line =~ /^\s+(\w+)\s*(.*?)$/) {
       
   256 		die "Bad macro - no name\n";
       
   257 	}
       
   258 	my $macro_name = $1;
       
   259 	if ($macro_name eq 'INIT_LOGICAL_SYMBOL' or $macro_name eq 'INIT_NUMERIC_SYMBOL') {
       
   260 		return;
       
   261 	}
       
   262 	$line = $2;
       
   263 	my @args = split ( '\s*,\s*', $line );
       
   264 	foreach (@args) {
       
   265 		die "Bad macro argument name\n" unless (/^\$\w+$/);
       
   266 		s/^\$//;
       
   267 	}
       
   268 	my $ev = '';
       
   269 	foreach $arg (@args) {
       
   270 		$ev.="s/\\\$$arg(\\W\|\$)/\\\\$arg\$1/go;";
       
   271 	}
       
   272 	foreach (@$inref) {
       
   273 		eval $ev;
       
   274 	}
       
   275 	push @$outref, "\t.macro $macro_name ".join(',',@args)."\n";
       
   276 	process($inref, $outref);
       
   277 	push @$outref, "\t.endm\n";
       
   278 }
       
   279 
       
   280 
       
   281 sub process_logical_expr($$) {
       
   282 	my ($val, $outref) = @_;
       
   283 	$val = process_numeric_expr($val, $outref);
       
   284 	$val =~ s/\<\=/________LE________/g;	# protect <= and >= during expansion of =
       
   285 	$val =~ s/\>\=/________GE________/g;
       
   286 	$val =~ s/\=/\=\=/g;					# equality operator is = on ARMASM, == on AS
       
   287 	$val =~ s/________LE________/\<\=/g;
       
   288 	$val =~ s/________GE________/\>\=/g;
       
   289 	$val =~ s/\{TRUE\}/(1)/g;
       
   290 	$val =~ s/\{FALSE\}/(0)/g;
       
   291 
       
   292 	my @lops = split( /(\s*\:LAND\:\s*|\s*\:LOR\:\s*|\s*\:LNOT\:\s*|\s*\:DEF\:\s*|\s*\(\s*|\s*\)\s*)/, $val );
       
   293 	my @lops2;
       
   294 	foreach (@lops) {
       
   295 		s/\s*\:LAND\:\s*/\:LAND\:/go;
       
   296 		s/\s*\:LOR\:\s*/\:LOR\:/go;
       
   297 		s/\s*\:LNOT\:\s*/\:LNOT\:/go;
       
   298 		s/\s*\:DEF\:\s*/\:DEF\:/go;
       
   299 	}
       
   300 	my @lops2;
       
   301 	while (scalar (@lops)) {
       
   302 		my $x = shift @lops;
       
   303 		if ($x eq ':DEF:') {
       
   304 			my $sym = shift @lops;
       
   305 			$sym =~ s/^\s*//;
       
   306 			$sym =~ s/\s*$//;
       
   307 			if ($sym =~ /^(\w|\$|\\)+$/) {
       
   308 				push @$outref, "\t.ifdef $sym\n\t.set __defined__$sym, 1\n\t.else\n\t.set __defined__$sym, 0\n\t.endif\n";
       
   309 				push @lops2, " __defined__$sym ";
       
   310 			} else {
       
   311 				die "Bad :DEF: operand $sym\n";
       
   312 			}
       
   313 		} elsif ($x eq ':LAND:') {
       
   314 			push @lops2, ' && ';
       
   315 		} elsif ($x eq ':LOR:') {
       
   316 			push @lops2, ' || ';
       
   317 		} else {
       
   318 			push @lops2, $x;
       
   319 		}
       
   320 	}
       
   321 	my @lops3;
       
   322 	while (scalar (@lops2)) {
       
   323 		my $x = shift @lops2;
       
   324 		if ($x eq ':LNOT:') {
       
   325 			my $operand;
       
   326 			while (1) {
       
   327 				$operand = shift @lops2;
       
   328 				last if ($operand !~ /^\s*$/);
       
   329 			}
       
   330 			push @lops3, "(0==($operand))";
       
   331 		} else {
       
   332 			push @lops3, $x;
       
   333 		}
       
   334 	}
       
   335 	return join('',@lops3);
       
   336 }
       
   337 
       
   338 sub process_numeric_expr($$) {
       
   339 	my ($val, $outref) = @_;
       
   340 	$val =~ s/\&/0x/g;			# ARMASM accepts hex numbers starting with & or 0x, AS only accepts 0x
       
   341 	$val =~ s/(\W|^)2_([0|1]+)(\W|$)/$1 0b$2$3/g;	# Binary numbers start with 2_ on ARMASM, 0b on AS
       
   342 	$val =~ s/\:AND\:/\&/g;
       
   343 	$val =~ s/\:OR\:/\|/g;
       
   344 	$val =~ s/\:SHL\:/\<\</g;
       
   345 	$val =~ s/\:SHR\:/\>\>/g;
       
   346 	return $val;
       
   347 }
       
   348 
       
   349 sub process_init_logical_symbol($$$$) {
       
   350 	my ($name, $rest, $outref, $comment) = @_;
       
   351 	my $counter;
       
   352 	if ($rest =~ /^\s*\,\s*(\w+)\s*$/) {
       
   353 		$counter = $1;
       
   354 	} elsif ($rest !~ /^\s*$/) {
       
   355 		die "Bad INIT_LOGICAL_SYMBOL\n";
       
   356 	}
       
   357 	push @$outref, "\t.ifndef $name$comment\n\t.set $name, 0\n\t.else\n\t.set $name, 1\n";
       
   358 	if ($counter) {
       
   359 		push @$outref, "\t.set $counter, $counter \+ 1\n";
       
   360 	}
       
   361 	push @$outref, "\t.endif\n";
       
   362 }
       
   363 
       
   364 sub process_init_numeric_symbol($$$$) {
       
   365 	my ($name, $value, $outref, $comment) = @_;
       
   366 	my $expr = process_numeric_expr($value, $outref);
       
   367 	push @$outref, "\t.ifndef $name$comment\n\t.set $name, $expr\n\t.endif\n";
       
   368 }
       
   369 
       
   370 sub process_area($$$) {
       
   371 	my ($line, $outref, $comment) = @_;
       
   372 	my @args = split(',',$line);
       
   373 	my $align = 0;
       
   374 	foreach (@args) {
       
   375 		if (/^\s*ALIGN\s*\=\s*(\d+)\s*$/) {
       
   376 			$align = $1;
       
   377 		}
       
   378 	}
       
   379 	push @$outref, "\t.text$comment\n\t.p2align $align\n";
       
   380 }
       
   381 
       
   382 sub process_align($$$) {
       
   383 	my ($line, $outref, $comment) = @_;
       
   384 	if ($line =~ /^\s*$/o) {
       
   385 		push @$outref, "\t.align$comment\n";
       
   386 	} else {
       
   387 		push @$outref, "\t.balign $line$comment\n";
       
   388 	}
       
   389 }
       
   390 
       
   391 sub process_dcb($$$$) {
       
   392 	my ($label, $args, $outref, $comment) = @_;
       
   393 	if (defined($label)) {
       
   394 		push @$outref, "$label\:";
       
   395 	}
       
   396 	while ($args !~ /^\s*$/) {
       
   397 		my $arg;
       
   398 		$args =~ s/^\s*//;
       
   399 		if ($args =~ /^\"/) {
       
   400 			$args =~ s/\\\"/________ESCAPED_QUOTE________/go;
       
   401 			$args =~ /\"(.*?)\"\s*(.*?)$/o or die "Unterminated string literal\n";
       
   402 			$arg = $1;
       
   403 			$args = $2;
       
   404 			$arg =~ s/________ESCAPED_QUOTE________/\\\"/go;
       
   405 			push @$outref, "\t.ascii \"$arg\"$comment\n";
       
   406 			undef $comment;
       
   407 			last if ($args !~ /\s*\,(.*?)$/o);
       
   408 			$args = $1;
       
   409 		} else {
       
   410 			$args =~ /(.*?)\s*(\,|$)(.*?)$/o;
       
   411 			$arg = $1;
       
   412 			$args = $3;
       
   413 			my $expr = process_numeric_expr($arg, $outref);
       
   414 			push @$outref, "\t.byte $expr$comment\n";
       
   415 			undef $comment;
       
   416 		}
       
   417 	}
       
   418 }
       
   419 
       
   420 sub process_dcw($$$$) {
       
   421 	my ($label, $args, $outref, $comment) = @_;
       
   422 	if (defined($label)) {
       
   423 		push @$outref, "$label\:";
       
   424 	}
       
   425 	while ($args !~ /^\s*$/) {
       
   426 		my $arg;
       
   427 		$args =~ s/^\s*//;
       
   428 		$args =~ /(.*?)\s*(\,|$)(.*?)$/o;
       
   429 		$arg = $1;
       
   430 		$args = $3;
       
   431 		my $expr = process_numeric_expr($arg, $outref);
       
   432 		push @$outref, "\t.hword $expr$comment\n";
       
   433 		undef $comment;
       
   434 	}
       
   435 }
       
   436 
       
   437 sub process_dcd($$$$) {
       
   438 	my ($label, $args, $outref, $comment) = @_;
       
   439 	if (defined($label)) {
       
   440 		push @$outref, "$label\:";
       
   441 	}
       
   442 	while ($args !~ /^\s*$/) {
       
   443 		my $arg;
       
   444 		$args =~ s/^\s*//;
       
   445 		$args =~ /(.*?)\s*(\,|$)(.*?)$/o;
       
   446 		$arg = $1;
       
   447 		$args = $3;
       
   448 		my $expr = process_numeric_expr($arg, $outref);
       
   449 		push @$outref, "\t.word $expr$comment\n";
       
   450 		undef $comment;
       
   451 	}
       
   452 }
       
   453 
       
   454 
       
   455