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