会議室であるが、最近ではイントラネット上のグループウェアで予約管理が行われるというような方法も一般化しているが、昔は、会議室の入り口に予約表がぶら下がっていて、既に予約が書き込まれていなければ、そこに使用時間帯と使用者の名前を書き込んで予約するという方法が普通であった。
パイプラインの資源に対しても同じ手法で、メモリや演算器などの各資源ごとに予約表を作って、命令のデコードサイクルに、その命令の実行を完了するまでの全てのサイクルで必要な資源の予約表をチェックし、全ての資源が予約可能であれば、それらの資源の使用を予約表に書き込んで実行に入る。一方、どれかの資源が予約できない場合は命令の実行開始をストールする。
予約表であるが、図4.7のようにシフトレジスタで構成するのが便利である。
図4.7:予約表の構造 |
FF1は、次のサイクルでのこの資源の予約状況を記録し、FF2は、2サイクル後の資源の予約状況を記録する。FF3、FF4は更にその先のサイクルの予約状況を記録するFFである。命令をデコードすると、その命令の種別が分かり、それ以降の各サイクルで、どの資源を必要とするかが分かる。従って、それぞれの資源の予約表に対して、それを必要とするサイクル数を図4.7のCycleに入力すると、次のサイクルで必要とする場合はFF1、その更に次のサイクルで必要な場合はFF2、…の状態が選択されてReserved出力に出てくる。これが"1"であれば、先行する実行中の命令でその資源が予約されているので、その命令の実行はストールすることになる。一方、"0"であれば予約の無い状態であるので、図の上側のデコーダを通して対応するFFに"1"をセットして予約を行う。
そして、1サイクルが終わると、予約表のFF2をFF1、FF3をFF2、FF4をFF3にコピーしてシフトを行い、FF4には"0"を入れる。このようにシフトを行うことにより、次の命令(実行をストールした場合は、同じ命令であるが)のデコードと資源予約を行う状態とする。
図4.7には一つの資源の予約表しか書いてないが、各資源に同様な予約表があり、その命令の実行で必要となる全ての資源の予約表をチェックして、全ての資源が予約でき、必要なオペランドもバリッドであることを確認してから、その命令の実行を開始する。そして、これらの条件の一つでも欠けている場合には、その命令の実行を開始せず、次のサイクルに再度、オペランドや資源のチェックを行う。このようにして命令の実行を開始すれば、パイプラインでの命令の実行途中で必要な資源が使えないという事態は起こらない。
なお、デコードステージで条件が欠けていて命令の実行をストールする場合は、メモリから読み出された次の命令を命令レジスタに書き込まないようにすれば良い。こうしておけば、次のサイクルにも同じ命令がデコードされ、再度、実行に必要なオペランドや資源のチェックが行われることになる。また、同時にプログラムカウンタの更新を抑止しておけば、その次の命令フェッチのアドレスも同じであり、ストール中は、命令デコードまでの部分は同じ動作が繰り返されることになり矛盾は生じない。