web-dev-qa-db-ja.com

マイクロプロセッサで使用されるスタックポインターとは何ですか?

マイクロプロセッサ試験の準備をしています。プログラムカウンターを使用して次の命令のアドレスを保持する場合、スタックポインターの使用とは何ですか?

47
KAR

スタックは、LIFO(最後に入力、最初に出力-スタックにプッシュする最後のエントリは、ポップしたときに戻る最初のエントリです))スタックを保持するために通常使用されるデータ構造です。フレーム(現在の関数に属するスタックのビット)。

これには次のものが含まれますが、これらに限定されません。

  • 返信先住所。
  • 戻り値の場所。
  • 渡されたパラメーター。
  • ローカル変数。

アイテムをスタックにプッシュし、それらをポップします。マイクロプロセッサでは、スタックはユーザーデータ(ローカル変数や渡されたパラメーターなど)CPUデータ(呼び出し時のリターンアドレスなど)の両方に使用できます。サブルーチン)。

スタックの実際の実装は、マイクロプロセッサのアーキテクチャに依存します。メモリ内で上下に移動でき、プッシュ/ポップ操作の前後に移動できます。

通常、スタックに影響する操作は次のとおりです。

  • サブルーチンの呼び出しと戻り。
  • 割り込み呼び出しと戻り。
  • エントリを明示的にプッシュおよびポップするコード。
  • SPレジスタの直接操作。

私の(架空の)アセンブリ言語の次のプログラムを検討してください。

Addr  Opcodes   Instructions    ; Comments
----  --------  --------------  ----------
                                ; 1: pc<-0000, sp<-8000
0000  01 00 07  load r0,7       ; 2: pc<-0003, r0<-7
0003  02 00     Push r0         ; 3: pc<-0005, sp<-7ffe, (sp:7ffe)<-0007
0005  03 00 00  call 000b       ; 4: pc<-000b, sp<-7ffc, (sp:7ffc)<-0008
0008  04 00     pop r0          ; 7: pc<-000a, r0<-(sp:7ffe[0007]), sp<-8000
000a  05        halt            ; 8: pc<-000a
000b  06 01 02  load r1,[sp+2]  ; 5: pc<-000e, r1<-(sp+2:7ffe[0007])
000e  07        ret             ; 6: pc<-(sp:7ffc[0008]), sp<-7ffe

次に、上記のコメントに示されている手順を説明しながら、実行を追跡しましょう。

  1. これは、プログラムカウンターがゼロで、スタックポインターが8000である開始条件です(これらの数値はすべて16進数です)。
  2. これは、レジスターr0に即値7をロードし、次のステップに移動するだけです(特に指定しない限り、デフォルトの動作は次のステップに移動することを理解していると想定します)。
  3. これは、スタックポインタを2減らすことでr0をスタックにプッシュし、レジスタの値をその場所に格納します。
  4. これはサブルーチンを呼び出します。プログラムカウンターであったwouldは、前のステップのr0と同様の方法でスタックにプッシュされ、プログラムカウンターはその値に設定されます新しい価値。これは、システムレベルの処理として実行されること以外は、ユーザーレベルのプッシュと同じです。
  5. これにより、スタックポインターから計算されたメモリ位置からr1がロードされます。関数にパラメーターを渡す方法を示しています。
  6. Returnステートメントは、スタックポインターが指す場所から値を抽出し、プログラムカウンターにロードして、同時にスタックポインターを調整します。これはシステムレベルのポップのようなものです(次の手順を参照)。
  7. スタックからr0をポップするには、スタックポインターが指す場所から値を抽出し、そのスタックポインターを上に調整します。
  8. 停止命令は、プログラムカウンターが存在する場所、つまり無限のループをそのまま残します。

うまくいけばその説明から、それが明らかになるでしょう。要するに、スタックはLIFOの方法で状態を保存するのに便利であり、これはほとんどのマイクロプロセッサがサブルーチン呼び出しを行う方法に理想的です。

[〜#〜] sparc [〜#〜] でない限り、もちろんその場合はスタックに循環バッファを使用します:-)

更新:上記の例で値をプッシュおよびポップする際に実行される手順を明確にするために(明示的または呼び出し/戻りによって)、次の例を参照してください。

LOAD R0,7
Push R0
                     Adjust sp       Store val
sp-> +--------+      +--------+      +--------+
     |  xxxx  |  sp->|  xxxx  |  sp->|  0007  |
     |        |      |        |      |        |
     |        |      |        |      |        |
     |        |      |        |      |        |
     +--------+      +--------+      +--------+

POP R0
                     Get value       Adjust sp
     +--------+      +--------+  sp->+--------+
sp-> |  0007  |  sp->|  0007  |      |  0007  |
     |        |      |        |      |        |
     |        |      |        |      |        |
     |        |      |        |      |        |
     +--------+      +--------+      +--------+
91
paxdiablo

スタックポインターには、スタックにプッシュされた最新のエントリのアドレスが格納されます。

値をスタックにプッシュするには、スタックポインターをインクリメントして次の物理メモリアドレスをポイントし、新しい値をメモリ内のそのアドレスにコピーします。

スタックから値をポップするには、スタックポインターのアドレスから値をコピーし、スタックポインターをデクリメントして、スタック内の次の使用可能な項目を指します。

ハードウェアスタックの最も一般的な使用法は、サブルーチン呼び出しの戻りアドレスを格納することです。サブルーチンの実行が終了すると、リターンアドレスがスタックの最上部からポップされ、プログラムカウンターレジスタに配置されます。これにより、プロセッサはサブルーチンの呼び出しに続く次の命令で実行を再開します。

http://en.wikipedia.org/wiki/Stack_%28data_structure%29#Hardware_stacks

11
Robert Harvey

[試験の準備]の準備がさらに完了しました;-)

