
| シリーズの一部 |
| 算術論理回路 |
|---|
| クイックナビゲーション |
コンピュータにおいて、算術論理ユニット(ALU)は、整数または2進数に対して算術演算とビット演算を実行する組み合わせ型デジタル回路です。[ 1 ] [ 2 ]これは、浮動小数点数を処理する浮動小数点ユニット(FPU)とは対照的です。ALUは、コンピュータの中央処理装置(CPU)、FPU、グラフィックス処理装置(GPU)など、多くの種類のコンピュータ回路の基本的な構成要素です。[ 3 ]
ALUへの入力は、演算対象となるデータ(オペランド)と、実行する演算を示すコード(オペコード)です。ALUの出力は、実行された演算の結果です。多くの設計では、ALUはステータス入力またはステータス出力、あるいはその両方を備えており、それぞれ前の演算または現在の演算に関する情報をALUと外部ステータスレジスタ間で伝達します。
ALUには様々な入力ネットと出力ネットがあり、これらはALUと外部回路間でデジタル信号を伝達するために使用される電気導体です。ALUが動作しているとき、外部回路はALUの入力に信号を入力し、それに応じてALUは出力を介して信号を生成し、外部回路に伝達します。
基本的なALUは、2つの入力オペランド(AとB)と結果出力(Y )で構成される3つの並列データバスを備えています。各データバスは、1つの2進整数を伝送する信号群です。通常、A、B、Yのバス幅(各バスを構成する信号数)は同一であり、外部回路(例えば、カプセル化されたCPUやその他のプロセッサ)のネイティブワードサイズと一致します。
オペコード入力は、ALUに演算選択コードを伝達するパラレルバスです。演算選択コードは、ALUが実行する算術演算または論理演算を指定する列挙値です。オペコードのサイズ(バス幅)は、ALUが実行できる演算の最大数を決定します。例えば、4ビットのオペコードは最大16個の異なるALU演算を指定できます。一般的に、ALUオペコードは機械語命令とは異なりますが、場合によっては、機械語命令内のビットフィールドとして直接エンコードされることもあります。
ステータス出力は、現在のALU演算結果に関する補足情報を伝える様々な個別信号です。汎用ALUは一般的に、次のようなステータス信号を備えています。
ステータス入力は、演算実行時に追加情報をALUに提供することを可能にします。通常、これは1つの「キャリーイン」ビットであり、これは前回のALU演算から保存されたキャリーアウトです。

ALUは組み合わせ論理回路であり、入力の変化に応じて出力が非同期的に変化します。通常動作では、すべてのALU入力に安定した信号が供給され、信号がALU回路を伝播するのに十分な時間(「伝播遅延」と呼ばれる)が経過すると、ALU演算の結果がALU出力に表示されます。ALUに接続された外部回路は、演算全体を通してALU入力信号の安定性を確保し、ALU出力をサンプリングする前に信号がALU回路を伝播するのに十分な時間を確保する役割を果たします。
一般的に、外部回路はALU入力に信号を適用することでALUを制御します。通常、外部回路はシーケンシャルロジックを用いてALUの動作を制御する信号を生成します。外部シーケンシャルロジックは、最悪条件(つまり、伝播遅延が最大となる条件)においてALU出力が安定するのに十分な時間を確保するために、十分に低い周波数の クロック信号によって制御されます。
たとえば、CPU は、オペランドをそのソース (通常はプロセッサ レジスタ) から ALU のオペランド入力にルーティングし、同時に加算演算を実行するように ALU のオペコード入力に値を適用することで加算演算を開始します。同時に、CPU は演算完了時に ALU 出力 (加算演算の結果の合計) を宛先レジスタに格納できるようにします。ALU の入力信号は次のクロックまで安定状態に保持され、CPU が次のクロックを待機する間に ALU を介して宛先レジスタに伝播されます。次のクロックが到着すると、宛先レジスタに ALU 結果が格納され、ALU 演算が完了しているため、ALU 入力は次の ALU 演算用にセットアップされます。
ALUは、多くの基本的な算術演算とビット論理演算を一般的にサポートしています。基本的な汎用ALUは、通常、以下の演算をそのレパートリーに含んでいます。[ 1 ] [ 2 ] [ 4 ]
| タイプ | 左 | 右 |
|---|---|---|
| 算術シフト | ||
| 論理的変化 | ||
| 回転 | ||
| キャリーを通して回転する |
ALUシフト演算は、オペランドA(またはB)を左または右(オペコードによって異なります)にシフトし、シフトされたオペランドはYに格納されます。単純なALUは通常、オペランドを1ビット位置だけシフトできますが、より複雑なALUではバレルシフタを使用することで、1回の演算で任意のビット数だけオペランドをシフトできます。すべてのシングルビットシフト演算において、オペランドからシフトアウトされたビットはキャリーアウトに出力されます。オペランドにシフトインされるビットの値は、シフトの種類によって異なります。

