プログラムはCPUレベルでどのように実行されますか?


14

これはよくある質問です。しかし、私は心の中で異なる角度を持っています。ここで明確にしようとします。

私が知っていることから、CPUが実行するすべての命令は機械語であり、CPUができることはすべて、ALUとそのトランジスタのおかげで何らかの算術演算を行うことです(ハードウェアレベルの場合)。

ただし、これは理解するよりも入力する方が簡単です。すべてのCPUが加算、減算などを行うのであれば、これらの算術演算で実行されるプログラム、たとえば、印刷Hello WorldというJAVAプログラムはどうでしょうか。

つまり、このプログラムは、CPUに追加するだけのものにどのように変換されるのでしょうか。

PSこの質問がこのウェブサイトに当てはまらない場合は、おpoび申し上げます。

- - -二部 - - -

はい。これに迅速かつ熱意を持って答えてくれたすべての人に感謝します。質問に少し手を加えて、すべての回答にコメントしてからもう一度質問するよりも良いと思いました。

ここにあります。

まず、全員がHello Worldの例について具体的に回答しています。これは私のせいだ。私はこれをジェネリックのままにしておくべきでした。Hello worldの例では、出力デバイスと、その処理がCPUだけに限定されるわけではないことを疑問視しています。

また、多くの人がCPUが単なる追加以上のことを行うことに気付きました。私はそれに同意します。私はただそれを書いておらず、ずっとそれを想定していました。私が理解していることから、これはプロセスです:

  1. メモリから命令を読み取る(データおよびアドレスバスとプログラムカウンタースタッフを使用)

    1. CPU内のレジスタにデータを保存する
    2. ALUはもちろん、命令をデコードした後、算術演算を行うか、ifのような命令の場合はジャンプします
    3. そして、出力デバイスなどのように、必要に応じて他のリソースと通信します。これ以上のプロセスは今のところ簡単です。

CPUが命令をデコードし、算術演算を実行することを決定するステップ3で(ここでは、現在の命令をジャンプするなど、他に実行すべき演算がないと仮定しています。 )ここで私の視覚化が終了します。プログラムからの命令がCPUの単なる算術演算である方法。それはその算術演算を行い、その命令はその目的を果たします。

今回は明確にしたいと思います。

PSここでは、ALUはプログラムで行う実際の算術演算に限定されず、バイナリ形式のすべての命令を実行するなど、それらを意味する結果を得るために加算または減算することで大きな仮定を取っています得た。ここで間違っている場合は、以下の回答が私の質問に正しく答えています。


コンパイラがプログラムを機械語に変換することを理解しています。プログラムを算術演算として視覚化することはできません。プログラム自体が2つの数字を追加することである場合、それは理解できますが、そうでない場合は..まだ!! :)
user2827893

1
たとえば、MC6502、Z80などの非常に単純なCPUなど、実際のCPUの命令セットを確認する必要があります。次に、メモリアクセス命令、データ処理命令、ブランチがあることを確認します。任意のアルゴリズムを実装するために組み合わされます。
TEMLIB

3
CPUは間違いなく追加以上のことができます。CPUが比較とジャンプを実行できることに言及することは重要です。
セオドロスチャツィジアンナキス

1
IF(決定を下す)とMOVE(データの読み取りと保存)を見るのをまだ拒否しているようです。プログラミングは99%IFとMOVEです。算術は無視できます。最初の例(Hello world)には算術演算がまったくありません。
edc65

1
1.この質問を編集して質問内容を変更するのではなく、新しい混乱を伴う新しい質問をした方が良い答えを得る可能性が高いと思います。元の質問に対する良い回答が得られ、元の質問はそれ自体で成り立つように思えるので、編集を削除して新しい質問をしてみませんか?2.とはいえ、新しい部分を理解することはできません。新しい部分についてのあなたの質問は正確に何ですか?あなたは「これはどこ私の可視化が終了している」と言うとき、あなたは意味ですか行うステップ3を理解し、または手順3を理解していませんか?もしそうなら、あなたは何を理解しませんか?
DW

回答:


7

