第 5 回 アセンブリ言語

本日の内容


このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。

5-1. アセンブリ言語

基本書式

アセンブリ言語はテキストファイルに記述します。 アセンブラのユーザーズマニュアル AVR Assembler Assembler source に示されているように記述します。 「ラベル: ニモニック オペランド」 を空白で区切って記述します。 ラベルの前に空白があってはいけません。 また、セミコロン(;)の後ろはコメントとしてアセンブル時に無視されます。 ニモニックの位置には他にディレクティヴ、マクロなどを置くことができます。


ラベル  ニモニック オペランド コメント
.org	0x0013
reset:
	ldi	r16,low(RAMEND)
	out	SPL,r16

演算

アセンブリ言語中で定数の演算式を書くことが出来ます。 アセンブラのユーザーズガイドの AVR Assembler Expressions にあるように C 言語で許されて いるような演算子がそのまま使えます。 但し、レジスタの内容は演算の対象ではありません。

ディレクティヴ

アセンブラとはニモニックとオペランドから機械語を生成するものですが、 利便性を向上するためのアセンブラの機能があります。 ディレクティヴとはアセンブラに対する指示をする命令です。 ディレクティヴはピリオド(.)で始めます。

良く使うディレクティヴを紹介します。

cseg, dseg, eseg
それぞれ、 Code, Data, EEPROM の内容を定義するという意味です。
equ
任意の値を持つラベルを定義します。再定義できません。 計算値も定義できます。
def
レジスタにラベルを定義します。再定義できません。 これを使用すると、レジスタの利用を論理的に表示できるので、 必ず使うことを推奨します。
org
実際のプログラムやデータを置く始点となる番地を指定します。
db, dw, dd, dq
データをじかに書きます。 db は Byte, dw は Word(16bit)の定義に使います。カンマ(,)で区切るといく つも定義できます。 なお、プログラム領域(cseg で定義される領域)は 16bit です。 lpm 命令で 8bit ずつ取り出す場合、下位 8bit がアドレスの偶数番地、上位 8bit が奇数番地に対応します。さらに、奇数個のデータを入れると、上位 8bit が $00 で埋められます。
byte
dseg で SRAM の領域にラベル付きの領域を定義する際に使用します。
exit
アセンブリのリストの最後を示します。
macro, endmacro

マクロを定義します。 macro のオペランドにマクロ名を指定します。 マクロ定義の中で引数として @0 から @9 の 10 個の仮引数が使えます。 なお、AVR のアセンブラのマクロ中のラベルはローカルにしか使用できません ので、マクロ中に定義したラベルに外部からアクセスすることはできません。 なお、グローバルなラベルを使用するには #define 疑似命令を使用する手が ありますが、こちらこちらで基本的に一行で記述しなければならず、複数行を 書くには(\)を使用した継続行を使用する必要があります。

5-2. 関数

EQU などで使用できる関数を下記に示します。 なお、これらは一部なので、詳しくは アセンブラマニュアル Expressions を参照してください。

LOW(式)
式の値の下位8bitを取り出します
HIGH(式)
式の値の上位8bitを取り出します
EXP2(式)
式の値の2のべき乗を返します。 (1<<式)と同等です
LOG2(式)
式の値の 2 を底とした対数の整数部分を返します
INT(式)
式の値を切り捨てます
FRAC(式)
式の値の小数部分を取り出します
ABS(式)
式の値の絶対値を返します

5-3. アセンブル

さて、この節では実際にプログラムを作成する手順を説明します。

  1. Atmel Studio を起動します。
  2. 「ファイル→新規作成→プロジェクト」を選びます。
  3. 「インストール済み」 で Assembler を選び、名前にプロジェクト名を入 れます
  4. Device Family で ATmega を選び、 ATmega328P を選びます
  5. main.asm という編集画面が開きますので、プログラムを入力します。
  6. 「ファイル→ main.asm の保存」でプログラムを保存します。
  7. 「ビルド→ソリューションのビルド」でアセンブルします。
  8. アセンブルエラーが出た場合、エラーをダブルクリックするとエラーの出 た行へカーソルが移動します。

5-4. シミュレータを使ったデバッグ

アセンブルしたプログラムはシミュレータで動作を観察できます。 「プロジェクト→ プロジェクト名 のプロパティ」を選ぶと 設定画面が出ます。 Tool の設定画面で、 Simulator を選ぶと ソフトウェアシミュレータ を使えるようになります。 シミュレータはプログラムを一命令ずつ動かしたり、指定した所まで動かして 止めたり出来ます。

シミュレータはテープレコーダのボタンのようなボタンで操作をします。 なお、 右側の画面でマイコンの状態を見ることができます。

プログラムリストの行をダブルクリックすると左側に赤い丸が付きます。 これを ブレークポイントと言います。 矢印一つの Run ボタンを押すと、ブレークポイントで停止します。 これにより、プログラムの途中のレジスタの値などをチェックできます。

その他、一命令だけ実行する Step Into, Call 命令に関しては戻って来るま で一括で実行する Step over, サブルーチン中から抜け出すまで実行する Step out があります。

なお、実行中にI/Oのボタンを押すと、その値に変化させることができます。

