エンディアン、メモリフォーマット、データタイプ、例外/割り込み

エンディアン

Cortex-M3の製品を担当し始めてしばらくして、あるお客さんから問い合わせがありました。「Cortex-M3はリトルインディアンですか、ビッグインディアンですか?」この問い合わせは、メールで来たので、最初Typoかと思いましたが、2箇所も間違わないだろうし、キーボード上「i」と「e」は離れていますので、打ち間違うことは無いだろうと思いました。確かに音は似ていますが...。「Cortex-M3は、(デフォルト)リトルエンディアンです」と、丁寧にお答えしました。作り話のようですが、本当の話です。エンディアンの話は、用語解説を参照していただくとして、データフォーマットについて説明いたします。

Cortex-M3のデータフォーマット

「メモリマップ(第19回参照)」の章にて詳しく説明いたしますが、Cortex-M3のメモリは、固定アドレスで、リニア配列されています。Cortex-M3は、そのリニアに配列されているメモリを、0から昇順に番号が付けられたバイトの集合として参照します。

Cortex-M3のエンディアンは、データとコードで異なります。

  • ●データ : リトルエンディアン形式またはビッグエンディアン形式でアクセス可能。
  • ●コード : 常時リトルエンディアン

Cortex-M3に限らず、ARMプロセッサは、リトルエンディアンがデフォルトのメモリフォーマットです。従いまして、ワード内の最も下のアドレスを持つバイトは、そのワードの最下位のバイトになります。ワード内の最も上のアドレスを持つバイトは、そのワードの最上位のバイトになります。

ビッグエンディアン形式では、ワード内の最も下のアドレスを持つバイトは、そのワードの最上位のバイトになります。ワード内の最も上のアドレスを持つバイトは、そのワードの最上位のバイトになります。

下図に、リトルエンディアンのメモリフォーマットとビッグエンディアンのメモリフォーマットの例を示します。

Cortex-M3には、エンディアンを設定するピンBIGEND (注意:マイコンのピンではありません。論理モジュールの外部との信号線の名前です)があります。これを使用するとリトルエンディアン、またはビッグエンディアン形式のいずれかを選択することができます。BIGENDピンの状態は、リセット時にロジックに取り込まれ反映されます。従って、リセット後にエンディアンを変更しようとしてもできません。

  • ( * )システム制御空間(SCS)(用語解説参照)へのアクセスは常時リトルエンディアンになっています。BIGENDの機能が有効かどうかは、Cortex-M3を搭載したマイコンによって異なります。お使いになっているマイコンの仕様を確認してください。
図2

メモリフォーマット

マイコンのビット数

読者の皆様に、ちょっと基本的なことを質問させていただきます。32ビットマイコンって何が32ビットでしょうか?CPUが扱うデータが32ビットだと32ビットマイコンですか?では、CPUは32ビット演算ができますが、メモリ(ROMやRAM)とつながっているバスが16ビットしかないマイコンの場合は、16ビットマイコンでしょうか、32ビットマイコンでしょうか?演算は32ビットでもデータ処理が16ビットでしか処理できなければ16ビットマイコンの処理能力しかないことになりますが、CPUが32ビットだったら、32ビットマイコンと呼んでいいのでしょうか?

一般的には、CPUが処理をするデータのビット数で何ビットマイコンという呼び方をしています。ただし、厳密な規定はありません。現実に、CPUは32ビットでもメモリバスが16ビットで、32ビットマイコンと呼んでいるマイコンはあります。

前述しましたが、CISCマイコンでは命令のコード長が決まっていませんので、8ビットや16ビットマイコンでも、24ビット命令長のマイコンがあってもいいわけです。一方、RISCはパイプライン処理に乗せるために、命令長は一定です。したがって、マイコンのビット数の呼び名に左右されずに、実際に扱うデータ長や命令長をちゃんとチェックしなければ、そのマイコンの処理能力はわからないと言うことです。

データタイプ

Cortex-M3のデータタイプ

Cortex-M3の場合は、命令長はThumb-2命令セットですので、32ビットと16ビットが混在します。データ長は32ビット、16ビット、8ビットを取り扱います。各データ長は以下のように呼ばれています。

  • ●32ビットデータ : ワード
  • ●16ビットデータ : ハーフワード
  • ●8ビットデータ : バイト

