第 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. 命令セット

ここでは、 AVR Instruction Set Manual を解説します。 AVR Assembler の Instruction も関連しますが、載ってない情報もあります。

アドレッシングモード

mnemonicoperandcomment
ldr0,X; X レジスタの示す番地のメモリの値を r0 レ ジスタへ入れる
ldr0,X+ ; X レジスタの示す番地のメモリの値を r0 レジスタへ入れた後、
; X を 1加算する
ldr0,-Y; Y を 1減算した後、
; Y レジスタの示す番地のメモリの値を r0 レジスタ へ入れる
ldr0,Y+5 ; Y レジスタの値+5番地のメモリの値を r0 レジスタへ入れる

AVR Instruction Set Manual の pp.3-9 という巻頭にページを割いて、図解で解説してある 「アドレッシングモード」とはなんでしょうか? 命令の内容として、「データをレジスタに入れる」など、基本的な動作は同じ であるけど、動作の対象が異なるような別々の命令に対して、同じニモニック を与える一方で、オペランドの指定の仕方を変えて区別するというものです。

命令の分類

AVR Instruction Set の pp.11-15 には命令が分類されています。

Arithmetic and Logic Instructions
数値、論理演算
Branch Instructions
分岐
Data Transfer Instructions
データ転送
Bit and Bit-test Instructions
ビット操作とビット演算
MCU Control Instructions
Micro Controler Unit への操作命令

以下、特徴的な命令を分類しながら説明していきます。

定数を含む命令

アセンブラ言語では、オペランドに数値が書かれていた場合は、基本的にはア ドレスと解釈します。

一方で、コンピュータ用語、あるいはアセンブリ言語用語として、「即値 (immediate)」という言葉があります。 これは演算のデータとしてオペランドに含まれる定数を言います。 なお、ジャンプ命令や、コール命令のような分岐命令にも定数が付きますが、 演算に使用されないので、分岐先のアドレスは即値とは呼ばれないようです。

データ転送

16bit の命令

シフト、ローテート

分岐命令

特殊な命令

フラグレジスタ、条件分岐、スキップ

機械語には任意の論理式による IF 文はありません。その代わり、 演算結果が 0 かどうか、又は桁あふれ(オーバーフロー)したかどうかは常に 監視されていて、Status Register というレジスタに結果が入ります(データ シート pp.26-29)。 これはそれぞれ 1bit で状態を表しますが、このように状態を表す bit をフラグと呼びます。 フラグを 1 にすることを、「フラグを立てる」「フラグをセットする」のよ うに呼びます。一方、フラグを 0 にすることを「フラグを降ろす」「フラグ をクリアする」などと呼びます。

演算結果が 0 になったら Z (Zero)フラグがセットされます。一方、桁溢れをした場合 は C (Carry)フラグがセットされます。 この他、符号付き演算をサポートする N, V, S フラグや、8bit を 10 進2桁 で表現して演算をする時に使用する H フラグなどがあります。

これらのフラグに対して、フラグが立っていたり降りていたりする場合に分岐 する命令が Conditional Branch 命令です。 Conditional Branch 命令の一覧は AVR Instruction Set Manual p. 21 にあります。

一方、フラグを変化させるだけが目的で、結果を残さない引き算命令 CP, CPC, CPI があります。 また、レジスタが0やマイナスであることを検査する TST 命令もあります(但 し、こ れは実際は AND Rd,Rd を TST Rd と呼んでいるだけ)。 これらを組み合わせて、特定の論理式が成立した時に特定の処理を行うという、 高級言語で実装されている IF 文と同等の機能を実現します。

この他、条件分岐として使用できる命令として、スキップ命令があります。こ れは、特定の条件が成立する時に次の命令を飛ばす命令です。 スキップ命令は条件判断と分岐命令が一体になっていて1命令で完結します。 但し、このようなスキップ命令で「飛ばされる次の命令」のサイズは1命令で す。 AVR は RISC ですが、命令は1ワードまたは2ワードの可変長です。それにも関 わらず、次の命令を解釈して1命令スキップするようになっています。 スキップ命令には次のものがあります。

