18c2ecf20Sopenharmony_ci#!/usr/bin/env perl 28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci# PowerPC assembler distiller by <appro>. 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_cimy $flavour = shift; 78c2ecf20Sopenharmony_cimy $output = shift; 88c2ecf20Sopenharmony_ciopen STDOUT,">$output" || die "can't open $output: $!"; 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cimy %GLOBALS; 118c2ecf20Sopenharmony_cimy $dotinlocallabels=($flavour=~/linux/)?1:0; 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci################################################################ 148c2ecf20Sopenharmony_ci# directives which need special treatment on different platforms 158c2ecf20Sopenharmony_ci################################################################ 168c2ecf20Sopenharmony_cimy $globl = sub { 178c2ecf20Sopenharmony_ci my $junk = shift; 188c2ecf20Sopenharmony_ci my $name = shift; 198c2ecf20Sopenharmony_ci my $global = \$GLOBALS{$name}; 208c2ecf20Sopenharmony_ci my $ret; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci $name =~ s|^[\.\_]||; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci SWITCH: for ($flavour) { 258c2ecf20Sopenharmony_ci /aix/ && do { $name = ".$name"; 268c2ecf20Sopenharmony_ci last; 278c2ecf20Sopenharmony_ci }; 288c2ecf20Sopenharmony_ci /osx/ && do { $name = "_$name"; 298c2ecf20Sopenharmony_ci last; 308c2ecf20Sopenharmony_ci }; 318c2ecf20Sopenharmony_ci /linux/ 328c2ecf20Sopenharmony_ci && do { $ret = "_GLOBAL($name)"; 338c2ecf20Sopenharmony_ci last; 348c2ecf20Sopenharmony_ci }; 358c2ecf20Sopenharmony_ci } 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci $ret = ".globl $name\nalign 5\n$name:" if (!$ret); 388c2ecf20Sopenharmony_ci $$global = $name; 398c2ecf20Sopenharmony_ci $ret; 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_cimy $text = sub { 428c2ecf20Sopenharmony_ci my $ret = ($flavour =~ /aix/) ? ".csect\t.text[PR],7" : ".text"; 438c2ecf20Sopenharmony_ci $ret = ".abiversion 2\n".$ret if ($flavour =~ /linux.*64le/); 448c2ecf20Sopenharmony_ci $ret; 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_cimy $machine = sub { 478c2ecf20Sopenharmony_ci my $junk = shift; 488c2ecf20Sopenharmony_ci my $arch = shift; 498c2ecf20Sopenharmony_ci if ($flavour =~ /osx/) 508c2ecf20Sopenharmony_ci { $arch =~ s/\"//g; 518c2ecf20Sopenharmony_ci $arch = ($flavour=~/64/) ? "ppc970-64" : "ppc970" if ($arch eq "any"); 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci ".machine $arch"; 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_cimy $size = sub { 568c2ecf20Sopenharmony_ci if ($flavour =~ /linux/) 578c2ecf20Sopenharmony_ci { shift; 588c2ecf20Sopenharmony_ci my $name = shift; $name =~ s|^[\.\_]||; 598c2ecf20Sopenharmony_ci my $ret = ".size $name,.-".($flavour=~/64$/?".":"").$name; 608c2ecf20Sopenharmony_ci $ret .= "\n.size .$name,.-.$name" if ($flavour=~/64$/); 618c2ecf20Sopenharmony_ci $ret; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci else 648c2ecf20Sopenharmony_ci { ""; } 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_cimy $asciz = sub { 678c2ecf20Sopenharmony_ci shift; 688c2ecf20Sopenharmony_ci my $line = join(",",@_); 698c2ecf20Sopenharmony_ci if ($line =~ /^"(.*)"$/) 708c2ecf20Sopenharmony_ci { ".byte " . join(",",unpack("C*",$1),0) . "\n.align 2"; } 718c2ecf20Sopenharmony_ci else 728c2ecf20Sopenharmony_ci { ""; } 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_cimy $quad = sub { 758c2ecf20Sopenharmony_ci shift; 768c2ecf20Sopenharmony_ci my @ret; 778c2ecf20Sopenharmony_ci my ($hi,$lo); 788c2ecf20Sopenharmony_ci for (@_) { 798c2ecf20Sopenharmony_ci if (/^0x([0-9a-f]*?)([0-9a-f]{1,8})$/io) 808c2ecf20Sopenharmony_ci { $hi=$1?"0x$1":"0"; $lo="0x$2"; } 818c2ecf20Sopenharmony_ci elsif (/^([0-9]+)$/o) 828c2ecf20Sopenharmony_ci { $hi=$1>>32; $lo=$1&0xffffffff; } # error-prone with 32-bit perl 838c2ecf20Sopenharmony_ci else 848c2ecf20Sopenharmony_ci { $hi=undef; $lo=$_; } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (defined($hi)) 878c2ecf20Sopenharmony_ci { push(@ret,$flavour=~/le$/o?".long\t$lo,$hi":".long\t$hi,$lo"); } 888c2ecf20Sopenharmony_ci else 898c2ecf20Sopenharmony_ci { push(@ret,".quad $lo"); } 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci join("\n",@ret); 928c2ecf20Sopenharmony_ci}; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci################################################################ 958c2ecf20Sopenharmony_ci# simplified mnemonics not handled by at least one assembler 968c2ecf20Sopenharmony_ci################################################################ 978c2ecf20Sopenharmony_cimy $cmplw = sub { 988c2ecf20Sopenharmony_ci my $f = shift; 998c2ecf20Sopenharmony_ci my $cr = 0; $cr = shift if ($#_>1); 1008c2ecf20Sopenharmony_ci # Some out-of-date 32-bit GNU assembler just can't handle cmplw... 1018c2ecf20Sopenharmony_ci ($flavour =~ /linux.*32/) ? 1028c2ecf20Sopenharmony_ci " .long ".sprintf "0x%x",31<<26|$cr<<23|$_[0]<<16|$_[1]<<11|64 : 1038c2ecf20Sopenharmony_ci " cmplw ".join(',',$cr,@_); 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_cimy $bdnz = sub { 1068c2ecf20Sopenharmony_ci my $f = shift; 1078c2ecf20Sopenharmony_ci my $bo = $f=~/[\+\-]/ ? 16+9 : 16; # optional "to be taken" hint 1088c2ecf20Sopenharmony_ci " bc $bo,0,".shift; 1098c2ecf20Sopenharmony_ci} if ($flavour!~/linux/); 1108c2ecf20Sopenharmony_cimy $bltlr = sub { 1118c2ecf20Sopenharmony_ci my $f = shift; 1128c2ecf20Sopenharmony_ci my $bo = $f=~/\-/ ? 12+2 : 12; # optional "not to be taken" hint 1138c2ecf20Sopenharmony_ci ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints 1148c2ecf20Sopenharmony_ci " .long ".sprintf "0x%x",19<<26|$bo<<21|16<<1 : 1158c2ecf20Sopenharmony_ci " bclr $bo,0"; 1168c2ecf20Sopenharmony_ci}; 1178c2ecf20Sopenharmony_cimy $bnelr = sub { 1188c2ecf20Sopenharmony_ci my $f = shift; 1198c2ecf20Sopenharmony_ci my $bo = $f=~/\-/ ? 4+2 : 4; # optional "not to be taken" hint 1208c2ecf20Sopenharmony_ci ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints 1218c2ecf20Sopenharmony_ci " .long ".sprintf "0x%x",19<<26|$bo<<21|2<<16|16<<1 : 1228c2ecf20Sopenharmony_ci " bclr $bo,2"; 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_cimy $beqlr = sub { 1258c2ecf20Sopenharmony_ci my $f = shift; 1268c2ecf20Sopenharmony_ci my $bo = $f=~/-/ ? 12+2 : 12; # optional "not to be taken" hint 1278c2ecf20Sopenharmony_ci ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints 1288c2ecf20Sopenharmony_ci " .long ".sprintf "0x%X",19<<26|$bo<<21|2<<16|16<<1 : 1298c2ecf20Sopenharmony_ci " bclr $bo,2"; 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci# GNU assembler can't handle extrdi rA,rS,16,48, or when sum of last two 1328c2ecf20Sopenharmony_ci# arguments is 64, with "operand out of range" error. 1338c2ecf20Sopenharmony_cimy $extrdi = sub { 1348c2ecf20Sopenharmony_ci my ($f,$ra,$rs,$n,$b) = @_; 1358c2ecf20Sopenharmony_ci $b = ($b+$n)&63; $n = 64-$n; 1368c2ecf20Sopenharmony_ci " rldicl $ra,$rs,$b,$n"; 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_cimy $vmr = sub { 1398c2ecf20Sopenharmony_ci my ($f,$vx,$vy) = @_; 1408c2ecf20Sopenharmony_ci " vor $vx,$vy,$vy"; 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci# Some ABIs specify vrsave, special-purpose register #256, as reserved 1448c2ecf20Sopenharmony_ci# for system use. 1458c2ecf20Sopenharmony_cimy $no_vrsave = ($flavour =~ /linux-ppc64le/); 1468c2ecf20Sopenharmony_cimy $mtspr = sub { 1478c2ecf20Sopenharmony_ci my ($f,$idx,$ra) = @_; 1488c2ecf20Sopenharmony_ci if ($idx == 256 && $no_vrsave) { 1498c2ecf20Sopenharmony_ci " or $ra,$ra,$ra"; 1508c2ecf20Sopenharmony_ci } else { 1518c2ecf20Sopenharmony_ci " mtspr $idx,$ra"; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_cimy $mfspr = sub { 1558c2ecf20Sopenharmony_ci my ($f,$rd,$idx) = @_; 1568c2ecf20Sopenharmony_ci if ($idx == 256 && $no_vrsave) { 1578c2ecf20Sopenharmony_ci " li $rd,-1"; 1588c2ecf20Sopenharmony_ci } else { 1598c2ecf20Sopenharmony_ci " mfspr $rd,$idx"; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci}; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci# PowerISA 2.06 stuff 1648c2ecf20Sopenharmony_cisub vsxmem_op { 1658c2ecf20Sopenharmony_ci my ($f, $vrt, $ra, $rb, $op) = @_; 1668c2ecf20Sopenharmony_ci " .long ".sprintf "0x%X",(31<<26)|($vrt<<21)|($ra<<16)|($rb<<11)|($op*2+1); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci# made-up unaligned memory reference AltiVec/VMX instructions 1698c2ecf20Sopenharmony_cimy $lvx_u = sub { vsxmem_op(@_, 844); }; # lxvd2x 1708c2ecf20Sopenharmony_cimy $stvx_u = sub { vsxmem_op(@_, 972); }; # stxvd2x 1718c2ecf20Sopenharmony_cimy $lvdx_u = sub { vsxmem_op(@_, 588); }; # lxsdx 1728c2ecf20Sopenharmony_cimy $stvdx_u = sub { vsxmem_op(@_, 716); }; # stxsdx 1738c2ecf20Sopenharmony_cimy $lvx_4w = sub { vsxmem_op(@_, 780); }; # lxvw4x 1748c2ecf20Sopenharmony_cimy $stvx_4w = sub { vsxmem_op(@_, 908); }; # stxvw4x 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci# PowerISA 2.07 stuff 1778c2ecf20Sopenharmony_cisub vcrypto_op { 1788c2ecf20Sopenharmony_ci my ($f, $vrt, $vra, $vrb, $op) = @_; 1798c2ecf20Sopenharmony_ci " .long ".sprintf "0x%X",(4<<26)|($vrt<<21)|($vra<<16)|($vrb<<11)|$op; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_cimy $vcipher = sub { vcrypto_op(@_, 1288); }; 1828c2ecf20Sopenharmony_cimy $vcipherlast = sub { vcrypto_op(@_, 1289); }; 1838c2ecf20Sopenharmony_cimy $vncipher = sub { vcrypto_op(@_, 1352); }; 1848c2ecf20Sopenharmony_cimy $vncipherlast= sub { vcrypto_op(@_, 1353); }; 1858c2ecf20Sopenharmony_cimy $vsbox = sub { vcrypto_op(@_, 0, 1480); }; 1868c2ecf20Sopenharmony_cimy $vshasigmad = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1730); }; 1878c2ecf20Sopenharmony_cimy $vshasigmaw = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1666); }; 1888c2ecf20Sopenharmony_cimy $vpmsumb = sub { vcrypto_op(@_, 1032); }; 1898c2ecf20Sopenharmony_cimy $vpmsumd = sub { vcrypto_op(@_, 1224); }; 1908c2ecf20Sopenharmony_cimy $vpmsubh = sub { vcrypto_op(@_, 1096); }; 1918c2ecf20Sopenharmony_cimy $vpmsumw = sub { vcrypto_op(@_, 1160); }; 1928c2ecf20Sopenharmony_cimy $vaddudm = sub { vcrypto_op(@_, 192); }; 1938c2ecf20Sopenharmony_cimy $vadduqm = sub { vcrypto_op(@_, 256); }; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cimy $mtsle = sub { 1968c2ecf20Sopenharmony_ci my ($f, $arg) = @_; 1978c2ecf20Sopenharmony_ci " .long ".sprintf "0x%X",(31<<26)|($arg<<21)|(147*2); 1988c2ecf20Sopenharmony_ci}; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ciprint "#include <asm/ppc_asm.h>\n" if $flavour =~ /linux/; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ciwhile($line=<>) { 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci $line =~ s|[#!;].*$||; # get rid of asm-style comments... 2058c2ecf20Sopenharmony_ci $line =~ s|/\*.*\*/||; # ... and C-style comments... 2068c2ecf20Sopenharmony_ci $line =~ s|^\s+||; # ... and skip white spaces in beginning... 2078c2ecf20Sopenharmony_ci $line =~ s|\s+$||; # ... and at the end 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci { 2108c2ecf20Sopenharmony_ci $line =~ s|\b\.L(\w+)|L$1|g; # common denominator for Locallabel 2118c2ecf20Sopenharmony_ci $line =~ s|\bL(\w+)|\.L$1|g if ($dotinlocallabels); 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci { 2158c2ecf20Sopenharmony_ci $line =~ s|^\s*(\.?)(\w+)([\.\+\-]?)\s*||; 2168c2ecf20Sopenharmony_ci my $c = $1; $c = "\t" if ($c eq ""); 2178c2ecf20Sopenharmony_ci my $mnemonic = $2; 2188c2ecf20Sopenharmony_ci my $f = $3; 2198c2ecf20Sopenharmony_ci my $opcode = eval("\$$mnemonic"); 2208c2ecf20Sopenharmony_ci $line =~ s/\b(c?[rf]|v|vs)([0-9]+)\b/$2/g if ($c ne "." and $flavour !~ /osx/); 2218c2ecf20Sopenharmony_ci if (ref($opcode) eq 'CODE') { $line = &$opcode($f,split(',',$line)); } 2228c2ecf20Sopenharmony_ci elsif ($mnemonic) { $line = $c.$mnemonic.$f."\t".$line; } 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci print $line if ($line); 2268c2ecf20Sopenharmony_ci print "\n"; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ciclose STDOUT; 230