• ベストアンサー

複数バイト命令実行のタイミング

1バイト単位でメモリの各アドレスにデータが保存されているコンピューターにおいて、複数のバイトで表される命令がどのように実行されるのか教えて下さい。 メモリには一つのアドレスごとに8ビット(1バイト)のデータが入っており、CPUはプログラムカウンタで示されたメモリ上のアドレスにあるデータや命令を一つずつ順番に読み込んで、それをデコーダーが解釈し各回路への指令に変換することでプログラムを実行していくということは理解しています。 しかし現在の32ビットコンピューターなどにおいてアセンブリの命令、例えば「MOV A,B」(Bレジスタの内容をAレジスタにコピーする)といった命令は、「B90001」などの3バイトのマシン語で表されるとすると、メモリ上では アドレス  内容 0000  0xB9 0001  0x00 0002  0x01 のように3つの連続するアドレスにまたがってデータが存在し、CPUが「MOV A,B」を読み込み、それを順次デコーダーに送るまでには「MOV」、「A」、「B」の3クロックを要すると思います。 その際、デコーダーが命令を解釈し各回路に指令の信号を送るタイミングというのは、最後の「B」のデータを読み込んだ時点になるのでしょうか?もしそうならば、3クロック目に最後の「B」のデータがデコーダーに到着するまでの間、「MOV」と「A」のデータというのはCPUにメモリから読み込まれた後はどのように扱われるのでしょうか? 少し質問が分かりにくく恐縮ですが、情報工学を独学で勉強しており、プログラムが実際の回路でどのように実行されるのか理解したいと思っています。 どうぞご回答よろしくお願い致します。

質問者が選んだベストアンサー

  • ベストアンサー
  • mtaka2
  • ベストアンサー率73% (867/1179)
回答No.5

回答2の者です。 > 3バイト命令を一回でフェッチするということは、バス上では3クロック目で「MOV A,B」の3バイトが同時にデコーダーにフェッチされるということですか? いいえ、3クロック目ではありません。 命令フェッチステージ: アドレス0000~アドレス000F の16バイトを読み込み プリデコードステージ: 0000~0002 の3バイトが1命令であると判定 命令デコードステージ: 0000~0002 の3バイトを解釈、「MOV A,B」を発行 という流れですので、「MOVを読んで」「Aを読んで」「Bを読む」と順次処理するのではなく、 デコーダには、いきなり「MOV A,B」と解釈するのに十分なデータが揃います。 と、ここまでが今時のCPUの話。この場合、複数バイトを同時に読み込めますので、基本的には状態機械を作る必要がありません。 (厳密には、「16バイト単位での読み込み」での境界をまたいだ命令については、複数の命令フェッチを行う必要があるので、その状態は管理する必要があります) 一方、昔ながらの8ビットバスなCPUでは、複数バイト命令の実行をどのように実現するのか、という条件では、状態管理が必要になるわけですが、 > 既に読み込まれた命令というのは命令レジスタに保持されるということでしょうか? バイト列が命令として完結するまで、何らかのバッファレジスタに溜め込んでいくことになります。 そういう場合は、1クロック目・2クロック目は命令フェッチしてバッファに入れるだけで、 3クロック目の命令フェッチで命令デコードに必要なデータが揃うので、命令発行が行われます。 命令フェッチ時には、 「命令の1バイト目を読んでいる」のか「3バイト命令の2バイト目を読んでいる」のか「3バイト命令の3バイト命令を読んでいる」のか、 それによって処理が変わるわけですが、これが状態機械であり、 それぞれの状態にビット列を割り当て、それを保持するレジスタを用意し、 状態レジスタの内容、命令バッファの内容、最新のフェッチデータなどから、フェッチ部の動作が決まります。

miyaken912
質問者

お礼