CPSE Rd,Rr
レジスタ Rd と Rr が等しいときにスキップ
SBIC A,b
I/O の A 番地の b ビットがクリアされてたらスキップ
SBIS A,b
I/O の A 番地の b ビットがセットされてたらスキップ
SBRC Rr,b
Rr レジスタの b ビットがクリアされてたらスキップ
SBRS Rr,b
Rr レジスタの b ビットがセットされてたらスキップ

ジャンプ、コール

前述したように、条件分岐命令は、プログラムを連続して実行せずに、指定し た場所に制御を移します。 この他に、「無条件分岐」とも呼ばれる、単に何の条件にも関わらずに指定した場 所に制御を移すジャンプ命令があります。 さらに、サブルーチンを呼び出すコール命令と、呼び出された後で、呼び出し たコール命令の次の番地に戻るリターンがあります。 但し、条件分岐を含め、これらのすべてが相対ジャンプと呼ばれ、オペランド がプログラムカウンタに足される方式のジャンプ命令です。したがって、ジャンプで きる先が、現在のプログラム番地の近傍に限られます。 BRxx 命令は近傍として7bitのオペランドを -64から63 までの間の値として指 定できます。

一方、無条件分岐 rjmp とサブルーチンコール rcall は 12bit を -2048 か ら 2047 までの間の値を指定できます。 サブルーチンから戻るときは範囲を気にせずに ret のみで戻れます。

さらに、 ATmega328Pには 4Mword 内を行き来できる jmp 命令もあります。

この他に、 Z レジスタの値の番地に移動、または呼び出しを行う、 IJMP, ICALL 命令があります。

特殊な算術命令

通常の、8bitレジスタ同士や、8bitレジスタと即値との演算の他に、 特殊かつ有用な算術命令として次のようなものがあります。

ADIW, SBIW
16bit レジスタへの定数加減算命令。但し加減算できる値は 63 以下
INC, DEC
レジスタに1を加える/レジスタから1を減らす。なお、ゼロフラグは変化 しますが、キャリーフラグは変化しません。
LSL, LSR, ROL, ROR, ASR
様々なシフト、ローテート命令。レジスタの内容を左や右に1bit ずらし ます。これらは値を2倍または1/2倍にします。

その他

LPM
Zレジスタで指されるプログラム領域の値をレジスタに入れます
push, pop
スタックにレジスタの内容を入れたり出したりします
nop
何もしません

詳細の読み方

AVR Instruction SET マニュアルには AVR シリーズの全ての命令の解説が載っ ています。 しかし、これは全てのAVRマイコンで使用できるわけではありません。 それぞれのマイコンで使用可能な命令は、それぞれのデータシートに載ってい ます。 ATmega328P では pp. 431-434 に載っています。 ここでは AVR Instruction set マニュアルの命令のページの読み方を 最初の命令 ADC を例に説明します。

ADC — Add with Carry

Description:

Adds two registers and the contents of the C Flag and places the result in the destination register Rd.

Operation:
  1. Rd ← Rd + Rr + C
Syntax:Operands: Program Counter:
(i)ADC Rd,Rr0≤d≤31, 0≤r≤31 PC ← PC + 1
16-bit Opcode:
000111rdddddrrrr
Status Register(SREG) Boolean Formula:
ITHSVNZC
--
H:

Rd3⋅Rr3+Rr3⋅R3+ R3⋅Rd3

Set if there was a carry from bit 3; cleard otherwise

S:

N⊕V, For signed tests.

V:

Rd7⋅Rr7⋅R7+ Rd7Rr7 ⋅R7

Set if two's complement overflow resulted from the operation; cleard otherwise.

N:

R7

Set if MSB of the result is set; cleared otherwise.

Z:

R7R6R5R4R3R2R1R0

Set if the result is $00; cleard otherwise.

C:

Rd7⋅Rr7+ Rr7⋅R7+ R7 ⋅Rd7

Set if there was carry from the MSB of the result; cleard otherwise.

R(Result) equals Rd after the operation.

Examples:

			; Add R1:R2 to R3:R2
	add	r2,r0	; Add low byte
	adc	r3,r1	; Add with carry high byte
Words:

1 (2 bytes)

Cycles:

