次のコードは、割り込みベクタテーブルを定義するu-bootの最初の部分です。私の質問は、すべての行がどのように使用されるかです。開始点であり、実装する最初の命令である最初の2行を理解しました:リセット。以下でリセットを定義します。しかし、これらの手順はいつ使用しますか? System.mapによると、すべての命令には固定アドレスがあるため、_fiqは0x0000001Cにあります。fiqを実行する場合は、このアドレスをpcにコピーしてから、実行します。しかし、どのようにしてこの命令にジャンプできますか:ldr pc、_fiq?それはハードウェアまたはソフトウェアによって実現されますか?私が自分自身を正しく理解させてくれることを願っています。
>.globl _start
>_start:b reset
> ldr pc, _undefined_instruction
> ldr pc, _software_interrupt
> ldr pc, _prefetch_abort
> ldr pc, _data_abort
> ldr pc, _not_used
> ldr pc, _irq
> ldr pc, _fiq
>_undefined_instruction: .Word undefined_instruction
>_software_interrupt: .Word software_interrupt
>_prefetch_abort: .Word prefetch_abort
>_data_abort: .Word data_abort
>_not_used: .Word not_used
>_irq: .Word irq
>_fiq: .Word fiq
リセットを理解していれば、それらすべてを理解できます。
プロセッサがリセットされると、ハードウェアはPCを0x0000に設定し、0x0000で命令をフェッチすることによって実行を開始します。未定義の命令が実行されるか、実行しようとすると、ハードウェアはpcを0x0004に設定して応答し、0x0004から命令の実行を開始します。 irq割り込み、ハードウェアは実行中の命令を終了し、アドレス0x0018で命令の実行を開始します。等々。
00000000 <_start>:
0: ea00000d b 3c <reset>
4: e59ff014 ldr pc, [pc, #20] ; 20 <_undefined_instruction>
8: e59ff014 ldr pc, [pc, #20] ; 24 <_software_interrupt>
c: e59ff014 ldr pc, [pc, #20] ; 28 <_prefetch_abort>
10: e59ff014 ldr pc, [pc, #20] ; 2c <_data_abort>
14: e59ff014 ldr pc, [pc, #20] ; 30 <_not_used>
18: e59ff014 ldr pc, [pc, #20] ; 34 <_irq>
1c: e59ff014 ldr pc, [pc, #20] ; 38 <_fiq>
00000020 <_undefined_instruction>:
20: 00000000 andeq r0, r0, r0
00000024 <_software_interrupt>:
24: 00000000 andeq r0, r0, r0
00000028 <_prefetch_abort>:
28: 00000000 andeq r0, r0, r0
0000002c <_data_abort>:
2c: 00000000 andeq r0, r0, r0
00000030 <_not_used>:
30: 00000000 andeq r0, r0, r0
00000034 <_irq>:
34: 00000000 andeq r0, r0, r0
00000038 <_fiq>:
38: 00000000 andeq r0, r0, r0
もちろん、PCを変更し、これらのアドレスから実行を開始することに加えて。ハードウェアはマシンの状態を保存し、必要に応じてプロセッサモードを切り替えてから、ベクタテーブルの新しいアドレスで実行を開始します。
プログラマーとしての私たちの仕事は、これらの各命令に対して実行したい命令が正しいアドレスにあるようにバイナリーを構築することです。ハードウェアは、場所ごとに1つのワードと1つの命令を提供します。これらの例外が発生することを予期しない場合は、アドレス0にブランチを作成する必要はありません。たとえば、プログラムを起動するだけで、これらのアドレスのメモリに魔法はありません。これらの例外が予想される場合は、1つのワードであり、後続の例外の邪魔にならないようにジャンプできる命令に対して2つの選択肢があります。 1つはブランチで、もう1つはロードPCです。それぞれに長所と短所があります。
ハードウェアが例外を取得すると、プログラムカウンタ(PC)が関連する例外ベクトルのアドレスに自動的に設定され、プロセッサはそのアドレスから命令の実行を開始します。プロセッサのリセットが解除されると、PCは自動的にbase+0
に設定されます。未定義の命令は、PCをbase+4
などに設定します。ベクトルテーブル(base
)のベースアドレスは、プロセッサと構成に応じて、0x00000000、0xFFFF0000、またはVBAR
のいずれかになります。これにより、ベクターテーブルを配置する場所の柔軟性が制限されることに注意してください。正しい値を取得するには、使用しているデバイスのリファレンスマニュアルと併せてARMドキュメントを参照する必要があります。使用する。
テーブルのレイアウト(例外ごとに4バイト)では、ベクターから実際の例外ハンドラーにすぐに分岐する必要があります。 LDR PC, label
アプローチの理由は2つあります。PC相対ブランチはB
を使用して(24 << 2)ビット(+/- 32MB)に制限されるため、メモリ内のコードのレイアウトが多少制約されます。絶対アドレスをロードすることにより、ハンドラーはメモリー内のどこにでも配置できます。次に、分岐命令をアセンブルしてホットパッチする必要がなく、その場所に別のアドレスを書き込むだけで、実行時に例外ハンドラを非常に簡単に変更できます。
ただし、このように再マップ可能なリセットベクトルを使用する価値はほとんどありません。そのため、残りのベクトルをスキップして実際のエントリポイントコードに移動する単純なブランチとして実装されていることがよくあります。