>命令フェッチステージ: アドレス0000~アドレス000F の16バイトを読み込み 命令フェッチで一度に16バイトをメモリから読み込むことが出来るのですね。知りませんでした。 何度も深く掘り下げて質問して恐縮ですが、プログラムカウンタが指定出来る読み込み先(命令フェッチ先)のアドレスというのはひとつだけ(1バイト分だけ)だと理解していたのですが、データバスが16バイト分あるとしても、なぜ一度に16バイトものデータをフェッチすることが回路上可能なのでしょうか? 深く追究して質問してしまい恐縮ですが、よろしくお願い致します。

その他の回答 (6)

  • ybnormal
  • ベストアンサー率50% (220/437)
回答No.7

>追加の質問で恐縮ですが、1クロック(サイクル)の命令フェッチで複 >数のアドレスにわたるデータをフェッチし命令バッファに格納すること >が可能だと理解したのですが、私の認識ではプログラムカウンタによっ >て指定出来るアドレスは一つ(セレクタで指定出来るメモリアドレスは >一つ)だと思っていたのですが、なぜ複数のアドレスを指定することが >回路上可能なのでしょうか? PCが指定できるアドレスはもちろん一つで、通常はフェッチする命令の先頭アドレスを指します。例えば3バイト分を常に一括してフェッチするような実装の場合、下の例ではPC=0003のときは0003から0005までの命令をフェッチして、次のPCは0006を指します(分岐はないと仮定)。 アドレス  内容 0003  0xB9 0004  0x00 0005  0x01 0006  .... 0007 ....

miyaken912
質問者

お礼

ご回答ありがとうございます。 >PCが指定できるアドレスはもちろん一つで、通常はフェッチする命令の先頭アドレスを指します。例えば3バイト分を常に一括してフェッチするような実装の場合、下の例ではPC=0003のときは0003から0005までの命令をフェッチして、次のPCは0006 を指します(分岐はないと仮定)。 なるほど、大分理解が進みました。重ね重ねご丁寧な回答ありがとうございました!

  • mtaka2
  • ベストアンサー率73% (867/1179)
回答No.6

> 何度も深く掘り下げて質問して恐縮ですが、プログラムカウンタが指定出来る読み込み先(命令フェッチ先)のアドレスというのはひとつだけ(1バイト分だけ)だと理解していたのですが、データバスが16バイト分あるとしても、なぜ一度に16バイトものデータをフェッチすることが回路上可能なのでしょうか? それは、データバスが16バイト分あるから、としか答えようがないです。 たとえば、プログラムカウンタが0003 で、0003からに3バイト命令があった場合では、 データバスが128bitであり、16バイト単位で読み込みになりますから、 命令フェッチステージ: アドレス0000~アドレス000F の16バイトを読み込み →0003~0005 のバイト列を命令デコーダに渡す。 となります。 もしプログラムカウンタが000F だったとして、そこにある命令が3バイト命令だとしたら、 命令フェッチステージ1: アドレス0000~アドレス000F の16バイトを読み込み→000Fのバイトをバッファにためる 命令フェッチステージ2: アドレス0010~アドレス001F の16バイトを読み込み→バッファにある000Fにのバイトと、0010、0011 を、命令デコーダに渡す といった流れになります。 あと、回答4の --- 例えば命令バッファのエントリをオペコード、レジスタ1、レジスタ2のように分けてそれぞれに有効ビットを設けて、細切れの命令が格納されるときに該当する有効ビットを立てるようにすれば、命令が全部そろったかどうかはわかります --- と、私が書いた回答5の --- 「命令の1バイト目を読んでいる」のか「3バイト命令の2バイト目を読んでいる」のか「3バイト命令の3バイト命令を読んでいる」のか、 それによって処理が変わるわけですが、これが状態機械であり、 それぞれの状態にビット列を割り当て、それを保持するレジスタを用意し、 状態レジスタの内容、命令バッファの内容、最新のフェッチデータなどから、フェッチ部の動作が決まります。 --- は、抽象的に「状態機械」と言うか、具体的に「有効ビット」と言うのか、表現が違うだけで、意味としては同じことを説明してます。 …x86系の最近のCPUは、やってることがかなり複雑になってますので、理解が難しくなるのですが、 質問者さんは、そもそもその前段階として、CPUの基本的なハードウェア構成が理解しきれてないように見受けられます。 まずは回答1でも挙げられている通称パタヘネ本こと「コンピュータの構成と設計」は一度読んだ方が良いかと思います。 http://www.amazon.co.jp/dp/482228056X 著者のヘネシーとパターソンは、RISC CPU の提唱者とでも言うべき人で、 この本は一言で言うと、CPUの設計をハードウェア・ソフトウェア両面から解説した本です。 通称ヘネパタ本と呼ばれる「コンピュータ・アーキテクチャ」って本もあるのですが http://www.amazon.co.jp/dp/4822271528 こっちはハードウェアにそれほど踏み込んでません。 まぎらわしいので要注意。

