目次

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. フィールド数から1行の演算を判定
  3. 演算種に応じて、2進数を生成
  4. 例外の演算種に応じて、2進数を生成
  5. 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に入ってくるので、変数で受け取り  しておきます。

目次

inserted by FC2 system