web-dev-qa-db-ja.com

メモリがバイトアドレス指定されている場合、CPUは複数のバイトを一度にどのようにロードしますか?

私はCPUとそれらがどのように実装されているかについて読んでおり、いくつかの大きな複雑なアーキテクチャ(x86を見て)には、1クロックサイクル中にメモリからロードする命令があります。 1つのアドレスが1バイトを指しているので、どのように書けばよいですか。

mov eax, DWORD PTR ds:[esi]

ここで、メモリからダブルワード(4バイト!)をロードし、それをeaxにチャッキングしています。これは1クロックサイクルでどのように機能しますか? 4つのアドレスにアクセスする必要はありませんか? DWORDはds:[esi]から始まり、[ds:[esi] - 3]で終わります。つまり、4つの実効アドレスを計算する必要がありますが、1サイクルで実行されます。

どうやって?

ありがとう

5
DylanG

データバスの幅とアドレス可能な最小単位のサイズは2つの異なるものだからです。

バイトレベルでアドレスを指定できるからといって、8ビットのデータバスが必要になるわけではありません。ほとんど(おそらくすべて)の最新のx86プロセッサは64ビットのデータバスを使用し、メモリから読み取るたびに毎回64ビットを読み取ります。 8ビットのみを要求した場合、超過分は単に破棄されます。

64ビットを超えるリクエストを行う場合(たとえば、128ビットSSEレジスタ)をロードする場合)、複数のメモリアクセスが発生します。

また、多くのプロセッサにはアラインメントの概念があります。これは基本的に、すべてのメモリアクセスがデータバス幅で割り切れるアドレス上にあることを意味します。ほとんどは未調整のメモリをフェッチできますが、それが調整境界を越える場合(たとえば、64ビット調整システムのアドレス0xFCで32ビットを要求する場合)、データバスに収まる場合でも、複数のメモリアクセスを取得します。 。


質問のいくつかの側面に関するその他の注意事項は次のとおりです。

  • 1回のメモリアクセスには、1つのCPUクロックサイクルよりも時間がかかります。それがL1キャッシュにない場合、はるかに長くなります。大まかな桁数については この投稿 を参照してください。1ナノ秒= 1 GHzでの1クロックサイクルであることを覚えておいてください。最近の多くのデスクトップおよびラップトップCPUは、3 GHz以上、または0.333 ...ナノ秒未満のサイクルで実行できます。
  • 1クロックサイクルは1命令とは異なります。命令(完全にCPU内にとどまり、メモリや周辺機器にアクセスしないものでも)は、完了するまでに複数のサイクルを要する場合があります。さらに、複数の命令が同時に実行されている可能性があります(ここでは複数のコアやハイパースレッディングを指しているのではなく、ハイパースレッディングなしで単一のコアで複数の命令が同時に実行されていることを意味しています)。
7
8bittree

動作を説明する例として、まず古き良き68020のようなクラシックな32ビットプロセッサについて話しましょう。

さまざまな理由(互換性、ASCII文字など)の使いやすさ)のため、32ビットおよび64ビットのCPUでも個々のバイトに名前(「アドレス」と呼ばれます)があります。CPUにより大きなメモリチャンク、たとえば4バイトに名前を付けるには、最初のバイトに名前を使用し、暗黙的に後続のバイトは、直後に続くアドレス番号を持つバイトです。

一方、CPUには32本のデータラインD0 ... D32があるため、バスは32ビットを同時に転送できます。したがって、アドレスの32ビットのうち、下位2ビットはデータラインのグループを選択します(ビット00はD0 ... D7を選択し、01はD8 ... D15を選択し、10はD16 ... D23を選択し、11はD24を選択します... D31)。上位30アドレスビットのみが実アドレスラインA2 ... A32として存在します。下位2ビットの代わりに、CPUには4つの異なるバイト選択信号があり、さまざまな組み合わせで個別に使用できます。

これで、CPUがアドレス0x1000から32ビットを読み取る場合、32本のデータラインすべてを並行して使用できます。上位30ビットをアドレスバスに配置し、4つのバイト選択信号をすべて設定して、4バイトを転送します。

概要を見てみましょう:

  • 0x1000からバイトを読み取り:アドレスバス= 0x1000、バイト選択0
  • 0x1001からバイトを読み取り:アドレスバス= 0x1000、バイト選択1
  • 0x1002からバイトを読み取り:アドレスバス= 0x1000、バイト選択2
  • 0x1003からバイトを読み取り:アドレスバス= 0x1000、バイト選択3
  • 0x1004からバイトを読み取る:アドレスバス= 0x1004、バイト選択0
  • 0x1000からの短い読み取り:アドレスバス= 0x1000、バイト選択0 + 1
  • 0x1002からの短い読み取り:アドレスバス= 0x1000、バイト選択2 + 3
  • 0x1000からintを読み取り:アドレスバス= 0x1000、バイト選択0 + 1 + 2 + 3
  • 0x1002から(アラインされていない)intを読み取る:(最初のサイクル)アドレスバス= 0x1000、バイト選択2 + 3、次に(2番目のサイクル)アドレスバス= 0x1004、バイト選択0 + 1

現在のCPUでは原理は同じですが、内部キャッシュメモリでは、外部からのCPUコアの個々のバイト転送を監視できなくなりました。それらは、CPUコアとキャッシュ(両方ともオンチップ)の間で発生します。現在、メモリはキャッシュとのみ通信し、その転送は常にバイトより大きなチャンクで行われます。

2
Ralf Kleberhoff