「アンアラインド・データ・アクセス(第8回参照)」の章で述べましたが、Cortex-M3は32ビットマイコンですから、32ビット毎にアライメントされています。すなわちCPUがアクセスするデータの単位は32ビットです。8ビットや16ビットデータをメモリに格納する際、アンアラインド・データ・アクセスを使わなければ、32ビットのアラインメント(境界線)をまたいでデータを格納することはしません。

ユーザー(と言っても、実際はコンパイラのメモリシステム)は、すべてのデータ長を扱うときに注意を払う必要があります。特に、ワード、ハーフワード、バイトのデータを隣接して扱うときに、隣のデータ長の異なるデータを破損しないように注意しなければなりません。

図1

例外/割り込み処理

例外処理とは?

例外処理は、マイコンがメインルーチンを実行しているときに、突如として別の仕事(タスク)を要求される処理のことを言います。多くの場合、割り込みのことを指しますが、リセットも突如としてメインルーチンを停止させて初期化されますので、立派な例外処理に入ります。また、Cortex-M3では、メインルーチンを実行していときに異常な事態が発生し、メインルーチンを実行できなくなった時に、フォールトという処理を行います。これも突如として別の仕事を行うことになるので、例外処理の一つと言えます。例外処理はMCUから見ると、予期せぬタイミングで発生するので、遷移タイミングは、結構難しい処理になります。いかに速く、効率良く例外処理を実行し、メインルーチンに戻ってくるかは、各マイコンの設計のポイントとなります。

例外処理に関わる処理を全部ソフトウェアで行うとすると、ハードウェアの負担が小さくなるので、コストを抑えることが出来ますが、処理時間がかかって遅くなります。その処理のプログラムを書き込んでおくFlashも、その分多く必要です。(マイコンは安いが、ユーザーの手間とFlash容量が増えます)ハードウェアにすべて任せると、ソフトウェアの負担が減りFlashの容量も少なくて済みますが、論理規模が大きくなり、コスト的にデメリットとなります。(マイコンは高くなるが、ユーザーの手間とFlash容量は減ります)どこまでをソフトウェア、どこまでをハードウェアに任せるかは、マイコンのコストを含めた仕様検討の段階で重要なポイントになります。ハードウェアとソフトウェアの分担をどのくらいにするかは各マイコン設計者の悩みどころです。

現実問題として、例外処理全部をソフトウェアで対応することはできません。例外が発生したときの優先順位の管理や、ベクタへ飛んでいく処理等々にはハードウェアが必要です。 そのため、通常のマイコンでは多かれ少なかれ、割り込みを処理するハードウェアが組み込まれています。通常、必要最低限の割り込み用ハードウェアしか搭載していないマイコンはブロック図に記載されていない場合が多いです(例:ARM7、下図参照)。高度な割り込みを処理するハードウェアを搭載している場合は、そのハードウェアもセールスポイントになりますので、「割り込みコントローラー搭載」等の記載があります。

この割り込みコントローラがどこまでの仕事を担うかは各マイコンで様々です。例えば、割り込みベクタには、ジャンプ命令(または例外専用命令)を書いておいて、例外が発生すると、そのベクタの命令をCPUに実行させる方式があります。また、ベクタにはジャンプ先アドレスを書いて、ハードウェアが自動的にジャンプさせる方式(Cortex-M3の場合)等々です。例外処理の細かい仕様は、各マイコンで異なった方式が取られています。

ネスト型ベクタ割り込みコントローラ(NVIC)

下図に従来のARM7コアとCortex-M3コアのブロックを示します。Cortex-M3の赤丸で囲った部分がNVICになります。ARM7のコアには、このような割り込みを 制御する高機能なハードウェアは搭載されていません。「Cortex-M3プロセッサの概要(第3回参照)」の章で述べたように、Cortex-M3には、NVICが搭載されていて、このハードウェアが密接にプロセッサコアに関係付けられていますので、割り込みなどの例外処理を効率良く処理できるようになっています。

図4

ARM7の例外処理の状態遷移図を下図の(a)に、Cortex-M3の場合を(b)に示します。ARM7の場合は、ソフトウェアが介在する部分があるので、「ベクタテーブル」という状態がCortex-M3の場合よりも多くなっています。

ARM7の状態遷移