1

ADC の説明
  1. 最初の ADC はこの機械語に割り当てられた名前です。 これは ニーモニック(mnemonic)と呼ばれます。 一応、ニーモニックの由来のような「Add with Carry」のような文が添えられ ます
  2. Description は文章による命令の説明です。 この命令の場合は「二つのレジスタと C フラグの内容が加算され、結果が宛 先レジスタ Rd に入れられる」いう意味です。
  3. Operation では実際の機械語の動作を示しています。 最初の(i)は箇条書きを表しています。 アドレッシングモードが複数ある場合は、 (ii) などと加算されて列挙されま す。 左矢印は値の代入です。
  4. Syntax はアセンブリ言語の文法を表しています。 k はオペランドを示しています。 Operands で、指定できるオペランド Rd, Rr の d, r 範囲が 0 から 31 まで だと示しています。 AVR は命令ごとに使用できるレジスタの範囲が異なることがありますので、要 注意です。
  5. 16-bit Opcode では実際の機械語がどうなるか示しています。 r,d のビット位置が交差しています。
  6. Status Register (SREG) Boolean Formula では、 最初に SREG のうちの変化するビットを表示しています。 その後、論理式で、厳密な各フラグの計算式が与えられます。 この場合、 I,T 以外のフラグがすべて変化することが分かります。
  7. Examples は実際の使用例をプログラムで示します
  8. Words は機械語の命令長で、 2byte が 1word になります。
  9. Cycles はこの機械語が実行される時間(マシンサイクル)を意味します。 データシートの p.11 Figure 6 にあるように、 CPU クロック 1 つ 分でFetch と呼ばれる命令を読み、 次のクロックで実行します。 但し、実行中に次の命令を読んでいます。これを パイプライン処理と言います。 このため、最初の命令の実行が終了するのは T2 ですが、3番目の命令の実行 が終わるのは T4 です。 そのため、命令単独の実行時間は2CPUサイクルですが、パイプライン処理によ り、実質は 1 CPU サイクルで次の命令に処理が移ります。 但し、条件分岐 やコール命令やスキップ命令など、プログラムの実行する順序を変え る命令の場合、先読みした命令は無駄になるので、実行するのに 2 マシンサイ クル以上かかります。

ADIW — Add Immediate to Word

Description:

Adds an immediate value (0 - 63) to a register pair and places the result in the register pair. This instruction operates on the upper four register pairs, and is well suited for operations on the pointer registers.

This instruction is not available in all devices. Refer to the device specific instruction set summary.

Operation:
  1. Rd+1:Rd ← Rd+1:Rd + K
Syntax:Operands: Program Counter:
(i)ADIW Rd+1:Rd,Kd ∈ {24, 26, 28, 30}, 0≤K≤63 PC ← PC + 1
16-bit Opcode:
10010110KKddKKKK
Status Register(SREG) Boolean Formula:
ITHSVNZC
---
S:

N⊕V, For signed tests.

V:

Rdh7 ⋅R15

Set if two's complement overflow resulted from the operation; cleard otherwise.

N:

R15

Set if MSB of the result is set; cleared otherwise.

Z:

R15R14R13R12R11R10R9R8R7R6R5R4R3R2R1R0

Set if the result is $0000; cleard otherwise.

C:

R15 ⋅Rdh7

Set if there was carry from the MSB of the result; cleard otherwise.

R(Result) equals Rdh:Rdl after the operation (Rdh7-Rdh0 = R15-R8, Rdl7-Rdl0=R7-R0).

Examples:

	adiw	r25:r24,1	; Add 1 to r25:r24
	adiw	ZH:ZL,63	; Add 63 to the Z-pointer(r31:r30)
Words:

1 (2 bytes)

Cycles:

2

ADIW の説明
  1. Immediate はおそらくコンピュータ用語で即値という意味で す。オペランドにリテラルを含み、その値が直接処理されます
  2. Description は文章による命令の説明です。 注意喚起があるように、使用するマイコンのデータシートにこの命令があるかどうか 確認する必要があります。 ATmega328P にはこの命令があります。
  3. Operation での Rd+1:Rd は r25:r24 のように隣同士のレジスタをペアに して、 16bit のレジスタとして使用することを意味します。 また、 K は定数を意味します。
  4. Operands で、使用できるレジスタの範囲が規程されています。 d は 24,26,28,30 のどれかしか使用できません。
  5. Cycles では、この命令は 2 サイクルであると書かれています。 この命令のように1ワードで、プログラムカウンタを別のところに移動しない 命令でも 2 サイクルかかる命令もあります。