miyaken912
質問者

お礼

丁寧なご回答ありがとうございます。 命令フェッチについて大分理解がすすんだと思いますが、ご指摘の通りハードウェア構成について勉強不足な部分が多いと思います。 ご紹介いただいた「コンピュータの構成と設計」を読んでさらに学習を続けたいと思います。どうもありがとうございました。

  • ybnormal
  • ベストアンサー率50% (220/437)
回答No.4

>No.1,No.2での追加の質問とも重複しますが、命令発行がバイト単位で >はなく命令単位(この場合は3バイト)で行われるということは理解 >しましたが、命令が発行されるまでの間先に読み込んだオペコードや >レジスタ番号などは回路上どこに保持されるのでしょうか? レジスタ番号は分かるのは一般的には命令がデコードされてからです。よっぽど簡単なマイクロプロセッサでなければ、命令をメモリからフェッチした後、それらの命令を保持しておく命令バッファがあります。 あなたの例では、命令が発行されるまでは、B90001という命令が命令バッファに格納されていて、それがデコーダに向けて発行されて、デコーダが命令種別、レジスタ番号などを解釈し、それに基づいて演算処理に入ることになります。 >また命令発行のタイミング(この場合Bが到着してから)というのは >どのように実現されているのでしょうか? 命令が細切れにフェッチされて命令バッファにばらばらに入るようなアーキテクチャはきれいではないし命令フェッチにも時間〔サイクル数)がかかるので普通はそのようなことはしないでしょう。命令幅が8ビットであれば、メモリへの命令バスもCPU内部の命令バスも8ビットにして、命令単位で処理できるようにするはずです。 どうしても一つの命令をばらばらにしてフェッチしたいというのであれば、例えば命令バッファのエントリをオペコード、レジスタ1、レジスタ2のように分けてそれぞれに有効ビットを設けて、細切れの命令が格納されるときに該当する有効ビットを立てるようにすれば、命令が全部そろったかどうかはわかりますから、その時点で命令は発行可能になります。 でも現実にはそんな効率の悪いアーキテクチャにはしないのが普通です。

miyaken912
質問者

お礼

ご回答ありがとうございます。 命令バッファにフェッチされた命令が保持されるのですね。 追加の質問で恐縮ですが、1クロック(サイクル)の命令フェッチで複数のアドレスにわたるデータをフェッチし命令バッファに格納することが可能だと理解したのですが、私の認識ではプログラムカウンタによって指定出来るアドレスは一つ(セレクタで指定出来るメモリアドレスは一つ)だと思っていたのですが、なぜ複数のアドレスを指定することが回路上可能なのでしょうか? >どうしても一つの命令をばらばらにしてフェッチしたいというのであれば、例えば命令バッファのエントリをオペコード、レジスタ1、レジスタ2のように分けてそれぞれに有効ビットを設けて、細切れの命令が格納されるときに該当する有効ビットを立てるようにすれば、命令が全部そろったかどうかはわかりますから、その時点で命令は発行可能になります。 なるほど。有効ビットを設けることで実現することが出来るということが理解出来ました。ありがとうございます。

  • ybnormal
  • ベストアンサー率50% (220/437)
