2009/10/23コンピュータの命令アーキテクチャの基本となるのは命令セットです。第2、3、4回と何度か命令セットの話は出ていますが、第5回はもうすこし具体的にコンピュータの命令を見ていきます。System/360から登場し、最初は命令セットによって定義されるコンピュータの機能や構造を意味していましたが、現在は内部構造もアーキテクチャと呼ぶので、従来の命令の構成は命令セットアーキテクチャと(ISA)と呼ぶことが多いです。コンピュータの命令(機械語命令)コンピュータの機械語命令は普段プログラミングに用いる高級言語とは異なり、基本的には制御構造などはない。命令を表現するコードと、命令の対象を指定するコードから成り立つ。命令+アドレシングオペコード+オペランドコンピュータの命令の対象は、メモリやI/Oである。メモリは実際にはプロセッサ内部のレジスタ、メインメモリがある。I/Oはメモリ空間に位置づけられ、メモリと同じようにアドレシングできるものと、I/O空間は別に用意され、I/O専用命令によって処理される場合がある。機械語命令は数値にコーディングされたものなので、人間にとって簡単に理解できるものではない。実行の効率を考え作られたものである。アセンブリ言語は命令をわかりやすく表現した記述方式で、アセンブラによって機械語に変換する。高級言語とは異なり、機械語命令と1対1で対応している。命令アーキテクチャが異なればアセンブリ言語も異なる。移動命令(ロード命令、ストア命令)演算命令テスト命令(条件チェック)分岐命令サブルーチン・コール命令スーパバイザ・コール命令コンテクスト・スイッチ命令その他(排他制御命令など)古い時代のCPUは単純に計算制御のための命令だけを備えていましたが、現在のCPUはリアルタイム制御をしたり、複数の仕事を同時こなすことを考慮し、OSの並行処理のサポートをする命令が用意されています。移動命令メモリからレジスタへの移動(ロード命令)、レジスタからメモリへの移動(ストア命令)、メモリからメモリへの移動、レジスタからレジスタへの命令などが考えられます。レジスタはメモリよりも遥かに高速にアクセスできます。初期の8bitCPUでは乗算、除算などはありません。乗算や除算はシフト命令を利用して、ソフト的に実現するのが一般的でした。浮動小数点数の演算も別扱いです。演算ユニットやレジスタも浮動小数点数は別になっています。演算命令は、レジスタ-メモリ間で実行できるものと、レジスタ間のみ許される方式があります。レジスタ-メモリ間で演算できるものは、移動命令を演算命令が含んでいると考えられます。テスト命令テスト命令は値を比較する命令です。この命令は基本的には演算命令です。演算結果を残さない演算命令と考えられます。機能はステータスレジスタのフラグの状況に従って、プログラムカウンタの内容を変更することです。これによって条件による分岐(if文やswitch文の機能)を実現します。分岐命令にもアドレシングはあり、絶対アドレスに対する分岐、相対アドレス分岐、間接アドレス分岐などが考えられます。サブルーチン・コール命令サブルーチン・コール命令は基本的には分岐命令なのですが、戻り番地保存した上で分岐する必要があります。普通はスタック上に戻り番地を積んで分岐します。戻る場合は逆にスタックの値をポップして、その番地に戻ります。サブルーチン・コール命令には引数を渡す機能や戻り値を受け取るための仕組みをもった命令もあります。このような命令が用意されていると、関数やメソッド呼び出しは効率よく行えることになります。スーパーバイザ・コール命令オペレーティング・システムは一般に、ユーザが利用するユーザモードと、システムのリソースを操作するスーパーバイザモードをもっています。システムに操作を依頼する場合には、スーパーバイザ・コール命令とかトラップ命令を用います。これらの命令は現在のレジスタの値をすべて退避し、決められた番地に分岐する命令です。分岐先はシステムが決めており指定することはできません。同じような動作を行う場合に割り込みがあります。外部から割り込み信号が入った場合、CPUはすべてのレジスタをメモリ上のスタックなどに退避し、割り込みアドレスに分岐します。スーパーバイザ・コール命令はソフトウエア割り込みと呼ばれたりもします。この命令が、ユーザモードからスーパーバイザ・モードを移行する唯一の命令です。コンテクスト・スイッチ命令マルチタスク処理で、複数のプロセスを扱うために必要な処理(コンテクスト・スイッチ)をサポートする命令です。この命令はスーパーバイザ・モードで利用されます。割り込みやスーパーバイザ・コールがきっかけとなってプロセスの状態がスイッチされます。この処理を効率よく行うための命令です。命令の方式アキュムレータ・アーキテクチャ汎用レジスタ・アーキテクチャスタック・アーキテクチャアキュームレータ・アーキテクチャアキュムレータを中心において、アキュムレータを対象としてメモリ(主記憶)との間で演算をする命令によって構成される。EDSACやIBM701など初期のコンピュータの多くはこの方式。Intel8080などの初期の8bitマイクロプロセッサ、16bitの8086もこの方式である。メモリのアドレスを指定するレジスタ(インデックス・レジスタ)等は専用のレジスタを用い、専用の命令によって操作する(専用レジスタ・アーキテクチャ)。レジスタが専用化されているので、命令のサイズは小さい。8086専用レジスタの種類プログラム・カウンタステータス・レジスタスタック・ポインタフレーム・ポインタインデックス・レジスタセグメント・レジスタプログラム・カウンタ次に実行する命令のアドレスを保持するレジスタ。プログラム・カウンタを変更すれば実行アドレスを変更でき、プログラム・カウンタに対する相対命令は、プログラムの位置を自由に変更可能なプログラムの記述ができる。ステータス・レジスタ演算によって変化する状態を表現するビットの集まり。条件分岐命令はこの値によってジャンプ先が変わる。0による割り算、演算結果の符号、結果が0かどうか、といったビットが用意されている。PSW(プロセッサ・ステータス・ワード)とか、CC(コンディション・コード)レジスタと呼ばれることもある。スタック・ポインタ多くのプロセッサでは、サブルーチン呼び出しの制御のための命令をもっている。サブルーチン呼び出しでは、現在のプログラムカウンタやプロセッサなどの状態をメモリ上のスタックに積んで、サブルーチンにジャンプする。逆に戻りでは、それらの値を復帰することで、呼出し元に戻って制御を続ける。サブルーチンではスタック上に必要な計算データを置くことによって、入れ子の呼び出しや再帰呼び出しも問題なく処理できる。ローカル変数はスタック上に確保することにより、効率よく記憶管理することができる。汎用レジスタを多く用意する代わりに、スタックをレジスタ代わりに使えるような命令を用意するスタック・アーキテクチャと呼ばれる方式もある。フレーム・ポインタ関数やメソッドの呼び出し管理にスタックには、基本的な戻り番地以外に、ローカル変数やレジスタの退避情報などが格納される。これをコールフレームと呼ぶ。コールフレームの末尾はスタックポインタが管理しているが、先頭にあたる部分を保持するのがフレームポインタである。スタックポインタはローカル変数の追加等で位置が動くが、フレームポインタからは確実に戻り番地やレジスタの退避情報を参照できるため、安全に呼び出し元に復帰することができる。インデックス・レジスタ間接アドレッシングで利用されるレジスタである。配列などの連続データのアクセスに利用される。汎用レジスタ・アーキテクチャでは汎用レジスタがこの目的に利用できるが、専用レジスタ・アーキテクチャではアドレス操作専用のレジスタが用意されている場合が多い。MC68000シリーズは汎用レジスタ・アーキテクチャではあるが、データ・レジスタとアドレス・レジスタが別に存在する。これはプロセッサの設計を簡単にするためである。80286等で、64KBを超えたメモリアクセスのために導入されているレジスタ。8086ではセグメント・レジスタの値は4ビットシフトされ、アドレスデータに加算されて用いられる。8086は16bitプロセッサだが、アドレスは20bit。20bitのレジスタはないため、直接アクセスできる空間は64KBに限定される。コード・セグメント、データ・セグメントという具合に目的ごとにメモリ空間を分割して利用する形式。汎用レジスタ・アーキテクチャ演算に利用できるレジスタが複数あるアーキテクチャ。8本以上あるレジスタをさまざなな目的すべてに利用することができるので、柔軟なプログラミングが可能。アドレス修飾を行うインデックス・レジスタ、スタック・ポインタ、プログラム・カウンタなど専用機能をもつものも同じ命令で操作できる。命令は整理され、柔軟な処理が可能。汎用レジスタ・アーキテクチャにはレジスタとメモリの間の演算を基本とするレジスタ-メモリ方式とレジスタ間の演算を基本とするレジスタ-レジスタ方式がある。レジスタ-レジスタ方式は演算を行うためには必ずメモリからデータをレジスタにロードする必要があり、演算後はレジスタの値をメモリにストアする命令を実行する必要がある。Iteniumスタック・アーキテクチャメモリ上のスタックを汎用レジスタように扱う方式。スタック・ポインタに対する(あるいはフレーム・ポインタ)に対する相対アドレッシングを容易に利用できるような命令セットになっている。物理的なプロセッサも古くはバロースのB5000アーキテクチャ、HPのHP3000などがある。マイクロプロセッサでは、Motorolaの8bitプロセッサMC6809はスタックマシンを意識したアーキテクチャである。物理的なプロセッサではく、仮想マシンにはスタック・アーキテクチャは多く存在する。スタック・アーキテクチャは汎用レジスタ・アーキテクチャと比較してレジスタをアドシングする必要がないため、コードをたいへん小さくすることが可能である。演算はスタックの上部のデータに対して行うので、オペランドの必要がない命令で操作が可能となる。間接参照用レジスタPCプログラムカウンタSPスタックポインタ8086のレジスタ8080と命令の互換性はないが、8080を意識したレジスタセットになっている。8086は20bitのアドレスが扱えるが、レジスタはすべて16bit。20bitのアドレス空間を直接アクセスする手段は提供されていない。アドレスはセグメントレジスタの内容を4bitシフトして足した値から得られる。直接アクセス可能な範囲は64KBの空間に限られたので、大容量めもりを利用や、リニアなアドレス空間を意識して作成されたC言語などのコンパイルは困難であった。現在から考えれば、16bitプロセッサとしても使いやすいものではなく、欠点のほうが目立ったプロセッサであったが、80286の演算性能はそこそこ高く、広く16bitパソコンに利用はされたが、逆にそれがパソコンの発展を妨げたとも考えられている。80286のアーキテクチャを大きく見直し、直接的な32bitアドレッシングが可能になっている。EDIとなり専用レジスタというより、汎用レジスタ・アーキテクチャになっている。汎用レジスタ・アーキテクチャとしてはレジスタの数が少なく、自由にレジスタを利用できるようにはなっていない。命令はコンパクトではあるが、レジスタ-メモリ間演算が多くなるため、メモリのキャッシュ技術などが重要になってくる。