LDI — Load Immediate

Description:

Loads an 8 bit constant directly to register 16 to 31.

Operation:
  1. Rd ← K
Syntax:Operands: Program Counter:
(i)LDI Rd,K16≤d≤31, 0≤K≤255 PC ← PC + 1
16-bit Opcode:
1110KKKKddddKKKK
Status Register(SREG) Boolean Formula:
ITHSVNZC
--------
Examples:

	clr r31	; Clear Z high byte
	ldi r30,$F0	; Set Z low byte to $F0
	lpm	; Load constant from Program
		; memory pointed to by Z

Words:

1 (2 bytes)

Cycles:

2

LDI の説明
  1. Description にあるように、レジスタ16から31 にだけ定数を入れます。 レジスタに定数を入れるというのは基本的で重要な操作ですが、なんと、レジ スタ0 から 15 までには入れることができません。
  2. Status Register を変化させません

RJMP — Relative Jump

Description:

Relative jump to an address within PC - 2K +1 and PC + 2K (words). For AVR microcontrollers with Program memory not exceeding 4K words (8K bytes) this instruction can address the entire memory from every address location. See also JMP.

Operation:
  1. PC ← PC+k+1
Syntax:Operands: Program Counter:Stack:
(i)RJMP k-2K≤k<2K PC ← PC + k + 1Unchanged
16-bit Opcode:
1100kkkkkkkkkkkk
Status Register(SREG) Boolean Formula:
ITHSVNZC
--------
Examples:

	cpi	r16,$42	; Compare r16 to $42
	brne	error	; Branch if r16 <> $42
	rjmp	ok	; Unconditional branch
error:	add	r16,r17	; Add r17 to r16
	inc	r16	; Increment r16
ok:	nop		; Destination for rjmp (do nothing)
Words:

1 (2 bytes)

Cycles:

2

RJMP の説明
  1. プログラムカウンタ(PC)を k ワード先に移します。 ATmega328P のプログラムメモリは 32Kワードなので、 12bit ではすべての領域に移 動できません。遠くのアドレスに飛ぶには jmp 命令を使用します。
  2. Status Register を変化させません
  3. PC を変化させるのでパイプライン処理は無効になります。 したがって、次の命令を改めて読み込んで実行させなければならないので、 Cycles は 2 になります。

RCALL — Relative Call to Subroutine

Description:

Relative call to an address within PC - 2K + 1 and PC + 2K (words). The return address (the instruction after the RCALL) is stored onto the Stack. See also CALL. For AVR microcontrollers with Program memory not exceeding 4K words (8K bytes) this instruction can address the entire memory from every address location. The Stack Pointer uses a post-decrement scheme during RCALL.

Operation:
  1. PC ← PC + k + 1 Devices with 16 bits PC, 128K bytes Program memory maximum.
  2. PC ← PC + k + 1 Devices with 22 bits PC, 8M bytes Program memory maximum.
Syntax:Operands: Program Counter:Stack:
(i)RCALL k-2K≤k<2K PC ← PC + k + 1 STACK ← PC + 1SP ← SP -2 (2 bytes, 16 bits)
(ii)RCALL k-2K≤k<2K PC ← PC + k + 1 STACK ← PC + 1 SP ← SP - 3 (3 bytes, 22 bits)
16-bit Opcode:
1101kkkkkkkkkkkk
Status Register(SREG) Boolean Formula:
ITHSVNZC
--------
Examples:

	rcall	routine	; Call subroutine
	...
routine:	push	r14	; Save r14 on the Stack
	...
	pop	r14	; Restore r14
	ret		; Return from subroutine
Words:

1 (2 bytes)

Cycles:

3, devices with 16 bit PC

4, devices with 22 bit PC

Cycles XMEGA:

