6. AVR CPUコア

6.1 概要

 この節ではAVRコア・アーキテクチャの一般的な内容について説明します。CPUコアの主機能はプログラムの正しい実行を確実に行うことです。 したがってCPUには、メモリへのアクセス、計算の実行、周辺回路の制御、そして、割り込み処理を行う能力が必要です。

6.2 アーキテクチャ概要


Figure 6-1. AVRアーキテクチャのブロック図

 処理速度と並行処理の効率を最大化するため、AVRはハーバード・アーキテクチャ(プログラムとデータそれぞれに分離されたメモリとバスを使用する構造)を採用しています。プログラム・メモリの命令は単一のパイプラインによって実行されます。一つの命令が実行されている間に、次の命令がプログラム・メモリから先読みされます。この設計により、すべての命令が1クロックで実行されます。プログラム・メモリは In-System Programming(ISP)により再プログラム可能なフラッシュ・メモリです。

 高速アクセス可能なレジスタ・ファイルには32個x8ビットの1クロック・アクセス可能な汎用レジスタがあり、それぞれのレジスタにはです。これにより、算術論理ユニット(ALU)が1クロックで処理を行うことが可能になります。典型的なALUの処理では、二つのオペランドがレジスタ・ファイルから出力され、演算が実行され、そして実行結果をレジスタ・ファイルに書き戻す、この一連の処理を1クロックで実行します。

 32個のレジスタのうち6個については、3つの16ビット間接アドレス・ポインタ・レジスタとして、データ領域のアドレス参照に使用することができ、効率的なアドレス計算が可能です。このうち一つのアドレス・ポインタは、プログラム・フラッシュメモリ上のルックアップ・テーブルのアドレス・ポインタとしても使用できます。これらの追加機能をもつレジスタは、16ビットX、Y、Zレジスタと呼ばれ、この節で後ほど詳しく説明します。

 ALUは、レジスタとレジスタ、レジスタと定数の算術演算および論理演算をサポートします。単一レジスタに対する演算処理もALU内で実行されます。算術処理の直後にステータス・レジスタが更新され、計算結果についての情報を反映します。

 プログラム・フローの制御機能は、全アドレス空間を直接指定する、条件、または無条件のジャンプ命令やコール命令により提供されます。ほぼすべてのAVR命令は単一の16ビットワードの形式になっており、プログラムメモリの各アドレスには、16ビットまたは32ビットの命令コードが含まれます。

 プログラム・フラッシュメモリ空間は二つの領域、ブートプログラム領域とアプリケーション・プログラム領域、に分割されています。どちらの領域にも個別に、書き込み保護および読み書き保護のLockビットがあります。アプリケーション・フラッシュメモリ領域に書き込みを行うSPM命令は、ブートプログラム領域上で実行する必要があります。

 割り込み、およびサブルーチン・コールの間、戻りアドレスを示すプログラム・カウンタ(PC)の値がスタック上に保持されます。スタックは実用性のため、汎用データSRAM領域上に割り当てられており、したがってスタックのサイズはSRAMのサイズと、その使用状況によってのみ制限されます。すべてのユーザー・プログラムでは、リセット処理中で(サブルーチンまたは割り込み処理が実行される前に)スタック・ポインタ(SP)を初期化する必要があります。スタック・ポインタ(SP)は、I/O空間上で読み書きアクセスが可能です。データSRAM領域は、AVRアーキテクチャでサポートされている、5つの異なるアドレッシング・モードで簡単にアクセス可能です。  AVRアーキテクチャのメモリ空間は、すべてリニアで標準的なメモリマップとなっています。

 柔軟性の高い割り込みモジュールには、I/Oアドレス空間上にある各割込みのコントロール・レジスタに加え、ステータス・レジスタ内にグローバル割込み許可ビットがあります。すべての割込みには、割込みベクトル・テーブル内に別々の割込みベクトルがあります。割込みは、それぞれの割込みベクトルの順序にしたがって優先順位が決まります。割込みベクトルのアドレスが低い位置にあるほど優先度が高くなります。

 I/Oメモリ空間には64のアドレスがあり、コントロール・レジスタ、SPI、そして入出力ポートという形でCPU周辺機能が含まれています。I/Oメモリは直接アクセスすることも、レジスタ・ファイルに続く0x20 - 0x5Fのデータ空間アドレスからもアクセスできます。さらに、ATmega48/88/168 には、拡張I/O領域がSRAM上の0x60 - 0xFFにあり、そこではST/STS/STD と LD/LDS/LDD 命令のみが使用可能です。