回答No.3

>アドレス  内容 >0000  0xB9 >0001  0x00 >0002  0x01 >のように3つの連続するアドレスにまたがってデータが存在し、CPUが>「MOV A,B」を読み込み、それを順次デコーダーに送るまでには >「MOV」、「A」、「B」の3クロックを要すると思います。 命令がデコーダに送る前に、命令を発行(Issue)する必要があり、命令発行はバイト単位ではなく命令単位で行われます。したがってデコーダはレジスタ番号も含めた命令を受け取るのに1サイクルで十分です。(CPU内部の命令バスが8ビットしかないのなら話は別ですが、まずそんなCPUは存在しないでしょう) >その際、デコーダーが命令を解釈し各回路に指令の信号を送るタイミ >ングというのは、最後の「B」のデータを読み込んだ時点になるのでし>ょうか?もしそうならば、3クロック目に最後の「B」のデータがデコ>ーダーに到着するまでの間、「MOV」と「A」のデータというのはCPUに>メモリから読み込まれた後はどのように扱われるのでしょうか? 演算ユニットへの要求は、Bが到着してからになりますが、さっきも行ったように普通は命令は細切れにして発行されることはありませんから、MOVとAとBは同時にデコーダに入力されます。 どうしてもこれらを細切れに発行するのであれば、Reservation Stationのような演算キューを持たせて全部データがそろってから演算要求をだすことになるでしょう。

miyaken912
質問者

お礼

ご回答ありがとうございます。 >命令がデコーダに送る前に、命令を発行(Issue)する必要があり、命令発行はバイト単位ではなく命令単位で行われます。したがってデコーダはレジスタ番号も含めた命令を受け取るのに1サイクルで十分です。 >演算ユニットへの要求は、Bが到着してからになりますが、さっきも行ったように普通は命令は細切れにして発行されることはありませんから、MOVとAとBは同時にデコーダに入力されます。 No.1,No.2での追加の質問とも重複しますが、命令発行がバイト単位ではなく命令単位(この場合は3バイト)で行われるということは理解しましたが、命令が発行されるまでの間先に読み込んだオペコードやレジスタ番号などは回路上どこに保持されるのでしょうか?また命令発行のタイミング(この場合Bが到着してから)というのはどのように実現されているのでしょうか?

  • mtaka2
  • ベストアンサー率73% (867/1179)
回答No.2

基本的に「CPUの設計による」としかいいようがないですが、 ・最近のx86系CPUの場合、命令フェッチ段階で、メモリバスは128bit=16バイトぐらいありますので、3バイト命令ぐらいなら1回でフェッチ可能です。 ・さらに、最近では、「命令フェッチ」と「命令デコード」の間で「命令プリデコード」サイクルを設けて、128bit=16バイトのうち、命令開始位置になっているバイトにマーキングをしています。 ・そのマーキング結果を基に、命令デコードサイクルでは、複数バイト命令を複数個、一サイクルでデコードできます。 (プリデコードで、「何バイト命令か」が分かっているので、「複数バイト命令」を完結したバイト列としてデコードに渡せる) なお、大昔な8bitCPU時代(命令フェッチがバイト単位なCPU)だと、 バイト単位でメモリ上から1クロックずつ読み出すことになりますが、 その場合は、複数バイト命令実行時は、「状態機械」を構成して、 状態を更新しつつ命令フェッチ・デコードサイクルを繰り返すことになります。 つまり、質問内容のような場合なら、 [新規に命令をデコード開始している状態] ↓(0xB9をフェッチ) [0xB9 をフェッチ、複数バイト命令で読み込みが完了していないので2バイト目の読み込み待ち状態] ↓(0x00をフェッチ) [0xB9 0x00 をフェッチ、複数バイト命令で読み込みが完了していないので3バイト目の読み込み待ち状態] ↓(0x01をフェッチ) MOV A,B を発行して、[新規に命令をデコード開始している状態]に といった状態遷移が行われます。

