perlでAVRニモニックを機械語に変換(その2)

続きです。
一命令増やしてみましょう。

while(<>){
        if(/(?:LDI|ldi)\s+[rR](\d+),([0-9a-fxA-FX]+)/){
                $d=$1;
                $K=$2;
                $K=hex $K if $K =~ /x/;
                printf "%01X%01X%01X%01X\n"
                        ,$d-16
                        ,($K&0xf)
                        ,0xE
                        ,($K&0xf0)>>4
        }
        if(/(?:OUT|out)\s+([0-9a-fxA-FX]+),[rR](\d+)/){
                $A=$1;
                $r=$2;
                $A=hex $A if $A =~ /x/;
                printf "%01X%01X%01X%01X\n"
                        ,($r&0xf)
                        ,($A&0xf)
                        ,0xB
                        ,0x8 | ($A>>3&0x6) | ($r>>4 & 0x1)
        }
}

一命令増やしただけですが、行数が多くてげんなりします。命令一つに一行にしたいです。
ということで、書き換えました。要はニモニックを機械語に置換すれば良いのです。

~$ cat avr-asm.pl
while(<>){
s/(0[xX][0-9A-Fa-f]+)/hex $1/e;
s/LDI\s+[rR](\d+),(\d+)/sprintf("%01X%01X%01X%01X",($1-16),($2&0xf),0xE,($2>>4) )/e;
s/OUT\s+(\d+),[rR](\d+)/sprintf("%01X%01X%01X%01X",($2&0x0f),($1&0xf),0xB, 0x8|($1>>3&0x06)|($2>>4&0x01) )/e;
print;
}

命令を増やしつつ、ダイエットもしていきます。

~$ cat avr-asm.pl
while(<>){
s/(0X[0-9A-F]+)/hex $1/ei;
s/LDI\s+R(\d+),(\d+)/sprintf("%1X%1X%1X%1X",($1 -  16),($2 & 0xf),0xE,($2>>4) )/ei;
s/OUT\s+(\d+),R(\d+)/sprintf("%1X%1X%1X%1X",($2 & 0xf),($1 & 0xf),0xB,(8|($1>>3&6)|($2>>4&1)) )/ei;
s/EOR\s+R(\d+),R(\d+)/sprintf("%1X%1X%1X%1X",($1 & 0xf),($2 & 0xf),0x2,(4|($1>>4)|($2>>3&2)) )/ei;
print;
}

sprintfのところが、冗長に感じてきましたので関数化します。

~$ cat avr-asm.pl
while(<>){
s/(0X[0-9A-F]+)/hex $1/ei;
s/LDI\s+R(\d+),(\d+)/asm(0xE,($2>>4), ($1 -  16),($2 & 0xf) )/ei;
s/OUT\s+(\d+),R(\d+)/asm(0xB,(8|($1>>3&6)|($2>>4&1)), ($2 & 0xf),($1 & 0xf) )/ei;
s/EOR\s+R(\d+),R(\d+)/asm(0x2,(4|($1>>4)|($2>>3&2)), ($1 & 0xf),($2 & 0xf) )/ei;
print;
}
sub asm{
	my($x3,$x4,$x1,$x2) = @_;
	sprintf("%1X%1X%1X%1X",$x1,$x2,$x3,$x4);
}

()が多い気がします。
演算子の優先順位は、<<>>、|、&で比べると、

高い
<<>>
&
|
低い
ですので、()が取れます。
あと、正規表現を少し変えることで、各行を揃えることができます。

~$ cat avr-asm.pl
while(<>){
s/(0X[0-9A-F]+)/hex $1/ei;
s/LDI\s+R{1}(\d+),R{0}(\d+)/asm(0xE,(          $2>>4  ), $1-16 ,$2&0xf )/ei;
s/OUT\s+R{0}(\d+),R{1}(\d+)/asm(0xB,(8|$1>>3&6|$2>>4&1), $2&0xf,$1&0xf )/ei;
s/EOR\s+R{1}(\d+),R{1}(\d+)/asm(0x2,(4|$1>>4  |$2>>3&2), $1&0xf,$2&0xf )/ei;
print;
}
sub asm{
	my($x3,$x4,$x1,$x2) = @_;
	sprintf("%1X%1X%1X%1X",$x1,$x2,$x3,$x4);
}

使ってみます。

~$ cat sample
ldi r24,0x08
out 0x17,r24
eor r24,r25
~$ perl avr-asm.pl sample
88E0
87BB
8927
~$ 

いい感じです。
続く。

Leave a Reply

Your email address will not be published. Required fields are marked *

CAPTCHA