6.3 ALU – 算術論理演算ユニット

 高性能のAVR ALUは、32個すべての汎用レジスタと直接接続された状態で演算動作を行います。1クロック以内で、汎用レジスタ間またはレジスタと即値定数との間で算術演算が実行されます。ALUの演算動作は三つのカテゴリーに分類されます ー 算術演算、論理演算、そしてビット操作です。AVRアーキテクチャの実装のなかには、符号あり/符号なし乗算、および小数フォーマットをサポートする強力な乗算器を提供するものもあります。

詳細な説明については、「命令セット“Instruction Set”」の節を参照してください。

6.4 ステータス・レジスタ

 ステータス・レジスタには、最後に実行された算術命令の結果についての情報が格納されています。この情報を用いて、条件付き処理を行うためにプログラムの実行フローを切り換えることができます。 ステータス・レジスタは、命令セットのリファレンス中で示されているように、すべてのALU演算動作の結果によって更新されることにご注意ください。これにより多くの場合、専用の比較命令を用いる必要がなくなり、結果的により高速でサイズの小さいコードを生成することができます。

 割込み処理が始まる際のステータス・レジスタの値の退避、および、割込みから戻る際の値の復帰は、自動的には行われません。この操作はソフトウェアにより行う必要があります。

6.4.1 SREG – AVR ステータス・レジスタ

AVR ステータス・レジスタ – SREG – の定義は下記のとおりです:

ビット 7 6 5 4 3 2 1 0
0x3F(0x5F) I T H S V N Z C SREG
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
初期値 0 0 0 0 0 0 0 0

6.5 汎用レジスタ・ファイル

 レジスタ・ファイルは、AVR高機能RISC命令セット用に最適化設計されています。要求される実効速度と柔軟性を実現するため、レジスタ・ファイルでは次のような入力/出力手段がサポートされています:

 Figure 6-2に、CPU内の32個の汎用レジスタの構造を示します。

Figure 6-2. AVR CPU 汎用レジスタ

7 0 アドレス
R0 0x00
R1 0x01
R2 0x02
...
R13 0x0D
R14 0x0E
R15 0x0F
R16 0x10
R17 0x11
...
R26 0x1A Xレジスタ 下位バイト
R27 0x1B Xレジスタ 上位バイト
R28 0x1C Yレジスタ 下位バイト
R29 0x1D Yレジスタ 上位バイト
R30 0x1E Zレジスタ 下位バイト
R31 0x1F Zレジスタ 上位バイト

 レジスタ・ファイルを操作する命令のほとんどが、すべてのレジスタに直接アクセスでき、それらのほぼすべての命令が1クロック命令となっています。

 Figure 6-2にあるとおり、各々のレジスタはデータメモリとしてのアドレスも割り当てられており、ユーザー・データメモリ空間の最初の32アドレスに直接マッピングされています。実際の回路がSRAMとして実装されているわけではありませんが、このメモリ構造により、X、Y、Zポインタ・レジスタによりあらゆるレジスタを指すように設定でき、汎用レジスタへのアクセスに非常に高い柔軟性を提供しています。

6.5.1 Xレジスタ、Yレジスタ、Zレジスタ

 レジスタR26..R31 には、汎用レジスタとしてのほかに追加機能があります。これらのレジスタは、データメモリ空間への間接アドレッシングのための16ビットのアドレス・ポインタとなります。3つの間接アドレス・レジスタ、X、Y、Zの内容はFigure 6-3のように定義されています。

Figure 6-3. X、Y、Zレジスタ
15 XH XL 0
Xレジスタ 7 0 7 0
R27 (0x1B) R26 (0x1A)
15 YH YL 0
Yレジスタ 7 0 7 0
R29 (0x1D) R28 (0x1C)
15 ZH ZL 0
Zレジスタ 7 0 7 0
R31 (0x1F) R30 (0x1E)

 これらのアドレス・レジスタは異なるアドレッシング・モードとして、固定ディスプレースメント、自動インクリメント、自動デクリメントとしての機能を持っています。(詳細については、命令セット・リファレンスを参照してください)