各ALU演算が完了すると、ALUのステータス出力信号は通常、外部レジスタに保存され、将来のALU演算(例えば、多倍長演算の実装)や条件分岐の制御に利用できるようになります。ステータス出力信号を保存するビットレジスタは、多くの場合、単一のマルチビットレジスタとしてまとめて扱われ、「ステータスレジスタ」または「条件コードレジスタ」と呼ばれます。
実行されるALU演算によっては、ステータスレジスタの一部のビットが変更され、他のビットは変更されない場合があります。例えば、ANDやORなどのビット単位の論理演算では、キャリーステータスビットはこれらの演算には関係がないため、通常は変更されません。
CPUでは、格納されたキャリーアウト信号は通常、ALUのキャリーインネットに接続されます。これにより、倍精度演算を実行する際に、キャリー(加算のキャリー、減算のボロー、またはシフトオーバーフローを表す)の効率的な伝播が容易になり、キャリーの伝播をソフトウェアで管理する必要がなくなります(キャリーステータスビットに基づく条件分岐経由)。

ALUオペランドのソースとALU結果のデスティネーションは、カプセル化プロセッサのアーキテクチャと実行される演算によって異なります。プロセッサアーキテクチャは多岐にわたりますが、汎用CPUでは、ALUは通常、レジスタファイル(プロセッサレジスタの配列)またはアキュムレータレジスタと組み合わせて動作し、ALUはこれらをオペランドのソースと結果のデスティネーションの両方として頻繁に使用します。他のオペランドソースに対応するために、各マシン命令の要件に応じてレジスタファイルまたは代替ALUオペランドソースを選択するマルチプレクサが一般的に使用されます。
例えば、右に示すアーキテクチャは、2つの読み出しポートを持つレジスタファイルを採用しており、任意の2つのレジスタ(または同じレジスタ)に格納された値をALUオペランドとして使用できます。また、ALUオペランドを即値オペランド(機械命令[ 5 ]に直接エンコードされた定数値)またはメモリから取得することもできます。ALUの結果は、レジスタファイル内の任意のレジスタまたはメモリに書き込むことができます。
整数演算において、倍精度演算はALUワードサイズよりも大きな整数を演算するアルゴリズムです。このアルゴリズムでは、各整数をALUサイズのフラグメントの集合として扱い、最上位(MS)から最下位(LS)へ、またはその逆の順序で並べます。例えば、8ビットALUの場合、24ビット整数は3つの8ビットフラグメント(MS)、、LS )0x123456の集合として扱われます。フラグメントのサイズはALUワードサイズと正確に一致するため、ALUはこのオペランドの「断片」を直接演算できます。 0x120x340x56
このアルゴリズムは、ALUを用いて特定のオペランドフラグメントを直接演算し、多倍長精度演算結果の対応するフラグメント(「部分」)を生成します。生成された各部分は、多倍長精度演算結果を格納するために指定された記憶領域に書き込まれます。この処理はすべてのオペランドフラグメントに対して繰り返され、多倍長精度演算の結果である部分値の完全な集合が生成されます。
算術演算(加算、減算など)では、アルゴリズムはまずオペランドの LS フラグメントに対して ALU 演算を呼び出し、LS 部分ビットとキャリーアウトビットの両方を生成します。アルゴリズムは部分を指定されたストレージに書き込み、プロセッサのステートマシンは通常、キャリーアウトビットを ALU ステータスレジスタに格納します。次に、アルゴリズムは各オペランドのコレクションの次のフラグメントに進み、これらのフラグメントと、前回の ALU 演算で格納されたキャリービットに対して ALU 演算を呼び出し、別の(より上位の)部分ビットとキャリーアウトビットを生成します。前と同様に、キャリービットはステータスレジスタに格納され、部分は指定されたストレージに書き込まれます。このプロセスは、すべてのオペランドフラグメントが処理されるまで繰り返され、結果として、多重精度演算結果を構成する部分の完全なコレクションがストレージに生成されます。
倍精度シフト演算では、オペランドフラグメントの処理順序はシフト方向によって異なります。左シフト演算では、各部分のLSビット(格納されたキャリービットを介して伝達される)は、直前に左シフトされた下位オペランドのMSビットから取得する必要があるため、フラグメントはLSファーストで処理されます。一方、右シフト演算では、各部分のMSビットは、直前に右シフトされた上位オペランドのLSビットから取得する必要があるため、オペランドはMSファーストで処理されます。
ビット単位の論理演算(論理 AND、論理 OR など)では、各部分は対応するオペランド フラグメントにのみ依存するため、オペランド フラグメントは任意の順序で処理される可能性があります(前の ALU 演算から格納されたキャリー ビットは無視されます)。
2進固定小数点値は整数で表されます。したがって、特定の固定小数点スケール係数(または暗黙の基数位置)において、ALUは2つの固定小数点オペランドを直接加算または減算し、固定小数点の結果を生成することができます。この機能は、固定小数点と浮動小数点の両方の加算と減算で一般的に使用されます。
浮動小数点加算および減算では、小さい方のオペランドの仮数は右シフトされ、その固定小数点スケール係数が大きい方のオペランドの仮数と一致するようになります。次に、ALUは位置合わせされた仮数を加算または減算して、結果の仮数を生成します。結果の仮数は、他のオペランド要素と共に正規化および丸められ、浮動小数点の結果が生成されます。
複雑な機能を実行できるALUを設計することは可能ですが、回路の複雑さ、消費電力、伝播遅延、コスト、サイズの増加により、通常は現実的ではありません。そのため、ALUは通常、非常に高速(つまり、伝播遅延が非常に短い)で実行できる単純な機能に限定され、より複雑な機能はソフトウェアまたは外部回路によって実行されます。例えば、
グラフィックス・プロセッシング・ユニット(GPU)には、数百または数千の同時実行可能なALUが搭載されていることがよくあります。アプリケーションとGPUアーキテクチャに応じて、ALUは無関係なデータを同時に処理したり、関連するデータを並列処理したりするために使用されます。後者の例としては、グラフィックス・レンダリングが挙げられます。この処理では、複数のALUがピクセルのグループに対して同じ演算を並列に実行し、各ALUはシーン内の1つのピクセルに対して演算を実行します。[ 6 ]
ALUは通常、74181のようなスタンドアロンの集積回路(IC)として実装されるか、より複雑なICの一部として実装されます。後者の場合、ALUは通常、VHDL、Verilog、またはその他のハードウェア記述言語で記述された記述から合成することでインスタンス化されます。例えば、次のVHDLコードは非常に単純な8ビットALUを記述しています。
エンティティaluはport ( -- 外部回路への alu 接続: A : in signed ( 7 downto 0 ); -- オペランド A B : in signed ( 7 downto 0 ); -- オペランド B OP : in unsigned ( 2 downto 0 ); -- オペコードY : out signed ( 7 downto 0 )); -- 演算結果end alu ;aluのアーキテクチャの動作は、 begin case OPです。--オペコードをデコードして演算を実行します。"000" => Y <= A + Bの場合、加算します。"001" => Y <= A - Bの場合、減算します。"010" => Y <= A - 1の場合、減算します。"011" => Y <= A + 1の場合、増分します。"100" => Y <= not Aの場合、1の補数をとります。 "101" => Y <= A and Bの場合、ビット単位 AND をとります。"110" => Y <= A or Bの場合、ビット単位 OR をとります。"111" => Y <= A xor Bの場合、ビット単位 XOR をとります。その他の場合、Y <= (その他=> 'X' )、end case 、動作の終了。数学者ジョン・フォン・ノイマンは1945年にEDVACと呼ばれる新しいコンピュータの基礎に関する報告書の中でALUの概念を提唱した。[ 7 ]
情報化時代の黎明期において、電子回路のコスト、サイズ、そして消費電力は比較的高かった。そのため、初期のコンピュータはすべて、一度に1ビットのデータを処理するシリアルALUを搭載していたが、プログラマにとってはワードサイズが大きすぎるという問題もあった。複数の並列で個別のシングルビットALU回路を搭載した最初のコンピュータは、1951年に登場したWhirlwind Iで、16ビットワードの処理を可能にするために、このような「演算ユニット」を16個搭載していた。
1967年、フェアチャイルドは、8ビットの演算ユニットとアキュムレータを備えた、集積回路として実装された最初のALU型デバイス、フェアチャイルド3800を発表しました。このデバイスは加算と減算のみをサポートし、論理機能はサポートしていませんでした。[ 8 ]
完全な集積回路ALUはすぐに登場し、 Am2901や74181といった4ビットALUも登場しました。これらのデバイスは典型的には「ビットスライス」に対応しており、「キャリー・ルック・アヘッド」信号を備えていました。これにより、複数のALUチップを相互接続することで、より広いワードサイズのALUを構成することができました。これらのデバイスは急速に普及し、ビットスライス・ミニコンピュータで広く使用されました。
マイクロプロセッサは1970年代初頭に登場し始めました。トランジスタは小型化していましたが、フルワード幅のALUを搭載するにはダイスペースが不足することがあり、その結果、初期のマイクロプロセッサの中には、機械語命令ごとに複数サイクルを必要とする狭いALUを採用したものもありました。その例として、人気のあったZilog Z80が挙げられます。Z80は、4ビットのALUで8ビットの加算を実行していました。[ 9 ]その後、ムーアの法則に従ってトランジスタのサイズはさらに縮小し、マイクロプロセッサ上により広いALUを搭載することが可能になりました。
現代の集積回路(IC)のトランジスタは、初期のマイクロプロセッサに比べて桁違いに小型化されており、非常に複雑なALUをICに搭載することが可能になっています。今日では、多くの最新のALUは広いワード幅と、バレルシフタやバイナリ乗算器といったアーキテクチャ上の強化により、以前のALUでは複数回の演算を必要としていた演算を1クロックサイクルで実行できるようになりました。
ALUは機械回路、電気機械回路、電子回路として実現することができ[ 10 ]、近年では生物学的ALUの研究が行われています[ 11 ] [ 12 ](例えば、アクチンベース)。[ 13 ]