第 4 回 AVR マイコンのアセンブリ言語とアーキテクチャ

本日の内容


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

4-1. 準備

機械語とはコンピュータ(CPU)を動作させるための数値列の事です。 ATmega328p では 16bit または 32 bit で 1 つの命令を表します。 一方アセンブリ言語とはこれらの数値をその機能などが直観でわ かるように英単語や記号等を当てはめた物です。 アセンブリ言語で記述されたプログラムを機械語に直す事をアセンブル と言います。また、アセンブルを行うコンピュータプログラムを アセンブラと言います。 但し、アセンブリ言語をアセンブラと呼ぶ事もあります。

アセンブラの最新のマニュアルは PDF になってなく、 HTML バージョン だけあります。 ver. 1 のアセンブラ用のマニュアルは PDF になってます。 ver.1 に無くて、 ver. 2 にあるのは、条件アセンブリやプリプロセッサの機 能です。

リテラル(定数)

機械語やアセンブラでは頻繁に十六進数など、十進数以外の表記を使います。 これらのルールはアセンブラのマニュアルにあります。

十進数
0で始まらない 0から9までの数の集まり。 または単体の0。 また、マイナス記号が使えるので、負の数も使用できます。
十六進数
$または 0x で始めると十六進数を表します。 $F, $0f, 0xF, 0x0f など
二進数
0b で始めると二進数を表します。 0b00010101 など。
八進数
0で始めて 0 から 7 の列で八進数を表します。

アセンブリ言語は一つの機械語を機能と引数に分けて表現します。 機能の部分をmnemonic(ニモニック)と呼び、引数をオペラン ドと言います。 例えば、0000 1100 0000 0000は R0 レジスタと R0 レジスタを 足して、 R0 に収める機械語です。 また、0000 1100 0000 0001 は R0 レジスタと R1 レジスタを 足して、 R0 に収める機械語です。 一方、0000 1100 0001 0000 は R1 レジスタと R0 レジスタを 足して、 R1 に収める機械語です。 総称すると、0000 11rd dddd rrrrは Rd レジスタと Rr レジスタを 足して、 Rd に収める機械語です。 したがって、これらに対して機能を表すニモニックを add とし、Rd と Rr の 部分をオペランドとします。 つまり、Rd レジスタと Rr レジスタを足して Rd に収めることを、アセンブリ 言語で表現すると add Rd,Rr となります。 オペランドとして、メモリの番地の他、ビット位置や、定数(リテラル)、演算 結果の収納先などを指定することができます。

4-2. AVR マイコンのアーキテクチャ

AVR をプログラミングする観点で見た時の、 AVR の特徴的なアーキテクチャ についてお話します。

ハーバードアーキテクチャ

我々が普段使っている Windows を使うパソコンでは、メモリは単一のもので、 プログラムとデータが共存しています。これを(フォン)ノイマン型コンピュー タと呼んでいます。 一方、AVR では、データシートの p.13 Figure 4-1 にあるように、 Program Flash と SRAM に明確な区分があり、共存していません。これを ハーバードアーキテクチャと言います (由来のハーバードマークI は世界初の汎用(リレー式)計算機(1944))。 プログラムとデータの扱い方が違うので、プログラムをメモリ上で扱う OS や コンパイラなどの実装は難しいという欠点はあります。 しかし AVR の用途から考えると OS やコンパイラを使うことは無さそうなの で、問題無さそうです。 さらにこのようなアーキテクチャでは、CPU がプログラムを読み込む仕組みを 単純化できるなど長所もあります。 また AVR のようにプログラムの語長とデータの語長がそれぞれ 16bit と 8bit と異なるデザインも可能です。

プログラム領域

