目次
前
次
ARMアセンブラ(AWK)
IchigoJamのBASICでは、メモリに機械語を埋め
込んで、高速動作をさせることが可能です。
ARMのCortex-M0では、THUMB命令を利用できます。
ハンドアセンブルではない、アセンブリ言語コード
から機械語を生成するアセンブラを作成して、開発
時間を短縮してみます。
THUMB命令の一部は、次のようになっています。
Unix、Windows、MacOSXのいずれでも利用できる
スクリプト言語で、自分が得意とするAWKで
アプリケーションプログラムを作成しました。
ARMでは、メモリマップドI/Oを採用しています。
レジスタ間のデータ交換、レジスタとメモリの間
のデータ交換が主体なので、代入演算子「=」を
利用した記述を使います。
具体的には、以下のようにアセンブリ言語コード
を書いていきます。
R1 = R0
R1 <<= 2
R0 = R1
RET
AWKでは、1行の中のフィールドに分けてある数値
文字列を扱うので、演算子、数値、レジスタ名を
スペースで区切って表現する仕様を採用。
アセンブリ言語コードは、次のように記述します。
RET
R0 = 3
R1 += 1
R2 += R3
push { R0 R1 R2 R3 }
pop { R0 R1 R2 R3 }
[ R3 + 4 ] L = r0
R2 = [ R0 + R1 ] W
アセンブラは、1行の記述内容から、対応する
機械語コードを生成すればよいので、次に示す
シーケンスで処理しています。
- フィールド数を取得
- フィールド数から1行の演算を判定
- 演算種に応じて、2進数を生成
- 例外の演算種に応じて、2進数を生成
- 16ビット分の2進数を出力
アセンブラのソースコードは、以下。
#
function get_reg_code(x) {
# default
result = "111"
# search
if ( x == "R0" ) { result = "000" ; }
if ( x == "R1" ) { result = "001" ; }
if ( x == "R2" ) { result = "010" ; }
if ( x == "R3" ) { result = "011" ; }
return result
}
#
function get_num_bin3(x) {
# default
r2 = "0"
r1 = "0"
r0 = "0"
# calculate
if ( x >= 4 ) {
r2 = "1"
x = x - 4
}
if ( x >= 2 ) {
r1 = "1"
x = x - 2
}
if ( x > 0 ) { r0 = "1" }
# concatenate
result = r2 r1 r0
return result
}
#
function get_num_bin5(x) {
# default
r4 = "0"
r3 = "0"
# calculate
if ( x >= 16 ) {
r4 = "1"
x = x - 16
}
if ( x >= 8 ) {
r3 = "1"
x = x - 8
}
# copy
y = x
# concatenate
result = r4 r3 get_num_bin3(y)
return result
}
#
function get_num_bin8(x) {
# default
r7 = "0"
r6 = "0"
r5 = "0"
# calculate
if ( x >= 128 ) {
r7 = "1"
x = x - 128
}
if ( x >= 64 ) {
r6 = "1"
x = x - 64
}
if ( x >= 32 ) {
r5 = "1"
x = x - 32
}
# copy
y = x
# concatenate
result = r7 r6 r5 get_num_bin5(y)
return result
}
#
function get_num_bin11(x) {
# default
r10 = "0"
r9 = "0"
r8 = "0"
# calculate
if ( x >= 1024 ) {
r10 = "1"
x = x - 1024
}
if ( x >= 512 ) {
r9 = "1"
x = x - 512
}
if ( x >= 256 ) {
r8 = "1"
x = x - 256
}
# copy
y = x
# concatenate
result = r10 r9 r8 get_num_bin8(y)
return result
}
# main
{
# get field size
len = NF
#
printf("%s => ",$0)
#
if ( len == 1 ) {
# RET // 0100_0111_0111_0000
if ( toupper($1) == "RET" ) {
printf("0100011101110000\n")
}
}
if ( len == 2 ) {
# GOTO n11 // 11100 n11<00000000000>
if ( toupper($1) == "GOTO" ) {
tt = $2
if ( $2 < 0 ) { tt = 254 + $2 }
uu = get_num_bin11(tt)
xcode = "11100"
}
printf("%s%s\n",xcode,uu)
}
if ( len == 3 ) {
# substitute
# Rd = u8 // 00100 Rd<000> u8<00000000>
# Rd = Rm // 0100011000 Rm <000> Rd<000>
if ( $2 == "=" ) {
dd = get_reg_code(toupper($1))
if ( 0 <= $3 && $3 <= 255 ) {
ss = get_num_bin8($3)
xcode = "00100"
} else {
ss = get_reg_code(toupper($3))
xcode = "0100011000"
}
printf("%s%s%s\n",xcode,dd,ss)
}
# add or subtract
# Rd += u8 // 00110 Rd<000> u8<00000000>
# Rd -= u8 // 00111 Rd<000> u8<00000000>
if ( $2 == "+=" || $2 == "-=" ) {
dd = get_reg_code(toupper($1))
ss = get_num_bin8($3)
xcode = "00110"
if ( $2 == "-=" ) { xcode = "00111" }
printf("%s%s%s\n",xcode,dd,ss)
}
# logical AND , exclusive OR , OR
# Rd &= Rm // 0100000000 Rm<000> Rd<000>
# Rd ^= Rm // 0100000001 Rm<000> Rd<000>
# Rd |= Rm // 0100001100 Rm<000> Rd<000>
if ( $2 == "&=" || $2 == "^=" || $2 == "|=" ) {
dd = get_reg_code(toupper($1))
ss = get_reg_code(toupper($3))
xcode = "0100000000"
if ( $2 == "^=" ) { xcode = "0100000001" }
if ( $2 == "|=" ) { xcode = "0100001100" }
printf("%s%s%s\n",xcode,ss,dd)
}
# multiply , left shift , right shift
# Rd *= Rm // 0100001101 Rm<000> Rd<000>
# Rd <<= Rs // 0100000010 Rs<000> Rd<000>
# Rd >>= Rs // 0100000011 Rs<000> Rd<000>
if ( $2 == "*=" || $2 == "<<=" || $2 == ">>=" ) {
dd = get_reg_code(toupper($1))
ss = get_reg_code(toupper($3))
xcode = "0100001101"
if ( $2 == "<<=" ) { xcode = "0100000010" }
if ( $2 == ">>=" ) { xcode = "0100000011" }
printf("%s%s%s\n",xcode,ss,dd)
}
# condition Rn - u8 // 00101 Rn<000> u8<00000000>
# condition Rn - Rm // 0100001010 Rm<000> Rn<000>
if ( $2 == "-" ) {
dd = get_reg_code(toupper($1))
if ( 0 <= $3 && $3 <= 255 ) {
ss = get_num_bin8($3)
xcode = "00101"
} else {
ss = get_reg_code(toupper($3))
xcode = "0100001010"
}
printf("%s%s%s\n",xcode,dd,ss)
}
# condition Rn & Rm // 0100001000 Rm<000> Rn<000>
if ( $2 == "&" ) {
dd = get_reg_code(toupper($1))
ss = get_reg_code(toupper($3))
xcode = "0100001000"
printf("%s%s%s\n",xcode,ss,dd)
}
# Rd = -Rm // 0100001001 Rm<000> Rd<000>
if ( $3 == "-R0" || $3 == "-R1" || $3 == "-R2" || $3 == "-R3" ) {
dd = get_reg_code(toupper($1))
# select
ss = get_reg_code("R0")
if ( $3 == "-R1" ) { ss = get_reg_code("R1") }
if ( $3 == "-R2" ) { ss = get_reg_code("R2") }
if ( $3 == "-R3" ) { ss = get_reg_code("R3") }
#
xcode = "0100001001"
printf("%s%s%s\n",xcode,ss,dd)
}
# Rd &= ~Rm // 0100001110 Rm<000> Rd<000>
# Rd = ~Rm // 0100001111 Rm<000> Rd<000>
if ( $3 == "~R0" || $3 == "~R1" || $3 == "~R2" || $3 == "~R3" ) {
dd = get_reg_code(toupper($1))
# select
ss = get_reg_code("R0")
if ( $3 == "~R1" ) { ss = get_reg_code("R1") }
if ( $3 == "~R2" ) { ss = get_reg_code("R2") }
if ( $3 == "~R3" ) { ss = get_reg_code("R3") }
#
if ( $2 == "&=" ) { xcode = "0100001110" }
if ( $2 == "=" ) { xcode = "0100001111" }
printf("%s%s%s\n",xcode,ss,dd)
}
}
if ( len == 4 ) {
# IF 0 GOTO n8 // 11010000 n8<00000000>
# IF !0 GOTO n8 // 11010001 n8<00000000>
if ( $1 == "IF" ) {
tt = $4
if ( $4 < 0 ) { tt = 254 + $4 }
uu = get_num_bin8(tt)
# select
xcode = "11010000"
if ( $2 == "!0" ) { xcode = "11010001" }
printf("%s%s\n",xcode,uu)
}
}
if ( len == 5 ) {
if ( $2 == "=" ) {
# shift
# Rd = Rm << u5 // 00000 u5<00000> Rm<000> Rd<000>
# Rd = Rm >> u5 // 00001 u5<00000> Rm<000> Rd<000>
if ( $4 == "<<" || $4 == ">>" ) {
dd = get_reg_code(toupper($1))
ss = get_reg_code(toupper($3))
uu = get_num_bin5($5)
if ( $4 == "<<" ) { xcode = "00000" }
if ( $4 == ">>" ) { xcode = "00001" }
printf("%s%s%s%s\n",xcode,uu,ss,dd)
}
# add
# Rd = Rn + Rm // 0001100 Rm<000> Rn<000> Rd<000>
# Rd = Rn + u3 // 0001110 u3<000> Rm<000> Rd<000>
if ( $4 == "+" ) {
dd = get_reg_code(toupper($1))
ss = get_reg_code(toupper($3))
if ( 0 <= $5 && $5 <= 7 ) {
uu = get_num_bin3($5)
xcode = "0001110"
} else {
uu = get_reg_code(toupper($5))
xcode = "0001100"
}
printf("%s%s%s%s\n",xcode,uu,ss,dd)
}
# subtract
# Rd = Rn - Rm // 0001100 Rm<000> Rn<000> Rd<000>
# Rd = Rn - u3 // 0001111 u3<000> Rm<000> Rd<000>
if ( $4 == "-" ) {
dd = get_reg_code(toupper($1))
ss = get_reg_code(toupper($3))
if ( 0 <= $5 && $5 <= 7 ) {
uu = get_num_bin3($5)
xcode = "0001111"
} else {
uu = get_reg_code(toupper($5))
xcode = "0001100"
}
printf("%s%s%s%s\n",xcode,uu,ss,dd)
}
}
}
if ( len == 7 ) {
# Rd = [ Rn + u5 ] // 01111 u5<00000> Rn<000> Rd<000>
# Rd = [ Rn + Rm ] // 0101110 Rm<000> Rn<000> Rd<000>
if ( $2 == "=" && $3 == "[" && $5 = "+" && $7 == "]" ) {
dd = get_reg_code(toupper($1))
ss = get_reg_code(toupper($4))
if ( 0 <= $6 && $6 <= 31 ) {
uu = get_num_bin5($6)
xcode = "01111"
} else {
uu = get_reg_code(toupper($6))
xcode = "0101110"
}
printf("%s%s%s%s\n",xcode,uu,ss,dd)
}
# [ Rn + u5 ] = Rd // 01110 u5<00000> Rn<000> Rd<000>
# [ Rn + Rm ] = Rd // 0101010 Rm<000> Rn<000> Rd<000>
if ( $1 == "[" && $3 == "+" && $5 = "]" && $6 == "=" ) {
dd = get_reg_code(toupper($7))
ss = get_reg_code(toupper($2))
if ( 0 <= $4 && $4 <= 31 ) {
uu = get_num_bin5($4)
xcode = "01110"
} else {
uu = get_reg_code(toupper($4))
xcode = "0101010"
}
printf("%s%s%s%s\n",xcode,uu,ss,dd)
}
}
# access with long or word size
if ( len == 8 ) {
# Rd = [ Rn + u5 ] W // 10001 u5/2 <00000> Rn<000> Rd<000>
# Rd = [ Rn + u5 ] L // 01101 u5/4 <00000> Rn<000> Rd<000>
# Rd = [ Rn + Rm ] W // 0101101 Rm<000> Rn<000> Rd<000>
# Rd = [ Rn + Rm ] L // 0101100 Rm<000> Rn<000> Rd<000>
if ( $2 == "=" && $3 == "[" && $5 = "+" && $7 == "]" ) {
dd = get_reg_code(toupper($1))
ss = get_reg_code(toupper($4))
if ( 0 <= $6 && $6 <= 31 ) {
if ( $8 == "W" ) {
uu = get_num_bin5($6/2)
xcode = "10001"
}
if ( $8 == "L" ) {
uu = get_num_bin5($6/4)
xcode = "01101"
}
} else {
uu = get_reg_code(toupper($6))
if ( $8 == "W" ) { xcode = "0101101" }
if ( $8 == "L" ) { xcode = "0101100" }
}
printf("%s%s%s%s\n",xcode,uu,ss,dd)
}
# [ Rn + u5 ] W = Rd // 10000 u5/2 <00000> Rn<000> Rd<000>
# [ Rn + u5 ] L = Rd // 01100 u5/4 <00000> Rn<000> Rd<000>
# [ Rn + Rm ] W = Rd // 0101001 Rm<000> Rn<000> Rd<000>
# [ Rn + Rm ] L = Rd // 0101000 Rm<000> Rn<000> Rd<000>
if ( $1 == "[" && $3 == "+" && $5 = "]" && $7 == "=" ) {
dd = get_reg_code(toupper($2))
ss = get_reg_code(toupper($8))
if ( 0 <= $4 && $4 <= 31 ) {
if ( $6 == "W" ) {
uu = get_num_bin5($4/2)
xcode = "10000"
}
if ( $6 == "L" ) {
uu = get_num_bin5($4/4)
xcode = "01100"
}
} else {
uu = get_reg_code(toupper($4))
if ( $8 == "W" ) { xcode = "0101001" }
if ( $8 == "L" ) { xcode = "0101000" }
}
printf("%s%s%s%s\n",xcode,uu,ss,dd)
}
}
# PUSH or POP
if ( $1 == "PUSH" || $1 == "POP" ) {
sum = 0
# search
for ( i = 3 ; i < NF+1 ; i++ ) {
if ( $i == "R0" ) { sum = sum + 1 }
if ( $i == "R1" ) { sum = sum + 2 }
if ( $i == "R2" ) { sum = sum + 4 }
if ( $i == "R3" ) { sum = sum + 8 }
if ( $i == "R4" ) { sum = sum + 16 }
if ( $i == "R5" ) { sum = sum + 32 }
if ( $i == "R6" ) { sum = sum + 64 }
if ( $i == "R7" ) { sum = sum + 128 }
}
# convert
uu = get_num_bin8( sum )
if ( $1 == "PUSH" ) { xcode = "10110100" }
if ( $1 == "POP" ) { xcode = "10111100" }
#
printf("%s%s\n",xcode,uu)
}
}
ARMのTHUMB命令では、値をそのまま16ビットの中に
いれることがあるので、2進数の3桁、5桁、8桁
11桁を生成する関数を用意して使っています。
生成した2進数表現の機械語は、他のフィルタプログラム
を利用して、IchigoJamで使える書式に変換します。
IchigoJamを扱っているWEBサイトにある
アセンブリ言語コードをアセンブルして
みます。
ターゲットにしたアセンブリ言語コードは、以下。
(作成アセンブラ用に、書式はあわせています)
R3 = 9
R3 = R3 << 8
[ R1 + R3 ] = R3
R3 = R3 + 1
R2 = R3 >> 8
R2 - 10
IF !0 GOTO -4
RET
ファイル名は、「tt1.asm」としておきましょうか。
アセンブルは、次のようにタイプ。
gawk -f asm15x.awk tt1.asm > tt1.txt{enter}
I/Oリダイレクトで、ファイルに出力したので
その内容をみてみます。(見易くしてます。)
R3 = 9 => 0010001100001001
R3 = R3 << 8 => 0000001000011011
[ R1 + R3 ] = R3 => 0101010011001011
R3 = R3 + 1 => 0001110001011011
R2 = R3 >> 8 => 0000101000011010
R2 - 10 => 0010101000001010
IF !0 GOTO -4 => 1101000111111010
RET => 0100011101110000
原本と2進数を比較し、同じことを確認できました。
IchigoJamのメモリの中に入れるには、次のようにすればよいでしょう。
11 LET [0],`0010001100001001
12 LET [1],`0000001000011011
13 LET [2],`0101010011001011
14 LET [3],`0001110001011011
15 LET [4],`0000101000011010
16 LET [5],`0010101000001010
17 LET [6],`1101000111111010
18 LET [7],`0100011101110000
SRAMの#700、#800、#900には、PCG、VAR、VRAMと割り当てられて
いるので、配列では#800を使うことになります。
USR関数を利用して、メモリに格納した機械語を実行するには
次のようにすれば、よいでしょう。
LET A,USR(#800,0)
パラメータは、レジスタR0経由で渡し、結果は
レジスタR0に入ってくるので、変数で受け取り
しておきます。
目次
前
次