6.6 スタック・ポインタ

 スタック領域は主に一時的なデータを保存したり、ローカル変数の格納場所としたり、割込みやサブルーチン処理の後に戻るアドレスを保存したりするのに使います。スタック・ポインタ・レジスタは常にスタック領域の先頭アドレスを指しています。スタック領域は、メモリアドレスの高位から低位へと、サイズが増大するように実装されていることにご注意ください。スタックへのPUSH命令により、スタック・ポインタの値が減少する、ということです。

 スタック・ポインタは、サブルーチンと割込み用のスタックとして使われるデータSRAMのスタック領域を指しています。データSRAMのスタック領域は、あらゆるサブルーチン・コールの実行、および割込みが許可されるより以前に定義されていなければなりません。スタック・ポインタは、0x0100よりも高いアドレス、できればRAMENDに初期設定してください。

スタック・ポインタは、データをスタックにPUSH命令により格納する際に1減少、POP命令によって復帰する際に1増加し、サブルーチンから戻るためのRET命令や、割込みから戻るためのRETI命令によりデータが復帰する際に2増加します。

 AVRのスタック・ポインタは、I/Oアドレス空間上の2個の8ビットレジスタとして実装されています。実際に使用されるビット数は、各デバイスの実装に依存します。AVRアーキテクチャのデバイスの一部には、データスペースが小さいため、必要なレジスタがSPLのみとなる場合もあることに注意してください。この場合、SPHレジスタは実装されていません。

6.6.1 SPH と SPL – スタック・ポインタHigh と スタック・ポインタLow レジスタ

ビット 7 6 5 4 3 2 1 0
0x3E(0x5E) SP15 SP14 SP13 SP12 SP11 SP10 SP9 SP8 SPH
0x3D(0x5D) SP7 SP6 SP5 SP4 SP3 SP2 SP1 SP0 SPL
7 6 5 4 3 2 1 0
Read/Write R/W R/W R/W R/W R/W R/W R/W R/W
R/W R/W R/W R/W R/W R/W R/W R/W
初期値 RAMEND RAMEND RAMEND RAMEND RAMEND RAMEND RAMEND RAMEND
RAMEND RAMEND RAMEND RAMEND RAMEND RAMEND RAMEND RAMEND

6.7 命令の実行タイミング

 この節では、命令実行時の一般的なアクセスタイミングについて述べます。AVR CPUは、CPUクロックclkCPU によって動作しており、そのクロックはチップのクロック源として選択されたものから直接生成されています。内部でクロックの分割は行っていません。

 Figure 6-4 に、命令フェッチと命令実行の並行動作がハーバード・アーキテクチャとレジスタ・ファイルへの高速アクセスによって実現されている様子を示します。これは、1MHzあたり最大1MIPSの性能を得るための基本的なパイプライン設計思想であり、これにより、コストあたりの速度、クロック周波数あたりの速度、そして単位消費電力あたりの速度、それぞれについて最良の結果を実現します。


Figure 6-4. 命令フェッチと命令実行の並行動作

 Figure 6-5 に、レジスタ・ファイルの内部タイミングの概念を示します。1クロック中で、2個のオペランドに対してALU演算動作が行われ、格納先レジスタに演算結果が書き戻されます。


Figure 6-5. ALU演算処理の1クロック動作

6.8 リセットと割込み処理

 AVRでは、多種多様の割込み要因を提供します。これらの割込み、およびリセット・ベクトルには、プログラム・メモリ空間に個別のプログラム・ベクトルがあります。すべての割込みには個別の許可ビットが割り当てられており、割込みを有効にするには各々のビットに論理値1を書き込んだ上で、ステータス・レジスタのグローバル割込み許可ビットをセットする必要があります。プログラム・カウンタの値によっては、BLB02あるいはBLB12ロック・ビットが設定されていると、割込みが自動的に無効になる場合があります。この機能により、ソフトウェアのセキュリティを高めています。詳細については、「メモリ・プログラミング」(p.284)を参照してください。

 プログラム・メモリ空間の最小アドレス位置には、初期状態では、リセット・ベクトルおよび割込みベクトルとして定義されています。ベクトルの全リストは「割込み」(p.55)にあります。このベクトルのリストは同時に各割込みの優先順位を決定しています。アドレスが低い位置にあるほど、優先レベルが高くなります。 RESETは最も高い優先度を持ち、つづいてINT0(外部割込み要求0)が高くなります。割込みベクトル領域は、MCUコントロール・レジスタ(MCUR)のIVSELビットの設定により、ブート・フラッシュ領域の最初の位置に移動することができます。より詳しい内容については、「割込み」(p.55)を参照してください。リセット・ベクトルは、BOOTRSTヒューズ・ビットを設定することによっても、ブート・フラッシュ領域の最初の位置に移動することができます。「ブート・ローダーのサポート – 読み書き並行自己プログラミング ATmega88/ATmega168」(p.268)を参照してください。

 割込みが発生すると、グローバル割込み許可ビットIがクリアされ、すべての割込みが禁止されます。ユーザー・ソフトウェアによって、論理値1をIビットに書き込むことで、割込みのネスティングを有効にでき、すべての有効な割込みを、現在処理している割込みルーチンを中断して実行させることができます。Iビットは、割込み復帰命令RETIが実行されると、自動的にセットされます。

 割込みには基本的に二種類のものがあります。 ひとつは割込みフラグをセットするイベントによってトリガーされるものです。このタイプの割込みでは、プログラム・カウンタを割込み処理ルーチンの実行のため、割込みベクトルのアドレスへと変更し、ハードウェアが該当する割込みフラグをクリアします。 割込みフラグは、論理値1を該当ビットに書き込むことによってもクリアできます。それぞれの割込みの許可ビットがクリアされている状態で、割込みの条件が満たされた場合、割込みフラグはセットされ、次に割込みが有効になるか、ソフトウェアによってクリアされるまで記憶されます。同様に、グローバル割込み許可ビットがクリアされている間に、一つ以上の割込み条件が満たされた場合、該当する割込みフラグがセットされ、グローバル割込み許可フラグがセットされるまで記憶され、優先度の順位にしたがって実行されます。