ATmega328P のプログラム領域は データシートの Figure 12-1(p.36) にあるよ うに、0x0000 から 0x3fff まであります。 このうち、 Boot Flash Section という領域があり、起動時の補助プログラム を入れることができます。 Boot Loader に関しては30章に書かれています。 電源を入れた時やリセットした時は、ヒューズビットの値により、 ブートローダの領域、あるいは0x0000 番地から実行されます (リセットベクタ)。 割り込み が発生した時は、発生した割り込みに応じて 0x0001 番地から 0x0032 番地の どれかが呼び出されます(割り込みベクタ)。 そのため、通常はこのベクタにはジャンプ命令のみ書いて、それぞれを処理する 番地に移行するようにします。 割り込みベクタ以降はどこにプログラムを書いても影響はありません。 但し、ジャンプ命令でどこへでも飛べるわけでは無いので、プログラムはなる べく近くに書きます。

プログラム領域は32Kbyte ですが、プログラムカウンタは 14bit あるので、 16Kbyte にアクセスできます。 アセンブリ言語では PC という記号で参照できます。 プログラム領域は 16 bit = 1 word でプログラムを記述しますが、一方で、 データも記述できます。 さらに本講義では扱いませんが、プログラム領域をプログラムによって書き換 えることもできます。

プログラム領域にデータを書くには .db や .dw ディレクティヴを使用します。 AVR のデータ処理単位は 8bit ですが、プログラム領域は 16bit 単位でアド レスが振られているので、プログラムからアドレスを指定してデータを読み出 す場合、(プログラム領域のアドレス*2)で最初のバイト、 (プログラム領域のアドレス*2+1)で次のバイトを読むことができます。 プログラム領域をアクセスするには lpm 命令を使いますが、アドレス指定は Z レジスタのみが使用できます。

メモリ構造

AVR がデータをやりとりする場所は、プログラム領域の他、レジスタ、I/O、 SRAM領域、EEPROM があります。 このうち、レジスタ、I/O、SRAM は連続したアドレスが割り振られていて、 LD と ST 命令でやりとりできます(Figure 12-2 p.37)。 しかし、レジスタや I/O に関しては、より多くの専用の命令が用意されてい ます。

レジスタ

内部の数値論理ユニット(ALU)と接続して演算を行えるのはレジスタだけです。 したがって、機械語のプログラミングではレジスタの操作が重要になります。

AVRには 32 個のレジスタ(r0-r31)がありますが、 すべてのレジスタが同等ではありません。 r27:r26=X, r29:r28=Y, r31:r30=Z と、3組のレジスタは 16bit のインデック スレジスタとしてメモリの番地指定に使用できます。 また、定数読み込み命令 ldi 掛け算命令 mul やビット操作命令は r16 から r31 までしか使えません。 さらに小数の掛け算命令 fmul, fmuls, fmulsu は r16 から r23 までしか使 えません。 なお、これらの掛け算命令による結果は r1:r0 に入ります。 従って、レジスタで一番命令の制限が無いのは r16 から r23 までなので、通 常のプログラミングではこのレジスタを主に使用します。 さらに、 r26 から r31 はインデックスレジスタとして利用します。

I/O

各入出力ポートの他、割り込みや外部との通信用に I/O があります。 I/O 用の命令として in, out があります。 さらに、 I/O 自体は 64バイト用意されているのですが、前半の 32 バイトに 対してはビット演算命令 cbi, sbi, sbic, sbis を使用できます。 なお、ld, ldd, st, std 命令を用いて、 I/O 番地に 0x20 を加えた メモリ空間としてもアクセスできます。

SRAM、スタック

SRAM は 0x0060 番地から 0x08FF番地(RAMEND) までの連続した領域として使 用できます。 ここへは ld, ldd, st, std 命令でアクセスします。

一方、AVR では、この領域にスタックを置き、サブルーチン呼び出し rcall, ret などで使用します。 そのため、プログラムの開始時にスタックポインタを設定する必要があります。 典型的なプログラムの初期設定は、データシートの Interruptsの章載っています。


0x0000
	rjmp	RESET	; Reset Handler
...					; 以下割り込みハンドラの記述が続く
RESET:	ldi	r16,high(RAMEND)
	out	SPH,r16
	ldi	r16,low(RAMEND)
	out	SPL,r16