スタックポインタは、スタックで次に使用可能なスポットのアドレスを保持するレジスタです。

スタックは、スタックを格納するために予約されているメモリ内の領域です。つまり、LIFO(Last In First Out)タイプのコンテナです。ローカル変数と戻りアドレスを格納し、典型的なプログラムでの関数呼び出しのネストの簡単な管理。

スタック管理の基本的な説明については、こちらをご覧ください ウィキペディアの記事 .

6
mjv

8085の場合:スタックポインターは、スタックの最上位のアドレスを保持するマイクロプロセッサーの特殊な16ビットレジスタです。

コンピューターのスタックポインターレジスターは、割り込みハンドラーよりも低い特権レベルで実行されているプログラムによって、汎用で使用できるようになります。スタック操作を除くこのようなプログラムの命令セットは、オペランドなどのスタックポインタ以外のデータをスタックポインタレジスタに格納します。割り込みで実行を割り込みハンドラーに切り替えると、現在実行中のプログラムのリターンアドレスデータが、割り込みハンドラーの特権レベルでスタックにプッシュされます。したがって、スタックポインターレジスタに他のデータを格納しても、スタックが破損することはありません。また、これらの命令は、現在のスタックポインターを超えてスタックセグメントのスクラッチ部分にデータを格納できます。

詳細についてはこちらをお読みください。

スタックポインタレジスタの汎用使用

3
rahul

スタックは、一時データを保持するためのメモリ領域です。スタックは、プロシージャのリターンアドレスを保持するためにCALL命令によって使用されます。リターンRET命令は、スタックからこの値を取得し、そのオフセットに戻ります。 INT命令が割り込みを呼び出すときにも同じことが起こります。フラグレジスタ、コードセグメント、およびオフセットをスタックに格納します。 IRET命令は、割り込み呼び出しから戻るために使用されます。

スタックは、後入れ先出し(LIFO)メモリです。データはプッシュ命令でスタックに配置され、POP命令で削除されます。スタックメモリは、スタックポインター(SP)およびスタックセグメント(SS)レジスタの2つのレジスタによって維持されます。データのワードがスタックにプッシュされると、高位8ビットバイトがロケーションSP-1に配置され、低位8ビットバイトがロケーションSP-2に配置されます。 SPは2ずつ減分されます。SPは、SS x 10H)レジスタに追加され、物理スタックメモリアドレスを形成します。逆のシーケンスが発生します。スタックからデータがPOPPEDされるとき。ワードからデータがスタックからPOPPEDされるとき、上位8ビットバイトはロケーションSP-1で取得され、下位8ビットバイトはロケーションSP-2で取得されます。 SPは2ずつ増加します。

2

もっと深く理解したい場合は、 Patterson and Hennessy をイントロとして、 Hennessy and Patterson を中級から上級のテキストとしてお勧めします。高価ですが、本当にパレイルではありません。修士号を取得し、チップ、システム、およびシステムソフトウェアの一部を設計する従業員になったときに、どちらかまたは両方が利用できるようにしたいだけです(しかし、残念ながら、それは遠い昔でした;-)。スタックポインターは非常に重要です(マイクロプロセッサと他の種類のCPUの違いは、このコンテキストで非常に意味があります...または、そのほかのあらゆるコンテキストで、過去数十年で...!-)私は何も疑っていませんが、徹底的なゼロからのリフレッシャーが助けになります!-)

1
Alex Martelli

スタックポインターは、スタックの先頭へのアドレスを保持します。スタックを使用すると、関数はスタックに格納されている引数を相互に渡し、作成することができます スコープ付き 変数。このコンテキストのスコープとは、スタックフレームがなくなったとき、および/または関数が戻ったときに、変数がスタックからポップされることを意味します。スタックがなければ、すべてに明示的なメモリアドレスを使用する必要があります。これにより、アーキテクチャ用の高レベルプログラミング言語を設計することが不可能になります(または、少なくとも非常に困難になります)。また、通常、各CPUモードには独自のバンクスタックポインターがあります。したがって、例外が発生した場合(たとえば、割り込み)、例外ハンドラルーチンは、ユーザープロセスを破損することなく独自のスタックを使用できます。

1
Mads Elvheim

一部のCPUには、スタック専用のレジスタセットがあります。呼び出し命令が実行されると、1つのレジスタにプログラムカウンタがロードされると同時に、2番目のレジスタに1番目の内容がロードされ、3番目のレジスタに2番目がロードされ、4番目に3番目がロードされます。 。リターン命令が実行されると、プログラムカウンタは最初のスタックレジスタの内容でラッチされ、同時にそのレジスタが2番目のレジスタからラッチされます。そのようなハードウェアスタックはかなり小さい傾向があることに注意してください(たとえば、多くの小さなPICシリーズマイクロは、2レベルのスタックを持っています)。

ハードウェアスタックにはいくつかの利点がありますが(プッシュとポップは呼び出し/戻りに時間を追加しません)、2つのソースでロードできるレジスタがあるとコストがかかります。スタックが非常に大きくなった場合、プッシュプルレジスタをアドレス可能なメモリで置き換える方が安価です。これに小さな専用メモリを使用した場合でも、32個のアドレス指定可能なレジスタとインクリメント/デクリメントロジックを備えた5ビットポインタレジスタを使用する方が、それぞれ2つの入力を持つ32個のレジスタを使用するよりも安価です。アプリケーションがCPUに簡単に収まるよりも多くのスタックを必要とする可能性がある場合、メインRAMからスタックデータを格納/フェッチするロジックと共にスタックポインターを使用することができます。

0
supercat

スタックポインターは、スタックの先頭のアドレスを格納する小さなレジスタです。スタックの先頭のアドレスを指す目的で使用されます。

0
rashedcs