CPUの演算処理を司るALUの仕組み


はじめに

プログラムを実行するハードウェアのお話です。
CPU演算の核となるALUの仕組みについて学習したので共有します。

背景

自分の書いたプログラミングって実行した後どう動いているんだろう?
という疑問から低レイヤーの勉強を始めました。

もともと電気系の大学を出ており、ファームウェア周りも触ったことがあったので多少の知識はあったのですが
高級言語からビット演算までの一連の流れを理解したいと思い学習を始めました。

参考図書

ほぼこれから勉強したといっても過言ではないので、末尾ではなくここに参考文献を書いておきます。
コンピュータシステムの理論と実装

※著作権の違反にならないようあくまで自分のアウトプットの記載として書いているつもりですが、アウト,グレーな部分があったらご指摘お願いします。

ALUとは

ALUとは算術論理演算器です。
ALUはハードウェア上で実装される装置であり、演算処理の役割を担います。

ALUの中身としてはトランジスタなどの電子素子が多く含まれている電子素子です。
もう少し粗くみればAND回路やOR回路などから構成されています。

CPUがレジスタから情報を読み取って演算処理をする。という流れは割と知られていると思いますが、
この「CPUが演算処理をする」の部分は、ALUという装置が頑張ってくれているおかげで実現できています。

この演算処理の中心となるALUがどのように出来上がっているかを見ていきます。

ALUの構造

ALUの根本的な動作は「InputしたものをALUの内部で演算処理し、Outputする」という基本的なものです。
この時Inputはレジスタから読み取った情報で、それを演算してレジスタに結果を書き込む、という流れになります。

ただこれだとALUは1種類の演算しか行えません。
2つの入力を足し算するだけのコンピュータのできあがりです。
そこでこのALUにセレクターという要素を加えてあげます。

このSelectorはALUがInputA,Bに対してどのような処理を行うかを選択するための入力です。

例えば、
selectorの値が[0000]だった場合はOutput = InputA & InputB
selectorの値が[0101]だった場合はOutput = InputA + 1
...
といった感じになります。

今回Selectorは4ビット1なので、2^4=16パターンの値をとることができ、ALUはInputに対して16パターンの計算を行うことができます。

自分は高級言語でいうところのswitch文のようなイメージであると感じました。
低レイヤーの話をしているのに、高級言語で例えるのはナンセンスかもしれませんが...。

switch(selector){
    case 0000:
        Output = InputA & InputB;
        break;
    case 0101:
        Output = InputA + 1;
        break;

おそらく実際のALUはSelectorのビット数がもっと大きいのですが、今回は説明のために簡素化しています。2

このようにSelectorの入力を変化させることにより、ALUが入力に対してどのような演算を行うかを切り替えられます。
そしてこの演算処理を切り替えることを実現するのに重要となるのが、ALU内に含まれるマルチプレクサという装置となります。

マルチプレクサ

マルチプレクサは以下のような図で描かれます。

入力があり、セレクタがあり、Outputがあり...、先ほど示したALUの図と似たような図です。
selectorの端子は1ビット入力であり、

if selector = 0 then Output = InputA
if selector = 1 then Output = InputB

という出力になります。

このマルチプレクサ装置1個では2パターンの切り替えしかできませんが、ALUの内部にはマルチプレクサが複数個用意されています。
先ほど示したALUには4ビットのSelectorの入力がされていましたが、ALUの内部ではそれらが1ビットずつに分解され、個々のマルチプレクサのSelectorの入力となります。

ALUの処理の実現

どのようにして処理を切り替えているかはなんとなくつかめたと思うので、演算をどう実現しているかについて少し説明したいと思います。

例えばALUがこのような回路だとします。(この図は回路が不足しており不正確です。イメージ図としてご覧ください)

例えば
Outputの値をRegA&RegBとしたい場合

  1. OutputXの値がRegAとなるようにSelectorXの値を設定します。
  2. OutputYの値がRegBとなるようにSelectorYの値を設定します。
  3. Outputの値がRegA & RegBとなるようにSelectorZの値を設定します。

Outputの値を1+RegBとしたい場合

  1. OutputXの値が1となるようにSelectorXの値を設定します。
  2. OutputYの値がRegBとなるようにSelectorYの値を設定します。
  3. Outputの値が1+RegBとなるようにSelectorZの値を設定します。

といった感じで、この回路1つで様々な演算処理が実現できます。

ただし上にも書きましたが、この図の回路は素子が不足しており正常に動作しません。
具体的にはすべての演算処理をカバーできていません。
本当はNOT回路なども含める必要があるのですが、ちょっとそこまで書くのはしんどいので今回は省略します。

補足

ちなみに余談ですが、マルチプレクサやALU自体もNAND回路1種類で構成することが可能です。

これが最初に紹介した、コンピュータシステムの理論と実装の本質部分でもあり、
書籍の中には開発環境や、ヒントなどもたくさん用意されているため自分で実際にALUを実装することができました。

自分で実装するとより理解が深まるので、興味ある方は実際に実装してみることをおすすめします。

結論

  • ALUは一つの装置でありながら、入力に対して様々な演算処理を行うことが可能である。
  • その処理の切り替えを行っているのがマルチプレクサという装置である。
  • マルチプレクサとAndやOrなどの論理ゲートを組み合わせることで、様々な演算を実現している。
  • ALUの回路はNAND回路1種類だけで構成可能である。

まとめ

今回はALUがどのような仕組みで動いており、どのように構成されているかの概要を記してみました。
これから徐々に上のレイヤに昇っていく流れとなるので、またアウトプットしていきたいと思います。


  1. おそらくですが、このSelectorのビット数に関してはハードウェアのプラットフォームに依存するものだと思うので、あくまで今回は4ビットと仮定した場合で話をしています。 

  2. また、書籍ではOutputの出力のほかにOutputの値が0の時に1となる出力端子などの記載がありましたが、これらの用途に関してはまだ不明なため今後の課題としたいと思います。→判明しました。「コンピュータシステムの理論と実装」に載ってたCPUを実装してみるに記載