二つめのタイプは、割込み条件が満たされている間、トリガーされるものです。これらの割込みには、必ずしも割込みフラグが備わっているとは限りません。割込みが有効になる前に割込み条件が解消された場合、割込み動作は起動されません。

 AVRが割込み処理を終えるときは、待機中になっている割込みを処理する前に、必ずメイン・プログラムに戻り、一つ以上の命令が実行されます。

 ステータス・レジスタは、割込み処理開始時に自動的に退避されたり、割込み終了時に復帰されたりしない点に注意してください。これはソフトウェアで行う必要があります。

 CLI命令を使って割込みを禁止すると、割込みは即座に無効状態となります。CLI命令の実行後、たとえCLI命令と同時に発生したものであっても、いかなる割込みも実行されません。下記の例では、EEPROM書き込みシーケンスにおいて割込みを回避するための利用例を示しています。

アセンブリ言語での例

	in r16, SREG          ; SREGの値を退避
	cli                   ; 特定の期間において割込みを禁止する
	sbi EECR, EEMPE       ; EEPROM 書き込み開始
	sbi EECR, EEPE
	out SREG, r16         ; SREGの値(Iビットの状態)を復帰 
C言語での例

	char cSREG;
	cSREG = SREG;         /* SREGの値を退避 */
	_CLI();               /* 特定の期間において割込みを禁止する */
	EECR |= (1 << EEMPE); /* EEPROM 書き込み開始 */
	EECR |= (1 << EEPE);
	SREG = cSREG;         /* SREGの値(Iビットの状態)を復帰  */

 SEI命令を使って割込みを許可すると、待機中になっている割込みを処理する前に、下記の例のとおり、SEI命令直後の命令が必ず実行されます。

アセンブリ言語での例

	sei                    ; グローバル割込み許可フラグをセット
	sleep                  ; スリープ・モードに入り、割込みを待つ
	                       ; 注: 待機中の割込み処理が始まる前にスリープモードに入る
C言語での例

	__enable_interrupt();  /* グローバル割込み許可フラグをセット */
	__sleep();             /* スリープ・モードに入り、割込みを待つ */
	                       /* 注: 待機中の割込み処理が始まる前にスリープモードに入る */

6.8.1 割込み処理開始までの時間

 有効になっているAVRの割込みはすべて、割込み処理実行までの時間が最短で4サイクル必要です。4クロック経過後、実際の割込み処理ルーチンのためのプログラム・ベクトル・アドレスの実行を開始します。この4クロック期間で、プログラム・カウンタをスタックに退避します。割込みベクトルは通常割込み処理ルーチンへのジャンプになっており、このジャンプに3クロックを要します。もし、割込みが複数サイクルを必要とする命令の実行中に発生した場合は、その命令の実行が完了した後、割込み処理が開始します。MCUがスリープ・モードになっているときに割込みが発生した場合、割込み処理開始までの時間は、さらに4クロック増加します。この増加分はスリープ・モードからのスタートアップ時間によるものです。

 割込み処理ルーチンからの復帰には、4クロック必要です。この4クロック期間で、プログラム・カウンタ(2バイト)をスタックから復帰し、スタック・ポインタを2増加し、そしてSREGのIビットをセットします。 


目次に戻る