このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。
機械語とはコンピュータ(CPU)を動作させるための数値列の事です。 ATmega328p では 16bit または 32 bit で 1 つの命令を表します。 一方アセンブリ言語とはこれらの数値をその機能などが直観でわ かるように英単語や記号等を当てはめた物です。 アセンブリ言語で記述されたプログラムを機械語に直す事をアセンブル と言います。また、アセンブルを行うコンピュータプログラムを アセンブラと言います。 但し、アセンブリ言語をアセンブラと呼ぶ事もあります。
アセンブラの最新のマニュアルは PDF になってなく、 HTML バージョン だけあります。 ver. 1 のアセンブラ用のマニュアルは PDF になってます。 ver.1 に無くて、 ver. 2 にあるのは、条件アセンブリやプリプロセッサの機 能です。
機械語やアセンブラでは頻繁に十六進数など、十進数以外の表記を使います。 これらのルールはアセンブラのマニュアルにあります。
アセンブリ言語は一つの機械語を機能と引数に分けて表現します。
機能の部分を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
となります。
オペランドとして、メモリの番地の他、ビット位置や、定数(リテラル)、演算
結果の収納先などを指定することができます。
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 用の命令として in, out があります。 さらに、 I/O 自体は 64バイト用意されているのですが、前半の 32 バイトに 対してはビット演算命令 cbi, sbi, sbic, sbis を使用できます。 なお、ld, ldd, st, std 命令を用いて、 I/O 番地に 0x20 を加えた メモリ空間としてもアクセスできます。
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 に書きます。 これの読み書きの仕組みは I/O にある EEPROM のアドレスレジスタとデータ レジスタを使用します。 アドレスレジスタにアドレスを書けば、データレジスタにデータを読み書きでき ます(データシート pp.41-45)。 なお、eseg と db ディレクティヴを使用すると、プログラマから書き込んで 初期化することもできます。
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)。 割り込みとは次の条件が発生した時のことを言います。
これらの条件にマイコンが反応すると、それぞれの割り込みに対して、定めら れた割り込みベクタの番地のプログラムを実行します。
割り込みを許可/不許可するための値やレジスタのことを割り込みマス
クと言います。
これには、個別の割り込みを ON/OFF するものの他に、全体の割り込みを
ON/OFF する全体割り込み許可フラグが Status Register の Bit7 I にありま
す(データシート p.269)。
割り込みを使用する際は、個別の割り込みの設定をしたのち、この全体割り込
み許可を行います。
一方、割り込みが発生した時は、割り込みベクタが呼び出されますが、この際、
戻り番地がスタックに入る他に、この全体割り込み許可フラグがクリアされま
す。
割り込み処理を終えた後、割り込み許可フラグをセットすると同時に割り込み
発生した番地に戻らなければなりませんが、これを1命令で行う
RETI
命令が用意されています。
このような他の要因に影響されずにひとまとまりに操作することを
アトミック
と言います。
AVR のチップにおいて、クロックの入力方法や、ピンの使用方法など、起動以 前に設定しなければならない項目があります。 これらは、プログラムなどと一緒に設定情報として書き込む必要があります。 この設定情報はヒューズビットと呼ばれています。 これは 3 Byte あり、データシートpp.346-348 に記載されています。
ヒューズビットで設定可能なのは、Boot領域の設定、プログラムや EEPROM の 読み書きの設定、Broun-out 割り込みにおける電圧設定の他に、外部リセット 端子の無効化、クロックの内部外部切り替え、内部クロックの速度の設定など です。 本講義では、これらはすべてデフォルトで使用しますが、高速に動作させたい など、デフォルト以外の動作をさせる場合は、精読して活用する必要がありま す。
ここでは、 AVR Instruction Set Manual を解説します。 AVR Assembler の Instruction も関連しますが、載ってない情報もあります。
mnemonic | operand | comment |
---|---|---|
ld | r0,X | ; X レジスタの示す番地のメモリの値を r0 レ ジスタへ入れる |
ld | r0,X+ | ; X レジスタの示す番地のメモリの値を r0 レジスタへ入れた後、 |
; X を 1加算する | ||
ld | r0,-Y | ; Y を 1減算した後、 |
; Y レジスタの示す番地のメモリの値を r0 レジスタ へ入れる | ||
ld | r0,Y+5 | ; Y レジスタの値+5番地のメモリの値を r0 レジスタへ入れる |
AVR Instruction Set Manual の pp.3-9 という巻頭にページを割いて、図解で解説してある 「アドレッシングモード」とはなんでしょうか? 命令の内容として、「データをレジスタに入れる」など、基本的な動作は同じ であるけど、動作の対象が異なるような別々の命令に対して、同じニモニック を与える一方で、オペランドの指定の仕方を変えて区別するというものです。
AVR Instruction Set の pp.11-15 には命令が分類されています。
以下、特徴的な命令を分類しながら説明していきます。
アセンブラ言語では、オペランドに数値が書かれていた場合は、基本的にはア ドレスと解釈します。
一方で、コンピュータ用語、あるいはアセンブリ言語用語として、「即値 (immediate)」という言葉があります。 これは演算のデータとしてオペランドに含まれる定数を言います。
なお、ジャンプ命令や、コール命令のような分岐命令にも定数が付きますが、 演算に使用されないので、分岐先のアドレスは即値とは呼ばれないようです。
データの転送は以下のような命名規則になっています。
さまざまなアドレッシングモードが用意されています
レジスタペアを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命令スキップするようになっています。 スキップ命令には次のものがあります。
前述したように、条件分岐命令は、プログラムを連続して実行せずに、指定し た場所に制御を移します。 この他に、「無条件分岐」とも呼ばれる、単に何の条件にも関わらずに指定した場 所に制御を移すジャンプ命令があります。 さらに、サブルーチンを呼び出すコール命令と、呼び出された後で、呼び出し たコール命令の次の番地に戻るリターンがあります。 但し、条件分岐を含め、これらのすべてが相対ジャンプと呼ばれ、オペランド がプログラムカウンタに足される方式のジャンプ命令です。したがって、ジャンプで きる先が、現在のプログラム番地の近傍に限られます。 BRxx 命令は近傍として7bitのオペランドを -64から63 までの間の値として指 定できます。
一方、無条件分岐 rjmp とサブルーチンコール rcall は 12bit を -2048 か ら 2047 までの間の値を指定できます。 サブルーチンから戻るときは範囲を気にせずに ret のみで戻れます。
さらに、 ATmega328Pには 4Mword 内を行き来できる jmp 命令もあります。
この他に、 Z レジスタの値の番地に移動、または呼び出しを行う、 IJMP, ICALL 命令があります。
通常の、8bitレジスタ同士や、8bitレジスタと即値との演算の他に、 特殊かつ有用な算術命令として次のようなものがあります。
AVR Instruction SET マニュアルには AVR シリーズの全ての命令の解説が載っ ています。 しかし、これは全てのAVRマイコンで使用できるわけではありません。 それぞれのマイコンで使用可能な命令は、それぞれのデータシートに載ってい ます。 ATmega328P では pp. 431-434 に載っています。 ここでは AVR Instruction set マニュアルの命令のページの読み方を 最初の命令 ADC を例に説明します。
Adds two registers and the contents of the C Flag and places the result in the destination register Rd.
Syntax: | Operands: | Program Counter: | |
---|---|---|---|
(i) | ADC Rd,Rr | 0≤d≤31, 0≤r≤31 | PC ← PC + 1 |
0001 | 11rd | dddd | rrrr |
I | T | H | S | V | N | Z | C |
---|---|---|---|---|---|---|---|
- | - | ⇔ | ⇔ | ⇔ | ⇔ | ⇔ | ⇔ |
Rd3⋅Rr3+Rr3⋅R3+ R3⋅Rd3
Set if there was a carry from bit 3; cleard otherwise
N⊕V, For signed tests.
Rd7⋅Rr7⋅R7+ Rd7 ⋅ Rr7 ⋅R7
Set if two's complement overflow resulted from the operation; cleard otherwise.
R7
Set if MSB of the result is set; cleared otherwise.
R7⋅ R6⋅ R5⋅ R4⋅ R3⋅ R2⋅ R1⋅ R0
Set if the result is $00; cleard otherwise.
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.
; Add R1:R2 to R3:R2
add r2,r0 ; Add low byte
adc r3,r1 ; Add with carry high byte
1 (2 bytes)
1
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.
Syntax: | Operands: | Program Counter: | |
---|---|---|---|
(i) | ADIW Rd+1:Rd,K | d ∈ {24, 26, 28, 30}, 0≤K≤63 | PC ← PC + 1 |
1001 | 0110 | KKdd | KKKK |
I | T | H | S | V | N | Z | C |
---|---|---|---|---|---|---|---|
- | - | - | ⇔ | ⇔ | ⇔ | ⇔ | ⇔ |
N⊕V, For signed tests.
Rdh7 ⋅R15
Set if two's complement overflow resulted from the operation; cleard otherwise.
R15
Set if MSB of the result is set; cleared otherwise.
R15⋅ R14⋅ R13⋅ R12⋅ R11⋅ R10⋅ R9⋅ R8⋅ R7⋅ R6⋅ R5⋅ R4⋅ R3⋅ R2⋅ R1⋅ R0
Set if the result is $0000; cleard otherwise.
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).
adiw r25:r24,1 ; Add 1 to r25:r24
adiw ZH:ZL,63 ; Add 63 to the Z-pointer(r31:r30)
1 (2 bytes)
2
Loads an 8 bit constant directly to register 16 to 31.
Syntax: | Operands: | Program Counter: | |
---|---|---|---|
(i) | LDI Rd,K | 16≤d≤31, 0≤K≤255 | PC ← PC + 1 |
1110 | KKKK | dddd | KKKK |
I | T | H | S | V | N | Z | C |
---|---|---|---|---|---|---|---|
- | - | - | - | - | - | - | - |
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
1 (2 bytes)
2
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.
Syntax: | Operands: | Program Counter: | Stack: | |
---|---|---|---|---|
(i) | RJMP k | -2K≤k<2K | PC ← PC + k + 1 | Unchanged |
1100 | kkkk | kkkk | kkkk |
I | T | H | S | V | N | Z | C |
---|---|---|---|---|---|---|---|
- | - | - | - | - | - | - | - |
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)
1 (2 bytes)
2
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.
Syntax: | Operands: | Program Counter: | Stack: | ||
---|---|---|---|---|---|
(i) | RCALL k | -2K≤k<2K | PC ← PC + k + 1 STACK ← PC + 1 | SP ← 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) |
1101 | kkkk | kkkk | kkkk |
I | T | H | S | V | N | Z | C |
---|---|---|---|---|---|---|---|
- | - | - | - | - | - | - | - |
rcall routine ; Call subroutine
...
routine: push r14 ; Save r14 on the Stack
...
pop r14 ; Restore r14
ret ; Return from subroutine
1 (2 bytes)
3, devices with 16 bit PC
4, devices with 22 bit PC
2, devices with 16 bit PC
3, devices with 22 bit PC
4
Returns from subroutine. The return address is loaded from the STACK. The Stack Pointer uses a pre-increment scheme during RET.
Syntax: | Operands: | Program Counter: | Stach: | ||
---|---|---|---|---|---|
(i) | RET | None | See Operation | SP ← SP + 2 | (2 bytes, 16 bits) |
(ii) | RET | None | See Operation | SP ← SP + 3 | (3 bytes, 22 bits) |
1001 | 0101 | 0000 | 1000 |
I | T | H | S | V | N | Z | C |
---|---|---|---|---|---|---|---|
- | - | - | - | - | - | - | - |
call routine ; Call subroutine
...
routine: push r14 ; Save r14 on the Stack
...
pop r14 ; Restore r14
ret ; Return from subroutine
1 (2 bytes)
4 devices with 16-bit PC
5 devices with 22-bit PC
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).
Syntax: | Operands: | Program Counter: | |
---|---|---|---|
(i) | BREQ k | -64 ≤ k ≤ +63 | PC ← PC + k + 1
PC ← PC + 1, if condition is false |
1111 | 00kk | kkkk | k001 |
I | T | H | S | V | N | Z | C |
---|---|---|---|---|---|---|---|
- | - | - | - | - | - | - | - |
cp r1,r0 ; Compare registers r1 and r0
breq equal ; Branch if registers equal
...
equal: nop ; Branch destination (do nothing)
1 (2 bytes)
1 if condition is false
2 if condition is true
直前の演算の結果が0になったら(Z フラグがセットされていたら)プログラム カウンタに k+1 を加えます。そうで無い時は、次の命令に制御を移します。 なお、 k は -64 から 63 までの値なので、近傍にしか移れません。
なお、このような分岐命令は各フラグごとにセットとクリアで二つずつ用意さ れています。 但し、「ゼロフラグセット」のような名前ではなく、「イコール」のようなフ ラグの意味や使用される状況を意味した言葉が使われていることもあります。
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.
Syntax: | Operands: | Program Counter: | Stack: | |
---|---|---|---|---|
(i) | PUSH Rr | 0 ≤ r ≤ 31 | PC ← PC + 1 | SP ← SP - 1 |
1001 | 001d | dddd | 1111 |
I | T | H | S | V | N | Z | C |
---|---|---|---|---|---|---|---|
- | - | - | - | - | - | - | - |
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
1 (2 bytes)
2
1
レジスタの内容をスタックに入れます。 逆に、POP 命令でスタックから取り出せます。 レジスタの内容を、領域をわざわざ定義せずに退避させたいときなどに使用し ます。 特に、割り込み時など、レジスタの内容を一切破壊できないときに有用です。
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: | 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) | LPM | None, R0 implied | PC ← PC + 1 |
(ii) | LPM Rd, Z | 0 ≤ d ≤ 31 | PC ← PC + 1 |
(iii) | LPM Rd, Z+ | 0 ≤ d ≤ 31 | PC ← PC + 1 |
(i) | 1001 | 0101 | 1100 | 1000 |
---|---|---|---|---|
(ii) | 1001 | 000d | dddd | 0100 |
(iii) | 1001 | 000d | dddd | 0101 |
I | T | H | S | V | N | Z | C |
---|---|---|---|---|---|---|---|
- | - | - | - | - | - | - | - |
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
1 (2 bytes)
3
プログラム領域をレジスタに読み込みます。 プログラム領域は 16bit なので、上位 8bit と下位 8bit をアドレスで区別 するため、(実アドレス)*2 で下位8bit,(実アドレス)*2+1 で上位8bitのデー タを取得できます。 但し、直接アドレスを指定する仕組みは無く、必ず Z=r31:r30 レジスタを使用する必 要があります。 通常、この命令で呼び出すデータは dw や db ディレクティヴで定義します。
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.
Syntax: | Operands: | Program Counter: | |
---|---|---|---|
(i) | ROL Rd | 0 ≤ d ≤ 31 | PC ← PC + 1 |
(ii) | LPM Rd, Z | 0 ≤ d ≤ 31 | PC ← PC + 1 |
(iii) | LPM Rd, Z+ | 0 ≤ d ≤ 31 | PC ← PC + 1 |
0001 | 11dd | dddd | dddd |
I | T | H | S | V | N | Z | C |
---|---|---|---|---|---|---|---|
- | - | ⇔ | ⇔ | ⇔ | ⇔ | ⇔ | ⇔ |
Rd3
N⊕V, For signed tests.
N⊕ C (For N and C after the shift)
R7 Set if MSB of the result is set; cleared otherwise.
Rd7 Set if, before the shift, the MSB of Rd was set; cleared otherwise.
R (Result) equals Rd after the operation.
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)
1 (2 bytes)
1
Rd と C フラグを合わせて、左にビットを回転させます。 Rd の値は2倍され、最下位ビットに C フラグの内容が入れられます。 オーバーフローしたかどうかが C フラグに入ります。
なお、この命令は ADC Rd,Rd と同じです。
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.
Syntax: | Operands: | Program Counter: | |
---|---|---|---|
(i) | ASR Rd | 0 ≤ d ≤ 31 | PC ← PC + 1 |
1001 | 010d | dddd | 0101 |
I | T | H | S | V | N | Z | C |
---|---|---|---|---|---|---|---|
- | - | ⇔ | ⇔ | ⇔ | ⇔ | ⇔ | ⇔ |
Rd3
N⊕V, For signed tests.
N⊕ C (For N and C after the shift)
R7 Set if MSB of the result is set; cleared otherwise.
Rd0 Set if, before the shift, the LSB of Rd was set; cleared otherwise.
R (Result) equals Rd after the operation.
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
1 (2 bytes)
1
符号付きの数を 1/2 するために、最上位の符号付きビットはそのままにし、 右シフトをします。 但し、上位に埋め込まれる数は符号ビットと同じになります。
Arduino はマイコンのプログラミングを学ぶために開発された基板です。 Arduino UNO では、ATmega 328P のプログラミングを行います。
Arduino の回路図を入手しなさい。そして、 LED が ATmega328Pの何番ピンに接続しているか調べなさい。
Arduino の LED を点灯させるために、マイコンにすべきことをまとめなさ い。 つまり、以下のC++のプログラムで実際にマイコンがすべき動作をまとめな さい
pinMode(LED_BUILTIN,OUTPUT);
digitalWrite(LED_BUILTIN,High);
次を行うのに使う命令を示しなさい
Arduino の開発環境で、ツール→ライブラリを管理の画面を出し、 以下のキーワードのどれかを検索し、気に入ったライブラリ一つについて、 詳細を読み、何をするか、どのような使い方をするかなどを調べてまとめな さい。 そして、プレゼンテーションの原稿を作成しなさい。