2, devices with 16 bit PC

3, devices with 22 bit PC

Cycles Reduced Core tinyAVR:

4

RCALL の説明
  1. プログラムカウンタ(PC)を k ワード先に移すとともに、PC+1 をスタック に積みます。 ATmega328P のプログラムメモリは 32Kワードなので、 12bit ではすべての領域に移 動できません。遠くのアドレスを呼び出すには call 命令を使います。
  2. ATmega328P は16bit PC なので 3 サイクルです。

RET — Return from Subroutine

Description:

Returns from subroutine. The return address is loaded from the STACK. The Stack Pointer uses a pre-increment scheme during RET.

Operation:
  1. PC(15:0) ← STACKDevices with 16 bits PC, 128K bytes Program memory maximum.
  2. PC(21:0) ← STACKDevices with 22 bits PC, 8M bytes Program memory maximum.
Syntax:Operands: Program Counter:Stach:
(i) RETNone See Operation SP ← SP + 2 (2 bytes, 16 bits)
(ii) RETNone See Operation SP ← SP + 3 (3 bytes, 22 bits)
16-bit Opcode:
1001010100001000
Status Register(SREG) Boolean Formula:
ITHSVNZC
--------
Examples:

	call	routine	; Call subroutine
	...
routine:	push	r14	; Save r14 on the Stack
	...
	pop	r14	; Restore r14
	ret		; Return from subroutine
Words:

1 (2 bytes)

Cycles:

4 devices with 16-bit PC

5 devices with 22-bit PC

RET の説明
  1. スタックから戻り番地を取り出し、呼び出し位置の次の番地に戻ります。
  2. ATmega328P は16bit PC なので 4 サイクルです。

BREQ — Branch if Equal

Description:

Conditional relative branch. Tests the Zero Flag (Z) and branches relatively to PC if Z is set. If the instruction is executed immediately after any of the instructions CP, CPI, SUB or SUBI, the branch will occur if and only if the unsigned or signed binary number represented in Rd was equal to the unsigned or signed binary number represented in Rr. This instruction branches relatively to PC in either direction (PC - 63 ≤ destination ≤ PC + 64). The parameter k is the offset from PC and is represented in two’s complement form. (Equivalent to instruction BRBS 1,k).

Operation:
  1. (i) If Rd = Rr (Z = 1) then PC ← PC + k + 1, else PC ← PC + 1
Syntax:Operands: Program Counter:
(i) BREQ k-64 ≤ k ≤ +63 PC ← PC + k + 1
PC ← PC + 1, if condition is false
16-bit Opcode:
111100kkkkkkk001
Status Register(SREG) Boolean Formula:
ITHSVNZC
--------
Examples:

	cp	r1,r0	; Compare registers r1 and r0
	breq	equal	; Branch if registers equal
	...
equal:	nop		; Branch destination (do nothing)
Words:

1 (2 bytes)

Cycles:

1 if condition is false

2 if condition is true

BREQ の説明
  1. 直前の演算の結果が0になったら(Z フラグがセットされていたら)プログラム カウンタに k+1 を加えます。そうで無い時は、次の命令に制御を移します。 なお、 k は -64 から 63 までの値なので、近傍にしか移れません。

    なお、このような分岐命令は各フラグごとにセットとクリアで二つずつ用意さ れています。 但し、「ゼロフラグセット」のような名前ではなく、「イコール」のようなフ ラグの意味や使用される状況を意味した言葉が使われていることもあります。

  2. 条件が合わないときは 1 サイクルですが、条件が合ったときは 2 サイクルか かります。

PUSH — Push Register on Stack

Description:

This instruction stores the contents of register Rr on the STACK. The Stack Pointer is post-decremented by 1 after the PUSH. This instruction is not available in all devices. Refer to the device specific instruction set summary.

Operation:
(i)
  1. STACK ← Rr
Syntax:Operands: Program Counter:Stack:
(i) PUSH Rr0 ≤ r ≤ 31 PC ← PC + 1 SP ← SP - 1
16-bit Opcode:
1001001ddddd1111
Status Register(SREG) Boolean Formula:
ITHSVNZC
--------
Examples:

	call	routine	; Call subroutine
	...