簡単なプログラムを取得して、ネイティブマシンコードにコンパイルしてみてください。(Javaは通常、JVMコードにコンパイルされますが、Andrew Tennenbaumは、それをネイティブに実行するCPUを設計する方法を説明した本を持っています。したがって、GCCでは、コンパイラーに-Sスイッチを与えます。

これにより、オペレーティングシステムを呼び出すことにより、I / Oなどのトリッキーなものが実装されることがわかります。ソースをLinuxカーネルにダウンロードして同じことができますが、内部で行われているのは、すべてがコンピューターのメモリの状態(実行中のプロセスのリストなど)を操作すること、またはハードウェアと通信することですそれを制御するかのような特殊なCPU命令を使用して、特殊なメモリアドレスinoutx86の上で。ただし、一般に、デバイスドライバーと呼ばれる特別なプログラムのみが特定のハードウェアと通信し、OSは適切なドライバーにハードウェアを使用する要求を送信します。

具体的には、「hello、world!」と印刷すると コンパイラはそれを一連の命令に変換し、文字列を特定の場所にロードし(たとえば、メモリ内の文字列のアドレスを%rdiレジスタにロードし)、そのcall命令でライブラリ関数を呼び出します。このライブラリ関数は、ループを使用して文字列の長さを検索し、システムコールを呼び出します。write()文字列からそのバイト数をファイル記述子番号1(標準出力)に書き込みます。その時点で、OSはそのプロセスのファイル番号1を検索し、それに書き込むことの意味を決定します。標準出力への書き込みが画面に出力される場合、バイトをバッファーにコピーするなどのプロセスがあり、ターミナルプログラムによって読み取られ、ウィンドウシステムにどの文字をどのフォントに配置するかを指示します。ウィンドウシステムは、それがどのように見えるかを正確に決定し、画面にピクセルを配置するようにデバイスドライバーに指示します。これは、ビデオメモリを変更することによって行われます。


@Loreheadに感謝します。この説明は、Hello worldの例でよく見えます。
user2827893

5

あなたが理解したように、CPU自体は馬鹿です。しかし、周囲にはハードウェアチップの縮図があります。CPUの1行を別のチップに配線された高レベルに設定できる命令があります。そのハードウェアチップは回線を監視し、「ねえ、この回線が高い場合は、他の回線で何かをする」と言います。

これを簡単にするために、これらの行はグループ化されています。一部はデバイスのアドレス指定に使用され、一部はそれらのアドレスのデータ転送に使用され、その他は再び「おい、私のチップには重要なことがあります」という行です。

最後に、CPUは他のチップに、「Hello World」のように見えるようにモニタへの信号を変更してくださいと指示するだけです。

Googleは7セグメントディスプレイの描画を行います。ワイヤーがあり、電圧をかけるとセグメントが点灯します。CPUの1つの出力ラインと7セグメントディスプレイの1つのラインを接続すると、ディスプレイが点灯します。LEDを点灯させるのはCPUではなく、単にラインに電圧を印加するだけですが、他のハードウェアはそれによって気の利いたことをするかもしれません。

CPUがHのすべての行を高に設定すると、7セグメントにはHが表示されますが、HはCPUが加算または減算する数値ではありません。

ここで、すべてのレイヤーが7セグメント表示をHにするために必要なものに同意する場合(特定の5行を高く設定する)、JavaコンパイラーはHを表示するためのコードを作成できます。これはもちろんかなり不便です。抽象化する。最下層は次のようになります:「26個の文字があります。各文字に数字を割り当てましょう。「H」という数字に「72」という数字を付けてみましょう。 「行309を高く、行310を高く、行498を高く、行549を高く、行3を高く設定」の代わりに。各層は情報、特定の結果を達成する方法を抽象化し始めます。それらを気にする。

確かに、CPUが実際に処理できるのは、チェーン内の全員が同意した意味で、数値またはビットの膨大なマッピングになります。


3

大学では、CS学位プログラムの一環として、CPUを定義するレジスタ転送言語の拡張例を研究しました。私はそれについて別のテイクを取り、そのような表記法を定義として受け入れるシミュレーターを書くことに触発され、それをEmbedded Systems Programming(1989年3月号)であなたが尋ねたのと同じ種類の質問に答える方法として公開しました。そのようなことの直感的な理解を構築します。

クラスでは、レジスタ転送表記をレジスタ上の実際の論理ゲートに抽出しました!それはそれ自身を書きます:宛先としてレジスタ 'A'を持ち、コードA =(case1)または(case2)...を持ち、製品の合計または製品の合計の正規化形式として表現されるすべてを見てください。

コースの最後で、これが本当のCPUであることがわかりました。正しく思い出せば、PDP-8です。

今日では、ゲート図をプログラマブルロジックアレイチップに入力できます。

それがその要点です。レジスタは、他のレジスタに戻るANDゲートとORゲートの結果で設定されます。含める値の1つはオペコード値です。

想像してみてください:A:=(opcode == 17&X + Y)|(opcode == 18&X + Z)| ...

現代のCPUは、パイプラインとバスでより複雑ですが、単一のALUのような個々のサブユニットはそのように機能します。


2

ここでCPUを検討していますが、「Hello World」を実行するときに関係する別のコンポーネントがあります:ディスプレイです!

CPUの場合、メモリ内の値は、指定されたビット数(0と1)として表される単なる数値です。

画面上で文字に変わる方法は別の話です。ディスプレイには記憶もあります。このメモリ(グラフィックメモリ)は、画面上の「ピクセル」にマップされます。各ピクセルは値でエンコードされます。非常に基本的なモノクロディスプレイの場合、値は単なる強度です。カラーディスプレイの場合、値はさまざまな方法でエンコードできる赤緑と青(RGB)の組み合わせです。

そのため、CPUが特定の値をディスプレイメモリに「書き込む」と、ピクセルが点灯します。実際に文字を書くには、多くのピクセルを明るくする必要があります。通常、コンピューターのオペレーティングシステムでは、文字セット(実際にはいくつか)が定義されています。(「フォント」自体を抽象化し、各文字が画面上でどのように表示されるかの定義にマップします)

そのため、コードがコンパイルされると、CPUがグラフィックメモリのどこに書き込むべきかを知ることができるこれらのフォント/文字セットなどを含む、OSライブラリに由来するあらゆる種類のものが含まれます。(それは非常に複雑ですが、それが一般的なアイデアです:コンパイラには、インポートされたライブラリを介して、「hello world」コードだけのコードよりも多くのコードが含まれます)

最終的に、あなたが疑うように多くのことが起こっていますが、そのようなコードをすべて書く必要はありませんでした。


1

理論的なコンピューターサイエンスの分野からの質問に対する正式なアプローチを次に示します。

基本的に、CPUの計算モデルとチューリングマシンの間のマッピングを定義できます。すべての想像可能なチューリングマシンプログラムのセット(したがって、CPU上で実行可能なすべての想像可能なプログラム)が数え切れないほどあるという理論的証拠が存在します。これは、自然数をチューリングマシンに拡張するプログラムを含む、すべてのプログラムを一意の自然数で識別することができることを意味します

CPUが行うことのほとんどがバイナリ表現の自然数の計算であることを既に知っているので、CPUが考えられるすべてのプログラムを実行できると考えることができます。

注:これは非常に単純化されていますが、私の意見では、良い直観を与えます。


1

助けになるのは、思考を「算術を行う」ことから遠ざけることです。「Hello World」を印刷するために、コンピュータが内部で何をしているのかを本当に掘り下げようとしている場合は、1レベル下を考えるのが最善です。コンピュータの「状態」は、オンまたはオフのトランジスタスイッチ(または充電または非充電のコンデンサ)によって格納されるビットのセットとして説明できます。コンピューターはルールに従ってこれらのビットを操作します。コンピューターがこれらのビットを操作できる方法は、ビットを0から1、または1から0に変更する作業を行うトランジスターの形でCPUに書き込まれます。

ALUが「算術を行う」とは、それが本当に意味することは、算術の規則と矛盾しない方法でコンピューターの状態を変更したということです。少し変更するだけでした。それが加算または減算と考える理由を説明するのは、ソフトウェアの背後にある意味です。CPUは、実行中の処理を「認識」しません。状態から状態へと変化するだけで、それだけです(少なくともSkynetが引き継ぐまで)。

そのように考えると、「ジャンプ」命令のようなより複雑な命令も同じです。いくつかのビットを変更するだけです。この場合、次に実行する命令の場所を意味することがわかっているビットが変更されることがあります。CPUはこれを「認識」していませんが、知っています。したがって、これらのビットをコード内の場所から場所へ「ジャンプ」する命令を使用します。

IOも実際には変わりません。ビットを変更するだけです。わずか違いは、これらのビットがトランジスタに接続されているため、最終的に画面上の文字が点灯することです。「Hello World」が実際にシンプルだった頃を思い出すと、「Hello World」のASCII文字に対応するビットを書き込むと、それらの文字は画面。今日では、グラフィックカードとそれを混乱させるオペレーティングシステムがあるため、少し複雑になっていますが、基本的な考え方は同じです。オンまたはオフのトランジスタのセットがあり、それらは画面にピクセルを表示する回路にリンクされています。適切なものを設定すると、画面に「Hello World」と表示されます。

混乱は、単に構文とセマンティクスの問題です。ALUの「半分追加」または「完全追加」の動作は構文です。ビットを入れるとどのビットが出てくるかを定義します。その意味は、加算を行う能力の概念です。あなたと私は、ALUが「追加を行う」ことができることを知っていますが、その下で何が起こるかを本当に理解するには、ALUは構文のビットとバイトのみを操作することを覚えておく必要があります。


0

CPUは次のように機能します。

  • 現在の命令をフェッチし、「現在の命令」ポインタをインクリメントします。

  • デコードします(たとえば、この命令がCPUに実行するよう指示していることを確認します)

  • 実行(命令の言うことを実行)-命令が「ジャンプ」のようなものである場合、現在の命令ポインタが変更される場合があります。

  • 永遠に繰り返す

現代のCPUはより複雑で、そのプロセスの一部を大きくオーバーラップさせて予測しようとします(たとえば、「パイプライン」をいっぱいに保つためにCPUが「現在の命令」ポインターのはるか先にフェッチしている間に他の10命令がデコードされている間に実行を開始します)基本的なプロセスは本当に同じです。

指示には多くの種類がありますが、そのほとんどの例は次のとおりです。

  • 「移動」手順。これらはXを別のXにコピーできます。Xはメモリ(RAM)、レジスタ、またはCPUがそのような概念をサポートしている場合はI / O空間のアドレスです。

  • レジスタへのポップ、スタックへのプッシュレジスタなどを含むスタック操作命令。これらは、「スタックポインタ」レジスタを使用および更新する「移動」命令の特殊なケースです。

  • 2つのレジスタ間またはメモリとレジスタ間で数学演算を実行する命令。これらの命令は、フラグレジスタに自動的に影響します。そのようなフラグの1つは、結果がゼロの場合に設定される「ゼロ」フラグです。別のフラグは、結果の最上位ビットが設定される場合に設定される「負」フラグです。CPUに応じて他のものがあるかもしれません。

  • 算術演算の特殊なケースは比較命令で、これは減算と同じですが、結果は保持されません。フラグは引き続き影響を受けます。

  • 特定のフラグが設定されている場合、メモリアドレスにジャンプする分岐命令があります。上記の「ゼロ」フラグを覚えていますか?また、「等しい」フラグとしても機能するためBEQ、「ゼロ」フラグが設定されている場合に実際に分岐する多くのCPUのような命令が表示されます。

  • 論理演算(AND、OR、NOT)、シフトビット、テストビットを実行する命令。CPUによっては、数学命令などのフラグに影響する場合があります。

  • 無条件にジャンプする命令。

  • スタック上のリターンアドレスをジャンプして保存する命令(「呼び出し」)、およびスタックからアドレスをポップする他の命令(「リターン」)。

  • CPUを停止する、CPUを識別する、または割り込みハンドラーを呼び出すなどの特別な命令。

  • 「操作なし」-ほとんどすべてのCPUには、サイクルを消費して先に進む「no-op」命令があります。

これは実際には単なる例であり、命令の種類が少ないCPUと命令が多いCPUがあります。

ポイントは、CPUには数学命令以外にも多くの種類の命令があることを示すことです。高級言語のすべては上記の操作のタイプに分類され、それらの一部のみが数学またはALUタイプの命令になります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.