スタックは rcall, ret, reti で戻り番地を記憶するために使われる他、8bit のデータを出し入れをする push, pop でも使用できます。

EEPROM

ゲームのデータや利用者の設定情報など、電源を切っても失いたくないデータ は EEPROM に書きます。 これの読み書きの仕組みは I/O にある EEPROM のアドレスレジスタとデータ レジスタを使用します。 アドレスレジスタにアドレスを書けば、データレジスタにデータを読み書きでき ます(データシート pp.41-45)。 なお、eseg と db ディレクティヴを使用すると、プログラマから書き込んで 初期化することもできます。

I/O Memory

I/O 領域は 64 Byte あり、 データシート p.427 の Register Summary にまとめられてます。 この領域は基本的には LD, LDS, LDD, ST, STS, STD 命令で読み書きできます。 その時は、p.15 Figure 9 に示されるアドレスである 0x0020 から 0x00C6 の 間のアドレスを使用します。 この I/O 領域には、各PORT の信号を制御したり、割り込みの制御をするなど、 様々な機能が埋め込まれています。

この領域に対する特別な入出力命令として IN , OUT 命令があります。 この場合、アドレスは 0x00 から 0x3F としてアクセスします。 さらに、前半のアドレス 0x00 から 0x1F の I/O 領域だけに有効な命令とし て、特定のビットを検査する SBI, CBI があります。

割り込み

電源を入れた時やリセットした時は 0 番地から実行が始まります。 一方割り込みが発生した時はそれぞれの割り込みに割り当てられた割り込みベ クタが呼び出されます。 (データシート p.84 Table 16-1)。 割り込みとは次の条件が発生した時のことを言います。

  1. Reset, 電源On, 電圧低下によるリセット(Brown-out Reset), Watch dog Reset
  2. 外部割り込み0
  3. 外部割り込み1
  4. ピン変更割り込み
  5. ウォッチドッグタイマーオーバーフロー
  6. タイマー2 A と一致
  7. タイマー2 B と一致
  8. タイマー2 オーバーフロー
  9. タイマー1イベント発生
  10. タイマー1 A と一致
  11. タイマー1 B と一致
  12. タイマー1 オーバーフロー
  13. タイマー0 A と一致
  14. タイマー0 B と一致
  15. タイマー0 オーバーフロー
  16. SPI 転送完了
  17. USART0 Rx完了
  18. USART0 データレジスタ空
  19. USART0 Tx完了
  20. ADC変換完了
  21. EEPROM準備完了
  22. アナログコンパレータ
  23. I2C
  24. Store Program Memory完了

これらの条件にマイコンが反応すると、それぞれの割り込みに対して、定めら れた割り込みベクタの番地のプログラムを実行します。

割り込みを許可/不許可するための値やレジスタのことを割り込みマス クと言います。 これには、個別の割り込みを ON/OFF するものの他に、全体の割り込みを ON/OFF する全体割り込み許可フラグが Status Register の Bit7 I にありま す(データシート p.269)。 割り込みを使用する際は、個別の割り込みの設定をしたのち、この全体割り込 み許可を行います。 一方、割り込みが発生した時は、割り込みベクタが呼び出されますが、この際、 戻り番地がスタックに入る他に、この全体割り込み許可フラグがクリアされま す。 割り込み処理を終えた後、割り込み許可フラグをセットすると同時に割り込み 発生した番地に戻らなければなりませんが、これを1命令で行う RETI 命令が用意されています。 このような他の要因に影響されずにひとまとまりに操作することを アトミック と言います。

4-3. ヒューズビット

AVR のチップにおいて、クロックの入力方法や、ピンの使用方法など、起動以 前に設定しなければならない項目があります。 これらは、プログラムなどと一緒に設定情報として書き込む必要があります。 この設定情報はヒューズビットと呼ばれています。 これは 3 Byte あり、データシートpp.346-348 に記載されています。