routine:	push	r14	; Save r14 on the Stack
	push	r13	; Save r13 on the Stack
	...
	pop	r13	; Restore r13
	pop	r14	; Restore r14
	ret		; Return from subroutine
Words:

1 (2 bytes)

Cycles:

2

Cycles XMEGA:

1

PUSH の説明

レジスタの内容をスタックに入れます。 逆に、POP 命令でスタックから取り出せます。 レジスタの内容を、領域をわざわざ定義せずに退避させたいときなどに使用し ます。 特に、割り込み時など、レジスタの内容を一切破壊できないときに有用です。

LPM — Load Program Memory

Description:

Loads one byte pointed to by the Z-register into the destination register Rd. This instruction features a 100% space effective constant initialization or constant data fetch. The Program memory is organized in 16-bit words while the Z-pointer is a byte address. Thus, the least significant bit of the Z-pointer selects either low byte (ZLSB = 0) or high byte (ZLSB = 1). This instruction can address the first 64K bytes (32K words) of Program memory. The Z-pointer Register can either be left unchanged by the operation, or it can be incremented. The incrementation does not apply to the RAMPZ Register.

Devices with Self-Programming capability can use the LPM instruction to read the Fuse and Lock bit values. Refer to the device documentation for a detailed description.

The LPM instruction is not available in all devices. Refer to the device specific instruction set summary.

The result of these combinations is undefined:


	LPM	r30, Z+
	LPM	r31, Z+
Operation:
Operation:Comment:
(i) R0 ← (Z) Z: Unchanged, R0 implied destination register
(ii) Rd ← (Z) Z: Unchanged
(iii) Rd ← (Z) Z ← Z + 1 Z: Post incremented
Syntax:Operands: Program Counter:
(i) LPMNone, R0 impliedPC ← PC + 1
(ii) LPM Rd, Z 0 ≤ d ≤ 31 PC ← PC + 1
(iii) LPM Rd, Z+ 0 ≤ d ≤ 31 PC ← PC + 1
16-bit Opcode:
(i)1001010111001000
(ii)1001000ddddd0100
(iii)1001000ddddd0101
Status Register(SREG) Boolean Formula:
ITHSVNZC
--------
Examples:

	ldi	ZH, high(Table_1<<1)	; Initialize Z-pointer
	ldi	ZL, low(Table_1<<1)
	lpm	r16, Z		; Load constant from Program
				; Memory pointed to by Z (r31:r30)
	...
Table_1:
	.dw	0x5876		; 0x76 is addresses when ZLSB = 0
				; 0x58 is addresses when ZLSB = 1
Words:

1 (2 bytes)

Cycles:

3

LPM の説明

プログラム領域をレジスタに読み込みます。 プログラム領域は 16bit なので、上位 8bit と下位 8bit をアドレスで区別 するため、(実アドレス)*2 で下位8bit,(実アドレス)*2+1 で上位8bitのデー タを取得できます。 但し、直接アドレスを指定する仕組みは無く、必ず Z=r31:r30 レジスタを使用する必 要があります。 通常、この命令で呼び出すデータは dw や db ディレクティヴで定義します。

ROL — Rotate Left trough Carry

Description:

Shifts all bits in Rd one place to the left. The C Flag is shifted into bit 0 of Rd. Bit 7 is shifted into the C Flag. This operation, combined with LSL, effectively multiplies multi-byte signed and unsigned values by two.

Operation:
a figure of the operation of ROL
Syntax:Operands: Program Counter:
(i) ROL Rd 0 ≤ d ≤ 31PC ← PC + 1
(ii) LPM Rd, Z 0 ≤ d ≤ 31 PC ← PC + 1
(iii) LPM Rd, Z+ 0 ≤ d ≤ 31 PC ← PC + 1
16-bit Opcode: (See ADC Rd,Rd)
000111dddddddddd
Status Register(SREG) Boolean Formula:
ITHSVNZC
--
H:

Rd3

S:

N⊕V, For signed tests.

V:

N⊕ C (For N and C after the shift)

N:

R7 Set if MSB of the result is set; cleared otherwise.

