VBAの勉強を始めてみた

色々試しています。

CPUよもやま話(レジスタとクロック)

前回までに「レジスタ」という単語が何回か出てきましたが、レジスタが何者なのかについてはほとんど書いていなかったので、ここらで書いておこうと思います。

 

なぜCPUの中にレジスタが必要なのか?

CPUの中にはデータを一旦保持するためのレジスタがいくつか入っています。で、なぜこのレジスタが必要なのかということなんですが・・・・・・料理にでも例えてみようと思います。
料理をする際は、食材をまな板の上に置いて包丁で切ったりすると思います(空中でも出来なくはないですが、置く場所がないととても不便です)。
食材は順次、冷蔵庫から取り出します。が、冷蔵庫に無いものはスーパーに買いに行くことになります。
ということで、こんな感じで例えてみました。

  • 食材:データ
  • まな板:レジスタ
  • 冷蔵庫:メモリ
  • スーパー:HDD

 出来上がった料理は冷蔵庫に入れることもできるし、冷蔵庫からスーパーに売りに行くこともできます。・・・・・・って、そんなスーパーあるかい(@_@;)

この例え話なら

  • スーパー:CD-ROMまたはDVD-ROM

のほうがしっくりくるかもしれない。どっちにしても分かりにくかった人は無視して下さい。

 

レジスタの正体はDフリップフロップ

先ほども書きましたが、レジスタはデータを一旦保持するためのものです。データを保持するもので思い出されるのはフリップフロップですが、レジスタにはフリップフロップというものが使われていたりします。
フリップフロップは、クロックが立ち上がった瞬間の入力Dを出力Qに保持(次にクロックが立ち上がるまで)します。
真理値表

f:id:kouten0430:20190224135137p:plain

f:id:kouten0430:20190224135159g:plain

クロックに関係なく出力Qを保持したいのなら、下のように出力Qを入力Dへ直結します。

f:id:kouten0430:20190224135237g:plain

フリップフロップを、必要なbit数並べたものがレジスタです。

f:id:kouten0430:20190224135325p:plain

 

ADD A,B はどう実現するのか?

前回、アセンブリ言語について少し触れましたが、例えば ADD A,B のような処理はどのように行われるのでしょうか?

ADD A,B の処理内容は

です。

 回路図で書いてみましょう。(仮に、4bitCPUとする)

f:id:kouten0430:20190224135826p:plain

このように、レジスタA・レジスタBの出力を加算器の入力に接続し、加算器の出力をレジスタAの入力に戻します。レジスタBは値を保持するように、出力を入力に戻します。

次に動作を実験してみます。あらかじめ、レジスタAに1010、レジスタBに0101が保持されている状態から

ADD	A,B
ADD	A,B

を(つまり、ADD A,Bを2回)、Logisimでシミュレートしてみます。目で追えるように、クロックを0.25Hzで動作させるので刮目してご覧下さい。

f:id:kouten0430:20190224140226g:plain

解説

  1. 1行目のADD A,Bで1010+0101=1111となり、レジスタAの入力側に戻ります。
  2. 次のクロックで1111がレジスタAに保持されます。同時に、2行目のADD A,Bが実行されます。1111+0101=10100となるため、加算器の4ビット目から桁上がりが出力されています。
  3. 次のクロックで、0100(オーバーフローした出鱈目な値)がレジスタAに保持され、桁上がりはCフラグとして保持されます。

 

Cフラグを保持するのもDフリップフロップなので、クロックの立ち上がりで値を保持します。このフラグを参照して条件分岐させるなら、目的のフラグが保持されたクロックの立ち上がり(先のソースコードであれば直後の3行目)で実行する必要があります。クロックが進めば目的のフラグではなくなってしまうからです。

 

さて、少し脱線しましたが、これでADD A,Bを実行できる回路が分かりました。しかし、これでは回路が固定であるため、永遠にADD A,BしかできないCPUになってしまっています。
なので、転送元と転送先を切り替えることができる回路を追加しなければなりません。さらに言えば、その切り替えをプログラムで行えるようにする必要がある訳です。
(例えば、下のような命令ごとに回路を繋ぎかえできるようにしなければならない)

MOV	A,B	レジスタAのデータをレジスタBに転送
MOV	B,A	レジスタBのデータをレジスタAに転送
ADD	A,B	レジスタAとレジスタBの値を加算してから、レジスタAに転送
ADD	B,A	レジスタAとレジスタBの値を加算してから、レジスタBに転送
MOV	A,A	レジスタAのデータをレジスタAに転送(要するに自己保持)
MOV	B,B	レジスタBのデータをレジスタBに転送(要するに自己保持)

 

フリップフロップの中身

フリップフロップの実際の内部回路は複雑なので、単純化した図で表します。(本の受け売り)

f:id:kouten0430:20190224152704p:plain

クロックが0の時は、前段と後段では縁が切れ、後段だけで出力を自己保持しています。入力に変化があっても出力は保持されます。

f:id:kouten0430:20190224152733p:plain

クロックが1の時は、前段と後段が繋がります。前段で自己保持した出力を後段は素通しします。前段と入力とは縁が切れているので、入力に変化があっても出力は保持されます。

ここで、素朴な疑問・・・・・・。クロックが1になる瞬間の入力を出力に保持する訳ですが、クロックが1になると同時に(加算器などから)逆の値が入力にフィードバックされたらどうなるでしょう?1だと思ってたけどやっぱり0で・・・・・・、でもそれなら逆の逆の値がフィードバックされて・・・・・・堂々巡り?( ̄q ̄;)

という間抜けな考えをいだくのは私だけだと思いますが、この心配は要りません。

フリップフロップの入力から出力には遅延があり、さらに加算器の入力から出力にも遅延があり、さらに言えば電子が配線の中を移動する時間もあるので、厳密には同時ではありません。クロックの立ち上がりから少し遅れて、入力へのフィードバックがあると思えば良いのです。この時間は、人間の感覚からすれば限りなくゼロに近いけれど、ゼロではないということですね。