10. インラインアセンブラ¶
ここでは MicroPython でインラインアセンブラを書く方法を学びます。
注記: これは上級者向けのチュートリアルです。マイクロコントローラとアセンブル言語について既に知っている方を対象としています。
MicroPython にはインラインアセンブラがあります。アセンブリ言語のルーチンを Python 関数として書いて、普通の Python 関数と同様に呼び出せます。
10.1. 値の戻し方¶
インラインアセンブラ関数は特殊な関数デコレータで示します。最も単純な例から始めてみましょう。
@micropython.asm_thumb
def fun():
movw(r0, 42)
この入力はスクリプトからでも REPL からでもかまいません。この関数は引数をとらず、数値 42 を返します。 r0
はレジスタで、関数が返るときのこのレジスタの値が戻り値になります。MicroPython は、常に r0
を整数として解釈し、それを呼び出し元の整数オブジェクトに変換します。
print(fun())
を実行すると、42 が印字されるでしょう。
10.2. ペリフェラルへのアクセス¶
もう少し複雑な例として、LED を点灯してみましょう:
@micropython.asm_thumb
def led_on():
movwt(r0, stm.GPIOA)
movw(r1, 1 << 13)
strh(r1, [r0, stm.GPIO_BSRRL])
このコードでは新しい概念をいくつか使います:
stm
は pyboard のマイクロコントローラのレジスタに簡単にアクセスするための定数のセットを提供するモジュールです。REPL でimport stm
を実行してみた後に、help(stm)
としてみてください。利用可能なすべての定数の一覧が表示されます。stm.GPIOA
は GPIOA ペリフェラルのメモリ内アドレスです。pyboard の赤い LED は、ポート A、ピン PA13 にあります。movwt
は32ビットの数値をレジスタに移動します。これは2つの thumb 命令、movt
とmovw
に変わる便利な関数です。movt
は即値を上位16ビットにロードします。strh
はハーフワード(16ビット)をストアします。例ではr1
下位16ビットをメモリ位置r0 + stm.GPIO_BSRRL
にストアしています。これには、ポートA のピンのうちのr1
で設定したビットに該当するものすべてをハイにする効果があります。上記の例ではr1
の13番目のビットがセットされているので、PA13 がハイになります。これは赤のLEDを点灯させます。
10.3. 引数の受入れ¶
インラインアセンブラ関数は、最大4つの引数を受け入れられます。引数を使う場合には、レジスタと呼び出しの慣例にしたがい、名前を r0
, r1
, r2
, r3
にしなければなりません。
次の関数は、2つの引数を加算する例です:
@micropython.asm_thumb
def asm_add(r0, r1):
add(r0, r0, r1)
これは r0 = r0 + r1
を計算します。結果は r0
に設定されますが、これが戻り値になります。 asm_add(1, 2)
を実行すれば、3 が返るはずです。
10.4. ループ¶
インラインアセンブラでは label(my_label)
でラベルを割り当てられます。ラベルを割り当てておけば、 b(my_label)
のようにラベルを指定して分岐できますし、条件分岐も bgt(my_label)
のようにしてできます。
次の例では緑のLEDが点滅します。LEDは r0 回点滅します。
@micropython.asm_thumb
def flash_led(r0):
# GPIOA アドレスを r1 に格納
movwt(r1, stm.GPIOA)
# PA14 のビットマスク(LED #2 のピンをオンにする)を設定
movw(r2, 1 << 14)
b(loop_entry)
label(loop1)
# LED を点灯
strh(r2, [r1, stm.GPIO_BSRRL])
# 少し遅延させる
movwt(r4, 5599900)
label(delay_on)
sub(r4, r4, 1)
cmp(r4, 0)
bgt(delay_on)
# LED を消灯
strh(r2, [r1, stm.GPIO_BSRRH])
# 少し遅延させる
movwt(r4, 5599900)
label(delay_off)
sub(r4, r4, 1)
cmp(r4, 0)
bgt(delay_off)
# r0 回だけループ
sub(r0, r0, 1)
label(loop_entry)
cmp(r0, 0)
bgt(loop1)
10.5. 参考文献¶
インラインアセンブラでサポートされる命令の詳細については、 リファレンスドキュメント を参照してください。