ヒューズビットで設定可能なのは、Boot領域の設定、プログラムや EEPROM の 読み書きの設定、Broun-out 割り込みにおける電圧設定の他に、外部リセット 端子の無効化、クロックの内部外部切り替え、内部クロックの速度の設定など です。 本講義では、これらはすべてデフォルトで使用しますが、高速に動作させたい など、デフォルト以外の動作をさせる場合は、精読して活用する必要がありま す。

4-4. 命令セット

ここでは、 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)」という言葉があります。 これは演算のデータとしてオペランドに含まれる定数を言います。

なお、ジャンプ命令や、コール命令のような分岐命令にも定数が付きますが、 演算に使用されないので、分岐先のアドレスは即値とは呼ばれないようです。

データ転送

データの転送は以下のような命名規則になっています。

レジスタ→レジスタ
mov
メモリ→レジスタ
ld
定数(即値)→レジスタ
ldi
レジスタ→メモリ
st

さまざまなアドレッシングモードが用意されています

16bit の命令

レジスタペアを16bitレジスタとして扱う命令が少数用意されています。 用途は、アドレス計算を行うため、掛け算の結果を納めるため、浮動小数 点数など特定の16bitのデータを扱うためなど、限定されるため、 できることも、命令数も少ないです。 ただし、基本的には8bit命令の組み合わせでできることを、1命令ででき るように用意されていますので、活用するととても便利です。

シフト、ローテート

レジスタとキャリーフラグを含めてビット列を一桁動かします。 数(最上位ビットが符号ビット)として2倍や1/2倍に対応する場合「算術(Arithmetic)」と形容され、 単純にビット移動するだけの場合は「論理(Logical)」と形容されます。

キャリーフラグを含めているので、条件分岐と組み合わせて使用できます。

特殊な命令

sleep命令は設定により動作を変化させるため、用法やテストをする時は 要注意です。 また、割り込みに関する命令は、使用方法に定石があるため、データシートの 用例を熟知する必要があります。

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

機械語には任意の論理式による 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 するために、最上位の符号付きビットはそのままにし、 右シフトをします。 但し、上位に埋め込まれる数は符号ビットと同じになります。

4-5. Arduino のアーキテクチャ

Arduino はマイコンのプログラミングを学ぶために開発された基板です。 Arduino UNO では、ATmega 328P のプログラミングを行います。

4-6. 演習問題

演習4-1

Arduino の回路図を入手しなさい。そして、 LED が ATmega328Pの何番ピンに接続しているか調べなさい。

演習4-2

Arduino の LED を点灯させるために、マイコンにすべきことをまとめなさ い。 つまり、以下のC++のプログラムで実際にマイコンがすべき動作をまとめな さい


pinMode(LED_BUILTIN,OUTPUT);
digitalWrite(LED_BUILTIN,High);  

演習4-3

次を行うのに使う命令を示しなさい

  1. レジスタに定数を入れる
  2. I/Oにレジスタの値を出力する
  3. レジスタr16 と r17が等しいかどうかを調べる
  4. レジスタr16の4bit目が0かどうかを調べる
  5. I/OのPORTBの6bit目が1かどうかを調べる
  6. ラベルlabel0のサブルーチンを呼び出す
  7. サブルーチンから戻る
  8. なにもしない
  9. レジスタr16の値を1減らす
  10. 直前の計算結果が0だったらlabel0に飛ぶ
  11. レジスタr17の値を二倍にする
  12. レジスタr18の値を半分にする

演習4-4

Arduino の開発環境で、ツール→ライブラリを管理の画面を出し、 以下のキーワードのどれかを検索し、気に入ったライブラリ一つについて、 詳細を読み、何をするか、どのような使い方をするかなどを調べてまとめな さい。 そして、プレゼンテーションの原稿を作成しなさい。


坂本直志 <sakamoto@c.dendai.ac.jp>
東京電機大学工学部情報通信工学科