Z:
R7R6R5R4R3R2R1R0 Set if the result is $00; cleared otherwise.
C:

Rd7 Set if, before the shift, the MSB of Rd was set; cleared otherwise.

R (Result) equals Rd after the operation.

Examples:

	lsl	r18	; Multiply r19:r18 by two
	rol	r19 	; r19:r18 is a signed or unsigned two-byte integer
	brcs	oneenc	; Branch if carry set
	...
oneenc:	nop		; Branch destination (do nothing)
Words:

1 (2 bytes)

Cycles:

1

ROL の説明

Rd と C フラグを合わせて、左にビットを回転させます。 Rd の値は2倍され、最下位ビットに C フラグの内容が入れられます。 オーバーフローしたかどうかが C フラグに入ります。

なお、この命令は ADC Rd,Rd と同じです。

ASR — Arithmetic Shift Right

Description:

Shifts all bits in Rd one place to the right. Bit 7 is held constant. Bit 0 is loaded into the C Flag of the SREG. This operation effectively divides a signed value by two without changing its sign. The Carry Flag can be used to round the result.

Operation:
a figure of the operation of ASR
Syntax:Operands: Program Counter:
(i) ASR Rd 0 ≤ d ≤ 31PC ← PC + 1
16-bit Opcode: (See ADC Rd,Rd)
1001010ddddd0101
Status Register(SREG) Boolean Formula:
ITHSVNZC
--
H:

Rd3

S:

N⊕V, For signed tests.

V:

N⊕ C (For N and C after the shift)

N:

R7 Set if MSB of the result is set; cleared otherwise.

Z:
R7R6R5R4R3R2R1R0 Set if the result is $00; cleared otherwise.
C:

Rd0 Set if, before the shift, the LSB of Rd was set; cleared otherwise.

R (Result) equals Rd after the operation.

Examples:

	ldi	r16,$10	; Load decimal 16 into r16
	asr	r16	; r16=r16 / 2
	ldi	r17,$FC	; Load -4 in r17
	asr	r17	; r17=r17/2
Words:

1 (2 bytes)

Cycles:

1

ASR の説明

符号付きの数を 1/2 するために、最上位の符号付きビットはそのままにし、 右シフトをします。 但し、上位に埋め込まれる数は符号ビットと同じになります。

5-4. アセンブル

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

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

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

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

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

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

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

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

5-6. 実行

  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-7. 演習問題

演習5-1

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

演習5-2

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

演習5-3

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

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

演習5-4

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

演習5-5

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

switchtraining.asm


; switchtraining.asm
;
; Created: 2018/09/17 4:39:20
; Author : sakamoto
;

.cseg
.org	0x0000
		rjmp	reset
.org	INT_VECTORS_SIZE
reset:
	ldi     r16,high(RAMEND)
	out     SPH,r16 
		ldi		r16,low(RAMEND)
		out		SPL,r16
.equ	onb	= 0b00111111
.equ	ond	= 0b11000000
.equ	pullup	= 0b00110000
.equ	onc	= 0b00001111
		ldi		r16,onb
		out		ddrb, r16
		ldi		r16,ond
		out		ddrd, r16
		ldi		r16,pullup
		out		portd, r16
		ldi		r16,onc
		out		ddrc, r16
.def	now	= r17
.def	prev	= r18
.def	cond	= r19
		clr		prev
		ser		cond


.macro	clrport
		in	r16,@0
		andi	r16,~@1
		out	@0,r16
.endmacro
.macro setport
		in	r16,@0
		ori	r16,@1
		out	@0,r16
.endmacro


main:
		in	now,pind
		sbrc	prev,pind5
		rjmp	pressed
		sbrs	now,pind5
		rjmp	notpressed
nowpressed:
		ldi	r16,1<<pind4
		eor	cond,r16
notpressed:
pressed:
		andi	prev,~(1<<pind5)
		or	prev,now
		eor	now, cond
		sbrc	now,pind4
		rjmp	swon
swoff:
		clrport portb,onb
		clrport	portd,ond
		clrport portc,onc
		rjmp	main
swon:
		setport portb,onb
		setport	portd,ond
		setport portc,onc
		rjmp	main

.exit

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