命令コード部とオペランド部からなる機械語命令のビット構成
命令語の構成(命令フォーマット)とは、コンピュータが理解できる1つの機械語命令が、どのようなビットの並びでできているかという決まりのことです。命令語=CPUが実行する1つ分の命令を 0 と 1 のビット列で表したものです。
命令語は大きく分けて命令コード部とオペランド部の2つの部分でできています。上の図解の①のように、前半が「何をするか」、後半が「何に対して行うか」を表すと考えると分かりやすいです。
身近な例で言うと、お店の注文票に似ています。「焼く(動作)」+「ハンバーグを(対象)」のように、〈動作〉と〈対象〉がセットになって初めて1つの指示が完成します。命令語もまったく同じ構造をしています。
命令語を構成する2つの部分には、それぞれ明確な役割があります。
命令コード部(オペコード部、OPコード)は、「何をするか」=動作の種類を表します。
・加算(ADD)・減算(SUB)・転送(LOAD/STORE)・分岐(JUMP)など
・CPUはまずここを見て、どんな処理を行うかを判断する
・このビット幅で、表現できる命令の種類数が決まる(例:4ビットなら最大 2⁴=16 種類)
オペランド部(アドレス部)は、「何に対して行うか」=操作の対象を表します。
・対象のレジスタ番号、メモリの番地、即値(値そのもの)などを書く
・どう解釈するかは「アドレス指定方式」で決まる(直接・間接・即値など)
・命令によってはオペランド部を複数持つ(上の図解②の2アドレス・3アドレス命令)
上の図解②のように、オペランド部の個数によって0アドレス命令〜3アドレス命令と呼び分けます。たとえば「ADD A, B, C(A と B を足して C に入れる)」は対象が3つあるので3アドレス命令です。CPUはこの命令コード部を読んで動作を決め、オペランド部を読んで対象を特定する、という順で命令を解釈します。
命令語の「長さ(ビット数)」をどう決めるかには、固定長と可変長の2つの考え方があります。上の図解③で長さの違いを比べてみてください。
固定長命令は、すべての命令を同じビット数に揃える方式です。
・命令の区切りが常に同じ位置なので、解読(デコード)が単純で速い
・命令の取り出しやパイプライン処理がしやすい
・短い命令でも決まった長さを使うため、ややメモリにムダが出る
・RISC(命令を単純化したCPU)でよく採用される
可変長命令は、命令ごとに必要な長さだけ使う方式です。
・短い命令は短く、対象が多い命令は長く、と無駄なく詰められる
・メモリ(プログラムサイズ)を節約できる
・命令の長さがバラバラなので、区切りを判定する処理が複雑になる
・CISC(多機能な命令を持つCPU)でよく採用される
身近な例で言うと、固定長は「すべての荷物を同じサイズの箱に詰める」、可変長は「荷物に合わせて箱の大きさを変える」イメージです。前者は仕分けが楽(速い)、後者は隙間が少なく省スペース(節約)という、それぞれの長所があります。「固定長=デコードが速い/可変長=メモリ効率がよい」という対比で押さえておくとよいでしょう。
命令のオペランド部には「どこに対象のデータがあるか」が書かれています。でも、その書き方(解釈のしかた)は1種類ではありません。この「オペランド部の値をどう解釈して、実際のデータを取り出すか」の決まりをアドレス指定方式と呼びます。
代表的な3つの方式をまとめます。
・即値アドレス指定:オペランド部に値そのものが書いてある。「5を足せ」のように値が命令の中に直接入っているので、メモリを読む手間がなく速い。ただし使える値の大きさが限られる
・直接アドレス指定:オペランド部にメモリの番地(住所)が書いてある。「番地100にあるデータを使え」という意味で、その番地を1回読めば値が得られる
・間接アドレス指定:オペランド部に書かれた番地を読むと、さらに別の番地が書いてある。2回読んで初めて本当のデータに到着する。遠回りだが柔軟に使える
身近な例で考えると、直接アドレス指定は「棚の101番に荷物が入っている」と番地を直接教えてもらうイメージ。間接アドレス指定は「棚の101番に"本当の荷物は棚の200番にある"と書いたメモが入っている」ようなイメージです。1段階多く読む分だけ時間がかかりますが、番地を動的に変えられる柔軟性があります。
なぜ1つの方式に統一しないのか。それは、アドレス指定には「速さ」と「柔軟さ」のトレードオフ(一方を得ると他方が犠牲になる関係)があるからです。速い方式には表現できる範囲の限界があり、柔軟な方式はアクセスに時間がかかります。
各方式の特徴を並べると、次のとおりです。
・即値:メモリへのアクセスなし=最速。ただし命令の中に入れられる値の大きさに上限がある
・直接:1回メモリを読む。分かりやすく使いやすい。ビット幅の分だけ番地の広さが決まる
・間接:2回メモリを読む=やや遅い。でも番地を実行中に変えられる(配列の処理などに有利)
このほかにも、相対アドレス指定(=現在の位置からの距離で指定する方法)やレジスタアドレス指定(=CPU内の高速な記憶場所「レジスタ」を使う方法)など、複数の方式があります。プログラムの中には、速く動かしたい部分・柔軟さが必要な部分・それぞれが混在するため、用途に合わせて方式を組み合わせることでCPU全体の性能を最大限に引き出しています。