miyaken912
質問者

お礼

ご回答ありがとうございます。 >最近のx86系CPUの場合、命令フェッチ段階で、メモリバスは128bit=16バイトぐらいありますので、3バイト命令ぐらいなら1回でフェッチ可能です。 3バイト命令を一回でフェッチするということは、バス上では3クロック目で「MOV A,B」の3バイトが同時にデコーダーにフェッチされるということですか?僕の理解だと毎クロックごとに命令フェッチが実行されると思ったのですが、最初の1クロック目と2クロック目(メモリから「MOV」と「A」が読み込まれる)ではデコーダーに命令フェッチは行われていないのでしょうか? 同じことかもしれませんが、3クロック目で命令フェッチが行われるまでの間は「MOV」と「A」は命令レジスタに保持されて、3クロック目で「B」まで揃ったら命令レジスタの内容がデコーダーにフェッチされるという理解は正しいでしょうか? >複数バイト命令実行時は、「状態機械」を構成して、 状態を更新しつつ命令フェッチ・デコードサイクルを繰り返すことになります。 >複数バイト命令で読み込みが完了していないので2バイト目の読み込み待ち状態 上記と同じ質問かもしれませんが、状態機械(ステートマシン)で読み込み待ち状態の間は、既に読み込まれた命令というのは命令レジスタに保持されるということでしょうか?状態遷移(図)は理解しているのですが、状態機械自体がどのようなものか知らないので可能ならば補足説明をお願い致します。

回答No.1

>デコーダーが命令を解釈し各回路に指令の信号を送るタイミングというのは、最後の「B」のデータを読み込んだ時点になるのでしょうか? そうなりますね >もしそうならば、3クロック目に最後の「B」のデータがデコーダーに到着するまでの間、「MOV」と「A」のデータというのは CPUにメモリから読み込まれた後はどのように扱われるのでしょうか? ”CPUはハードウェアによる機械語インタプリタである” と思うと分かりやすいと思います.もっとも単純な実装方法としては,MOV命令が読み込まれた時点でレジスタ間転送命令の処理・・ソフトウェア的に言えばMOV処理ルーチンに飛ばします.(ハードウェア的にはステートマシンでMOV処理ステートを起動っていう感じでしょう) この後オペランドを順次読み込んで処理するステップですね.BからAへの転送だと分かるとBレジスタのライト信号,Aレジスタのリード信号をアサートして内部バス経由でデータ転送させます. たとえばこのための信号が上位4ビットが転送先,下位4ビットが転送元とするなら,MOVの後のAを読んだ時にAレジスタに当たる値を上位4ビットにセット,続いてBを読み込んだら下位4ビットをBレジスタになるようにして「実行!」信号を生成っていう感じでしょうか. こういう具合にMOVの後にあるオペランドを使って必要な信号を生成するわけですね. ヘネパタか・・パタヘネ・・でしたか,あの本の中で扱っているのはMIPSのベースになった32ビットRISC-CPUですけど,あの場合には必ず1ワードを1命令の固定長としているのですごく楽なんですね.1ワード読んだらそのまま命令デコーダに丸投げですし,デコーダも32ビット分を一度に解釈すればそれでオシマイですから.

miyaken912
質問者

お礼

ご回答ありがとうございます。 >”CPUはハードウェアによる機械語インタプリタである”と思うと分かりやすい なるほど。 >ハードウェア的にはステートマシンでMOV処理ステートを起動っていう感じでしょう ハードウェアのステートマシンとは具体的にどのような回路で実現出来るのでしょうか? また、このときのステートマシンとはつまりオペコードとオペランドのセットが全て読み込まれるまでは次の遷移に移行せず、最後のオペランド(この場合は「B」)が読み込まれるまでは、先に読み込まれた「MOV」と「A」はその情報をどこか(命令レジスタ?)に保存するというものでしょうか?

関連するQ&A