Arduinoを動かす No.2 :アセンブラでコードを書いてみる

Arduinoをアセンブラで動かしてみることを考えてます.

なぜアセンブラ?

と思われるかもしれませんが意外とマニアが多いと思います.私もCで書くよりアセンブラの方がごりごりハードを使ってる感覚があるので好きです.Arduinoはまだまだ初心者なのですが,アセンブラで組む方法を考えてみました.インラインでCの関数の中に組み込む方法もあるようですが,なんかカッコ悪いので別の方法を・・・

今回の方法は,Cの関数をアセンブラで記述して,それを大元の関数loop()で呼び出す形でアセンブラのプログラムを実現してみたいと思います.純粋にアセンブラだけではないですが,ほぼアセンブラで記述ということで(笑)

ただし,あくまで勉強の目的でやっていくので,実行速度の改善とかそんな高度なことは目指してません(いずれ考えるかもしれませんが・・・).あらかじめ了解ください.

で,まずは非常に単純な加算のプログラムを作成します.メインのソースから.MyAsm.inoというプログラムを以下のように作成しました.


#include <sample.h>

uint8_t  x;

void setup() {
      x = 49;
      Serial.begin(115200);
      samp1(&x, 67);
}

void loop() {
      Serial.println("value=");
      Serial.println(x);
}

これはC言語です.次にヘッダファイルのsample.hをライブラリのフォルダの中に,


extern "C" {
   void samp1(uint8_t  *x,  uint8_t  data);
}

と記載して保存しておきます.samp1という関数は引数が2つです.具体的に何をするのかですが,今回は動作確認の意味を込めて,*x + dataを計算してその答えを*xに代入するプログラムにしました.

関数setup()の中でx=49と代入してます.また,関数samp1の2つ目の引数に67という値を入れてます.したがって,計算結果は49+67=116がxの値となり,関数loop()でこの値が表示され続けるとOKです.今回は,このsamp1という関数をアセンブラで書いてみたいと思います.

それで,sample.hと同じ場所にsample.Sというアセンブラのコードが書かれたファイルをテキストエディタで作成します.中身はこんなコードです.

XL = 26   ; XレジスタはR26, R27の2バイト(定位置)
XH = 27

; 関数プロトタイプ void samp1(uint8_t *x, uint8_t data)

.global	samp1  ; 関数名 
.func samp1

samp1:					; ここから関数スタート
	mov	XL, r24		; 最初の引数*xはポインタなのでアドレス2バイト
	mov	XH, r25		; 引数の下位がR24, 上位がR25
	ld	r20, X		; R20<-(X) : Xレジスタの指すアドレスにある値をR20へ代入(R20=49)
	add	r20, r22	; R20<-R20+R22(=49+67=116) : R22は2つ目の引数dataの下位
	st	X, r20		; (X)<-R20 : Xレジスタの指すアドレスへR20の値を保存(X=116)
	ret

.endfunc

それぞれのコードの意味はコメントに書きましたので,参考にしてください.実行すると,

こんな感じで,正しい加算結果116が画面に表示され続けます.関数の引数で受け取った値が,R25から順番に格納されるのがポイントですね.それと関数の戻り値はおそらくアセンブラで記載は無理だと思うので,常にvoid関数にしてポインタ渡しで解決するしかないのかなと予想します.

あと,AVRでは,

  • レジスタ→レジスタ への代入:move(mov命令)
  • メモリ→レジスタへの代入:load(ld命令)
  • レジスタ→メモリへの代入:store(st命令)

と三種類あるようです.うーむ,Z80のようにLDで一本化してくれた方が楽だけどな・・・(笑).

※以下を参考にしました.筆者の方々に感謝いたします.

  1. AVR Assembler User Guide
  2. AVRアセンブラ関数の作り方:マイコン漬け
  3. アセンブリ・プログラム:CQ出版 ← どの本の見本なのかわかるようにして欲しい