1*4882a593Smuzhiyun#!/usr/bin/env perl 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0 3*4882a593Smuzhiyun 4*4882a593Smuzhiyun# PowerPC assembler distiller by <appro>. 5*4882a593Smuzhiyun 6*4882a593Smuzhiyunmy $flavour = shift; 7*4882a593Smuzhiyunmy $output = shift; 8*4882a593Smuzhiyunopen STDOUT,">$output" || die "can't open $output: $!"; 9*4882a593Smuzhiyun 10*4882a593Smuzhiyunmy %GLOBALS; 11*4882a593Smuzhiyunmy $dotinlocallabels=($flavour=~/linux/)?1:0; 12*4882a593Smuzhiyun 13*4882a593Smuzhiyun################################################################ 14*4882a593Smuzhiyun# directives which need special treatment on different platforms 15*4882a593Smuzhiyun################################################################ 16*4882a593Smuzhiyunmy $globl = sub { 17*4882a593Smuzhiyun my $junk = shift; 18*4882a593Smuzhiyun my $name = shift; 19*4882a593Smuzhiyun my $global = \$GLOBALS{$name}; 20*4882a593Smuzhiyun my $ret; 21*4882a593Smuzhiyun 22*4882a593Smuzhiyun $name =~ s|^[\.\_]||; 23*4882a593Smuzhiyun 24*4882a593Smuzhiyun SWITCH: for ($flavour) { 25*4882a593Smuzhiyun /aix/ && do { $name = ".$name"; 26*4882a593Smuzhiyun last; 27*4882a593Smuzhiyun }; 28*4882a593Smuzhiyun /osx/ && do { $name = "_$name"; 29*4882a593Smuzhiyun last; 30*4882a593Smuzhiyun }; 31*4882a593Smuzhiyun /linux/ 32*4882a593Smuzhiyun && do { $ret = "_GLOBAL($name)"; 33*4882a593Smuzhiyun last; 34*4882a593Smuzhiyun }; 35*4882a593Smuzhiyun } 36*4882a593Smuzhiyun 37*4882a593Smuzhiyun $ret = ".globl $name\nalign 5\n$name:" if (!$ret); 38*4882a593Smuzhiyun $$global = $name; 39*4882a593Smuzhiyun $ret; 40*4882a593Smuzhiyun}; 41*4882a593Smuzhiyunmy $text = sub { 42*4882a593Smuzhiyun my $ret = ($flavour =~ /aix/) ? ".csect\t.text[PR],7" : ".text"; 43*4882a593Smuzhiyun $ret = ".abiversion 2\n".$ret if ($flavour =~ /linux.*64le/); 44*4882a593Smuzhiyun $ret; 45*4882a593Smuzhiyun}; 46*4882a593Smuzhiyunmy $machine = sub { 47*4882a593Smuzhiyun my $junk = shift; 48*4882a593Smuzhiyun my $arch = shift; 49*4882a593Smuzhiyun if ($flavour =~ /osx/) 50*4882a593Smuzhiyun { $arch =~ s/\"//g; 51*4882a593Smuzhiyun $arch = ($flavour=~/64/) ? "ppc970-64" : "ppc970" if ($arch eq "any"); 52*4882a593Smuzhiyun } 53*4882a593Smuzhiyun ".machine $arch"; 54*4882a593Smuzhiyun}; 55*4882a593Smuzhiyunmy $size = sub { 56*4882a593Smuzhiyun if ($flavour =~ /linux/) 57*4882a593Smuzhiyun { shift; 58*4882a593Smuzhiyun my $name = shift; $name =~ s|^[\.\_]||; 59*4882a593Smuzhiyun my $ret = ".size $name,.-".($flavour=~/64$/?".":"").$name; 60*4882a593Smuzhiyun $ret .= "\n.size .$name,.-.$name" if ($flavour=~/64$/); 61*4882a593Smuzhiyun $ret; 62*4882a593Smuzhiyun } 63*4882a593Smuzhiyun else 64*4882a593Smuzhiyun { ""; } 65*4882a593Smuzhiyun}; 66*4882a593Smuzhiyunmy $asciz = sub { 67*4882a593Smuzhiyun shift; 68*4882a593Smuzhiyun my $line = join(",",@_); 69*4882a593Smuzhiyun if ($line =~ /^"(.*)"$/) 70*4882a593Smuzhiyun { ".byte " . join(",",unpack("C*",$1),0) . "\n.align 2"; } 71*4882a593Smuzhiyun else 72*4882a593Smuzhiyun { ""; } 73*4882a593Smuzhiyun}; 74*4882a593Smuzhiyunmy $quad = sub { 75*4882a593Smuzhiyun shift; 76*4882a593Smuzhiyun my @ret; 77*4882a593Smuzhiyun my ($hi,$lo); 78*4882a593Smuzhiyun for (@_) { 79*4882a593Smuzhiyun if (/^0x([0-9a-f]*?)([0-9a-f]{1,8})$/io) 80*4882a593Smuzhiyun { $hi=$1?"0x$1":"0"; $lo="0x$2"; } 81*4882a593Smuzhiyun elsif (/^([0-9]+)$/o) 82*4882a593Smuzhiyun { $hi=$1>>32; $lo=$1&0xffffffff; } # error-prone with 32-bit perl 83*4882a593Smuzhiyun else 84*4882a593Smuzhiyun { $hi=undef; $lo=$_; } 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun if (defined($hi)) 87*4882a593Smuzhiyun { push(@ret,$flavour=~/le$/o?".long\t$lo,$hi":".long\t$hi,$lo"); } 88*4882a593Smuzhiyun else 89*4882a593Smuzhiyun { push(@ret,".quad $lo"); } 90*4882a593Smuzhiyun } 91*4882a593Smuzhiyun join("\n",@ret); 92*4882a593Smuzhiyun}; 93*4882a593Smuzhiyun 94*4882a593Smuzhiyun################################################################ 95*4882a593Smuzhiyun# simplified mnemonics not handled by at least one assembler 96*4882a593Smuzhiyun################################################################ 97*4882a593Smuzhiyunmy $cmplw = sub { 98*4882a593Smuzhiyun my $f = shift; 99*4882a593Smuzhiyun my $cr = 0; $cr = shift if ($#_>1); 100*4882a593Smuzhiyun # Some out-of-date 32-bit GNU assembler just can't handle cmplw... 101*4882a593Smuzhiyun ($flavour =~ /linux.*32/) ? 102*4882a593Smuzhiyun " .long ".sprintf "0x%x",31<<26|$cr<<23|$_[0]<<16|$_[1]<<11|64 : 103*4882a593Smuzhiyun " cmplw ".join(',',$cr,@_); 104*4882a593Smuzhiyun}; 105*4882a593Smuzhiyunmy $bdnz = sub { 106*4882a593Smuzhiyun my $f = shift; 107*4882a593Smuzhiyun my $bo = $f=~/[\+\-]/ ? 16+9 : 16; # optional "to be taken" hint 108*4882a593Smuzhiyun " bc $bo,0,".shift; 109*4882a593Smuzhiyun} if ($flavour!~/linux/); 110*4882a593Smuzhiyunmy $bltlr = sub { 111*4882a593Smuzhiyun my $f = shift; 112*4882a593Smuzhiyun my $bo = $f=~/\-/ ? 12+2 : 12; # optional "not to be taken" hint 113*4882a593Smuzhiyun ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints 114*4882a593Smuzhiyun " .long ".sprintf "0x%x",19<<26|$bo<<21|16<<1 : 115*4882a593Smuzhiyun " bclr $bo,0"; 116*4882a593Smuzhiyun}; 117*4882a593Smuzhiyunmy $bnelr = sub { 118*4882a593Smuzhiyun my $f = shift; 119*4882a593Smuzhiyun my $bo = $f=~/\-/ ? 4+2 : 4; # optional "not to be taken" hint 120*4882a593Smuzhiyun ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints 121*4882a593Smuzhiyun " .long ".sprintf "0x%x",19<<26|$bo<<21|2<<16|16<<1 : 122*4882a593Smuzhiyun " bclr $bo,2"; 123*4882a593Smuzhiyun}; 124*4882a593Smuzhiyunmy $beqlr = sub { 125*4882a593Smuzhiyun my $f = shift; 126*4882a593Smuzhiyun my $bo = $f=~/-/ ? 12+2 : 12; # optional "not to be taken" hint 127*4882a593Smuzhiyun ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints 128*4882a593Smuzhiyun " .long ".sprintf "0x%X",19<<26|$bo<<21|2<<16|16<<1 : 129*4882a593Smuzhiyun " bclr $bo,2"; 130*4882a593Smuzhiyun}; 131*4882a593Smuzhiyun# GNU assembler can't handle extrdi rA,rS,16,48, or when sum of last two 132*4882a593Smuzhiyun# arguments is 64, with "operand out of range" error. 133*4882a593Smuzhiyunmy $extrdi = sub { 134*4882a593Smuzhiyun my ($f,$ra,$rs,$n,$b) = @_; 135*4882a593Smuzhiyun $b = ($b+$n)&63; $n = 64-$n; 136*4882a593Smuzhiyun " rldicl $ra,$rs,$b,$n"; 137*4882a593Smuzhiyun}; 138*4882a593Smuzhiyunmy $vmr = sub { 139*4882a593Smuzhiyun my ($f,$vx,$vy) = @_; 140*4882a593Smuzhiyun " vor $vx,$vy,$vy"; 141*4882a593Smuzhiyun}; 142*4882a593Smuzhiyun 143*4882a593Smuzhiyun# Some ABIs specify vrsave, special-purpose register #256, as reserved 144*4882a593Smuzhiyun# for system use. 145*4882a593Smuzhiyunmy $no_vrsave = ($flavour =~ /linux-ppc64le/); 146*4882a593Smuzhiyunmy $mtspr = sub { 147*4882a593Smuzhiyun my ($f,$idx,$ra) = @_; 148*4882a593Smuzhiyun if ($idx == 256 && $no_vrsave) { 149*4882a593Smuzhiyun " or $ra,$ra,$ra"; 150*4882a593Smuzhiyun } else { 151*4882a593Smuzhiyun " mtspr $idx,$ra"; 152*4882a593Smuzhiyun } 153*4882a593Smuzhiyun}; 154*4882a593Smuzhiyunmy $mfspr = sub { 155*4882a593Smuzhiyun my ($f,$rd,$idx) = @_; 156*4882a593Smuzhiyun if ($idx == 256 && $no_vrsave) { 157*4882a593Smuzhiyun " li $rd,-1"; 158*4882a593Smuzhiyun } else { 159*4882a593Smuzhiyun " mfspr $rd,$idx"; 160*4882a593Smuzhiyun } 161*4882a593Smuzhiyun}; 162*4882a593Smuzhiyun 163*4882a593Smuzhiyun# PowerISA 2.06 stuff 164*4882a593Smuzhiyunsub vsxmem_op { 165*4882a593Smuzhiyun my ($f, $vrt, $ra, $rb, $op) = @_; 166*4882a593Smuzhiyun " .long ".sprintf "0x%X",(31<<26)|($vrt<<21)|($ra<<16)|($rb<<11)|($op*2+1); 167*4882a593Smuzhiyun} 168*4882a593Smuzhiyun# made-up unaligned memory reference AltiVec/VMX instructions 169*4882a593Smuzhiyunmy $lvx_u = sub { vsxmem_op(@_, 844); }; # lxvd2x 170*4882a593Smuzhiyunmy $stvx_u = sub { vsxmem_op(@_, 972); }; # stxvd2x 171*4882a593Smuzhiyunmy $lvdx_u = sub { vsxmem_op(@_, 588); }; # lxsdx 172*4882a593Smuzhiyunmy $stvdx_u = sub { vsxmem_op(@_, 716); }; # stxsdx 173*4882a593Smuzhiyunmy $lvx_4w = sub { vsxmem_op(@_, 780); }; # lxvw4x 174*4882a593Smuzhiyunmy $stvx_4w = sub { vsxmem_op(@_, 908); }; # stxvw4x 175*4882a593Smuzhiyun 176*4882a593Smuzhiyun# PowerISA 2.07 stuff 177*4882a593Smuzhiyunsub vcrypto_op { 178*4882a593Smuzhiyun my ($f, $vrt, $vra, $vrb, $op) = @_; 179*4882a593Smuzhiyun " .long ".sprintf "0x%X",(4<<26)|($vrt<<21)|($vra<<16)|($vrb<<11)|$op; 180*4882a593Smuzhiyun} 181*4882a593Smuzhiyunmy $vcipher = sub { vcrypto_op(@_, 1288); }; 182*4882a593Smuzhiyunmy $vcipherlast = sub { vcrypto_op(@_, 1289); }; 183*4882a593Smuzhiyunmy $vncipher = sub { vcrypto_op(@_, 1352); }; 184*4882a593Smuzhiyunmy $vncipherlast= sub { vcrypto_op(@_, 1353); }; 185*4882a593Smuzhiyunmy $vsbox = sub { vcrypto_op(@_, 0, 1480); }; 186*4882a593Smuzhiyunmy $vshasigmad = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1730); }; 187*4882a593Smuzhiyunmy $vshasigmaw = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1666); }; 188*4882a593Smuzhiyunmy $vpmsumb = sub { vcrypto_op(@_, 1032); }; 189*4882a593Smuzhiyunmy $vpmsumd = sub { vcrypto_op(@_, 1224); }; 190*4882a593Smuzhiyunmy $vpmsubh = sub { vcrypto_op(@_, 1096); }; 191*4882a593Smuzhiyunmy $vpmsumw = sub { vcrypto_op(@_, 1160); }; 192*4882a593Smuzhiyunmy $vaddudm = sub { vcrypto_op(@_, 192); }; 193*4882a593Smuzhiyunmy $vadduqm = sub { vcrypto_op(@_, 256); }; 194*4882a593Smuzhiyun 195*4882a593Smuzhiyunmy $mtsle = sub { 196*4882a593Smuzhiyun my ($f, $arg) = @_; 197*4882a593Smuzhiyun " .long ".sprintf "0x%X",(31<<26)|($arg<<21)|(147*2); 198*4882a593Smuzhiyun}; 199*4882a593Smuzhiyun 200*4882a593Smuzhiyunprint "#include <asm/ppc_asm.h>\n" if $flavour =~ /linux/; 201*4882a593Smuzhiyun 202*4882a593Smuzhiyunwhile($line=<>) { 203*4882a593Smuzhiyun 204*4882a593Smuzhiyun $line =~ s|[#!;].*$||; # get rid of asm-style comments... 205*4882a593Smuzhiyun $line =~ s|/\*.*\*/||; # ... and C-style comments... 206*4882a593Smuzhiyun $line =~ s|^\s+||; # ... and skip white spaces in beginning... 207*4882a593Smuzhiyun $line =~ s|\s+$||; # ... and at the end 208*4882a593Smuzhiyun 209*4882a593Smuzhiyun { 210*4882a593Smuzhiyun $line =~ s|\b\.L(\w+)|L$1|g; # common denominator for Locallabel 211*4882a593Smuzhiyun $line =~ s|\bL(\w+)|\.L$1|g if ($dotinlocallabels); 212*4882a593Smuzhiyun } 213*4882a593Smuzhiyun 214*4882a593Smuzhiyun { 215*4882a593Smuzhiyun $line =~ s|^\s*(\.?)(\w+)([\.\+\-]?)\s*||; 216*4882a593Smuzhiyun my $c = $1; $c = "\t" if ($c eq ""); 217*4882a593Smuzhiyun my $mnemonic = $2; 218*4882a593Smuzhiyun my $f = $3; 219*4882a593Smuzhiyun my $opcode = eval("\$$mnemonic"); 220*4882a593Smuzhiyun $line =~ s/\b(c?[rf]|v|vs)([0-9]+)\b/$2/g if ($c ne "." and $flavour !~ /osx/); 221*4882a593Smuzhiyun if (ref($opcode) eq 'CODE') { $line = &$opcode($f,split(',',$line)); } 222*4882a593Smuzhiyun elsif ($mnemonic) { $line = $c.$mnemonic.$f."\t".$line; } 223*4882a593Smuzhiyun } 224*4882a593Smuzhiyun 225*4882a593Smuzhiyun print $line if ($line); 226*4882a593Smuzhiyun print "\n"; 227*4882a593Smuzhiyun} 228*4882a593Smuzhiyun 229*4882a593Smuzhiyunclose STDOUT; 230