ARM7では、割り込みが起こると、

  • ①ベクタテーブルへジャンプ
    これはハードウェアが行ってくれますが、マイコンのコンテキストをスタックに保存するのは、ソフトウェアが行います。すなわち、
  • ②レジスタの退避
  • ③ハンドラ処理へジャンプ
    これらの処理はソフトウェアが行います。その後ハンドラモードにおいて例外処理のコードが実行されます。
  • ④例外処理
    例外処理が終ったら、メインルーチンに戻る処理に入ります。
  • ⑤レジスタの復元
    その後
  • ⑥復帰命令の実行
    そして、ハードウェアが再び働き出して、
  • ⑦戻りアドレスへジャンプ

①から⑦までの一連の動作で、②~⑥はソフトウェアで行わなくてはなりません。

Cortex-M3の状態遷移

Cortex-M3の場合は、割り込みが発生すると、

  • ①汎用レジスタを自動退避
  • ②ベクタテーブルへジャンプ
  • ③ハンドラ処理へジャンプ
    これらの一連の動作はハードウェアが行ってくれるので、ソフトウェアはハンドラモードに入るまで、何もしなくても良いのです。
  • ④例外処理
    例外処理のコードの実行が完了したら、メインプログラムに戻ります。
  • ⑤復帰命令の実行
    すると、再びハードウェアが
  • ⑥汎用レジスタ復元
  • ⑦戻りアドレスへジャンプ

これらの処理を行ってくれるので、ソフトウェアでPUSH、POP等の処理をする必要はありません。①から⑦までの一連の動作で、④と⑤だけをソフトウェアで行えば、他の工程は、すべてハードウェアが行ってくれるので、ユーザーは非常に楽になります。また、ハードウェアを使うと、各工程を効率良く実行してくれますので、状態遷移の際のオーバーヘッドが少なくなるというメリットも生まれます。

図5

例外処理の言語

ARM7では割り込み処理に移る際と戻る際には、ソフトウェアが必須でした。この点はユーザーにとっては非常に不便です。さらに、その処理を行う言語は、アセンブラ言語を使用しなければなりませんでした。

ARM7では、下図に示しますように、メインルーチンはC言語で記述できましたが、例外処理のコードはアセンブラ言語で記述する必要がありました。そして、命令セットもARM命令とThumb命令の2種類あるので、リンカはこれらの4種類の言語(命令セット)をリンクしなければなりませんでした。しかし、Cortex-M3ではNVICを搭載することにより、ARM7がアセンブリ言語のソフトウェアで行っていた処理をハンドラが処理してくれるようになり、C言語だけで記述できる割り込み処理を実現しました。さらに命令セットもThumb-2命令に統一されましたので、下図の右側に示したように、Cortex-M3の場合のリンカの処理は左側のARM7の場合に比べて、非常に簡単になったのがわかります。さらに、ハードウェアのハンドラが処理することにより、オーバヘッドの短い割り込み処理を実現できるようになりました。

図6

NVICの主な機能

以下にNVICの特徴をリストアップします。

  • ①外部割り込みは、0~239の間で設定が可能です。ここで言う外部割り込みは、マイコンの外部割り込みではなく、Cortex-M3から見た外部になります。従って、マイコンの周辺機能(タイマ、通信モジュール、ADC等のアナログモジュール等)を指します。
  • ②割り込みの優先度は、8ビットレジスタを2つのグループに分けることによって設定を行います。実際の製品では、8ビットレジスタをフルに使用する必要は無く、マイコンメーカーによって何ビット使用するか選択が可能です。(3~8ビットの間で設定が可能)
  • ③割り込みの優先度はダイナミックに変更(再設定)が可能です。
  • ④Cortex-M3のマニュアル等の中で、割り込みの説明の時に、テールチェイン(Tail-Chaining)と後着(Late Arrival)という言葉を目にすると思います。詳細は後述しますが、これらはARM特有の言葉(概念)です。ARM特有の概念を取り入れることによって、連続する2つ以上の割り込み間の遷移において、コンテキストの保存と復元の際に、非常に短いオーバヘッドの割り込み処理を実現しました。
  • ⑤割り込みが発生した時の、コンテキストの保存と割り込みからの復帰の時の復元はハンドラ(ハードウェア)が行いますので、命令のオーバーヘッドは発生しません。
  • ⑥LDM(ロード)/ STM(ストア)、割り算のような実行時間の長い命令は中断可能となっており、割り込みが発生したら、一旦中断して、割り込み処理を優先して処理し、その処理が終了した後、再実行するという機能を持っています。