5-5. 実行

  1. Arduino をコンピュータに接続します
  2. Windows ではデバイスマネージャー、MacOSX では ls /dev/tty.*などで、Arduino のデバイス識別子を調べます。
  3. Windows Power Shell, cmd.exe, Terminal など、コマンドの入力できる 画面で、プログラムを作成したフォルダに行き、さらに、Debug というフォ ルダに入ります。 「プロジェクト名.hex」というファイルがあることを確認します。
  4. 下記のprogram.batプログラムをフォルダに置きます。
  5. .\program.bat COM3 flashuno.hex./program.bat /dev/tty.usb1234 flashuno.hexなどとするとプログラムがArduino に書き込めます。

program.bat(Windows 用)

以下のプログラムを program.bat というテキストファイルに収めます。

SET dude="C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe"
set conf="C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf"
rem %dude%  -C %conf% -p atmega328p -cstk500v1 -P %1 -b 57600 -D -U flash:w:%2%:i
%dude%  -C %conf% -p m328p -c arduino -P %1  -D -U flash:w:"%2":i

5-6. 演習問題

演習5-1

サンプルプログラムflashuno.asm の各ディレクティヴがどのような意味か、全て調べなさい。

演習5-2

サンプルプログラムflashuno.asm を機能毎に区分し、各機能を説明しなさい。

演習5-3

サンプルプログラムswitchtraining.asm を動作させなさい。

また、プログラムを読み、どのような動きをするのか、説明しなさい。

演習5-4

サンプルプログラムswitchtraining.asm の各ディレクティヴがどのような意味か、全て調べなさい。

演習5-5

サンプルプログラムswitchtraining.asm を機能毎に区分し、各機能を説明しなさい。

switchtraining.asm


  .cseg
  .org	0x0000
      rjmp	reset
  .org	INT_VECTORS_SIZE
  reset:
      ldi     r16,high(RAMEND)
      out     SPH,r16 
      ldi		r16,low(RAMEND)
      out		SPL,r16
    
      sbi		ddrb,pb5
      cbi		ddrd,pd4
      sbi		portd,pd4
  main:
      sbi		portb,pb5
      sbis	pind,pd4
      rjmp	onl
      rcall	shortwait
      rjmp	off
  onl:
      rcall	longwait
  off:
      cbi		portb,pb5
      sbic	pind,pd4
      rjmp	offl
      rcall	shortwait
      rjmp	main
  offl:
      rcall	longwait
      rjmp	main
  
      .equ	shorttime = 4
      .equ	longtime = 40
  .def	wreg0 = r20
  .def	wreg1 = r21
  .def	wreg2 = r22
  shortwait:
      ldi		wreg0,shorttime
      rjmp	wait0
  longwait:
      ldi		wreg0,longtime
  wait0:
      ldi		wreg1,0
  wait1:
      ldi		wreg2,0
  wait2:
      nop
      dec		wreg2
      brne	wait2
      dec		wreg1
      brne	wait1
      dec		wreg0
      brne	wait0
      ret
  .exit

演習5-6

次の操作をする命令の組を書きなさい

  1. レジスタ r16 に 0xA0 を入れる
  2. 出力ポート PORTB に 0x55 を出力する
  3. r16 の値が 0x32 かどうか調べ、等しければ label0 に飛び、等しくなけ れば label1 に飛ぶ
  4. r16 の値が 0x45 と比較し、大きければ label0 に飛び、それ以下なら label1 に飛ぶ
  5. rcall sub0 を 100回呼ぶ

演習5-7

flashuno.asm のプログラムを改造して、点滅の速さが2倍になるようにしよ う

演習5-8

flashuno.asm のプログラムを改造して、点滅の速さが1/2倍になるようにし よう

演習5-9

r16に入れた数だけ、0.1秒ずつLEDを点滅した後、1秒消灯する nblink というサブルーチンを作りなさい。 さらに、 次のプログラムと結合して正常に動作することを確かめなさい。


  .cseg
  .org	0x0000
      rjmp	reset
  .org	INT_VECTORS_SIZE
  reset:
      ldi     r16,high(RAMEND)
      out     SPH,r16 
      ldi		r16,low(RAMEND)
      out		SPL,r16
    
      sbi		ddrb,pb5
  main:
      ldi		r16,0
  loop:
      inc		r16
      push	r16
      rcall	nblink
      pop		r16
      cpi		r16,4
      brne	loop
      rjmp	main

演習5-10

番兵が0の数列をdbで確保し、各数列の値でblink()メソッドを呼ぶプログラム を書きなさい。


sample:
  .db	3,3,7,0
.equ	sampleadr = sample<<1

演習5-11

4番とGNDをつないだときだけ、LED が点灯するプログラムを作りなさい。

演習5-12

4番とGNDをつないだときは、1秒おきに2回LEDが点滅、つないでない時は 1秒おきに短くLEDが点滅するプログラムを作りなさい。

演習5-13

4番とGNDをつないだときは、1秒おきにLEDが1回点滅、2回点滅、3回点滅、 1回点滅,2回点滅、3回点滅と繰り返すが、 つないでない時は同じ回数の点滅を繰り返すプログラムを作りなさい。 つまり、3回点滅の時に線を外せば、そのまま3回点滅を繰り返し、 1回点滅の時に線を外すと1回点滅を繰り返すようにしなさい。


坂本直志 <[email protected]>
東京電機大学工学部情報通信工学科