フタなしカンヅメ

徒然なるままに @happytar0

アセンブリでLEDを点灯させる【前編】

前回の記事で無事にLEDを点灯させることができた。
コードは全てC言語で書いたが、もう一つの方法としてアセンブリで書いてみることにした。
アセンブリなんてコードを見ただけでウンザリしてしまう。

でもやってみる前から諦めてもしょうがない。
この機会に少し調べてみることにした。

開発環境を整える

アセンブリコードをコンパイルするためのコマンドは、最初に導入したCrossPackAVRというものに含まれているavr-asコマンドを使うことができる。
しかし、このコマンドでコンパイルできるアセンブリはGasと言われるもので、
いわゆるよく知られている、アセンブリコードのそれとは違うらしい。

そこで今回は、avraというアセンブラを導入してみることにした。
AVRA Home Page

下記サイトを参考にしながらインストール。
のぅわんべたぁ|AVRアセンブリ

まず、最新版をダウンロード後に展開し、srcディレクトリの中で以下のコマンドを実行してみた。
参考通りに上手くいかず、automakeの部分でコケてしまったので、touchコマンドでエラーが出るファイルを作ってみたところ成功。

$ touch NEWS README AUTHORS ChangeLog
$ aclocal
$ autoconf
$ automake -a
$ ./configure --prefix=/opt/local
$ sudo make install

これで開発するための環境は用意できた。
また、includesディレクトリに.inc拡張子のついたファイル群が入っているようで、マイコンの種類に応じた定義ファイルが格納されているようだ。
レジスタやポートに応じたアドレス、値がマッピングされているようで、初めにインクルードして使う感じだと思う。

LEDを点滅させる

なんと言っても最初はLEDを点滅させるところからだろう。
マイコンにはLEDを2つ接続しているが、手始めに一つ点灯させてみる。

.include "tn2313def.inc"

main:
    ldi   r16, 0b00011000
    out   DDRD, r16
    ldi   r16, 0b00001000
    out   PORTD, r16
    rjmp  main

なんとこれだけである…実に簡単だ。

まず、.includeで定義ファイルをインクルード。コロンが付く行はラベルなので解説は不要だと思う。
ちなみにドットから始まるものは擬似命令と呼ばれるもので機械語に変換されることはないらしい。
続いて、各命令について調べてみた。

使える命令セットは以下のURLからダウンロード出来る模様。
http://www.avr.jp/user/DS/PDF/AVRinst.pdf

LDI命令は「即値バイト定数を汎用レジスタに取得」と書いてある。
レジスタr16に右オペランドの値を入れると考えればいいと思う。

OUT命令は「汎用レジスタからI/Oレジスタに設定」と書いてあった。
そのままで、I/Oレジスタに汎用レジスタの値を設定するときに使う命令のようだ。

RJMP命令は「PC相対無条件分岐」と書いてある。
要は無条件でこの場所に飛ばすってことみたいだ。今回の場合はmainラベルに飛ばすので、ループさせるということになる。
いわゆるGOTOみたいな感じだろう。

DDRDや「0b00011000」などの値は、前回の記事で説明していたと思うので今回は省く。
上のコードをavraコマンドでコンパイルしてみた。

$ avra main.asm
AVRA: advanced AVR macro assembler Version 1.3.0 Build 1 (8 May 2010)
Copyright (C) 1998-2010. Check out README file for more info

   AVRA is an open source assembler for Atmel AVR microcontroller family
   It can be used as a replacement of 'AVRASM32.EXE' the original assembler
   shipped with AVR Studio. We do not guarantee full compatibility for avra.

   AVRA comes with NO WARRANTY, to the extent permitted by law.
   You may redistribute copies of avra under the terms
   of the GNU General Public License.
   For more information about these matters, see the files named COPYING.

Pass 1...
Pass 2...
done

Used memory blocks:
   Code      :  Start = 0x0000, End = 0x0004, Length = 0x0005

Assembly complete with no errors.
Segment usage:
   Code      :         5 words (10 bytes)
   Data      :         0 bytes
   EEPROM    :         0 bytes

こんなメッセージが表示されて成功した。
最初にエラーが出たのだけど、tn2313def.incファイル内にある「#」から始まる行の先頭に「;」を付けたところエラーは消えた。

# vimでこんな感じに処理した
:%s/^#/;#/g

出来上がったmain.hexというファイルを開いてみたところ、かなり小さくてびっくりした。わずか63バイトである…。

:020000020000FC
:0A00000008E101BB08E002BBFBCFE2
:00000001FF

バイナリの転送はavrdudeを使って以下のようなコマンドを実行した。

$ avrdude -c avrispmkII -P usb -p t2313 -U flash:w:main.hex:i

簡単なものだけど一発で成功したので抵抗感も薄らいだ。

アセンブリと聞くだけで拒否反応を示してしまいたくなるが、命令セットを覚えていくことで少しずつ理解が深まっていき、単純なコードながら深さと楽しさがあるように思える。

長くなってしまいそうなので、次の記事で2つのLEDを一定間隔で切り替えて点灯させる、ということをやってみたいと思う。

今回書いたコードもGitHubに上げてみた。
pontago/avr-LedTest-asm · GitHub


参考サイト
アセンブラなんて簡単じゃないか(1/3) − @IT MONOist
解説 AVRアセンブラ講座 (1)|freeml byGMO