Feel Physics Backyard

HoloLensの出張授業をする会社で、教材を開発しています

『CPUの創り方』によるCPUのしくみ入門 回路シミュレータを使って

CPUのしくみ入門

『CPUの創り方』という本がある。

 

CPUのしくみを理解し、シンプルなCPUをつくりましょう、という本である。

だが文中で著者も言っているように、CPUを自作するにはかなりの配線作業が必要になる。

そこで私は友人@su_exsさんに教えてもらった「源内CAD」というデジタル回路シミュレータを使い、CPUをつくってみることにした。

なお今回の作業では源内CAD支援コンテンツの標準ロジックIC一覧が大変参考になった。この場を借りてお礼です。 

まずは源内CADの使用上の注意点。

(1)下位のシミュレーションをしないと、その回路記号を使ったシミュレーションができない

(2)クロック非同期回路でのパターン入力には、遅延を考慮する

(3)削除コマンドの癖。キャンセルしないと大事な回路記号まで削除してしまう

それでは始めて行きましょう。

【書籍160ページ】

まずは単純なフリップフロップから試す。これはCPUのレジスタに使われている素子で、値を保持するのに使われる。

ダウンロード 120324-test01.gdr (0.7K)

フリップフロップ初動作

まずはフリップフロップ初動作

フリップフロップの動作確認 

フリップフロップの動作確認

クロックがHiになるたびにフリップフロップの出力がHiとLoで入れ替わる 

クロックがHiになるたびにフリップフロップの出力がHiとLoで入れ替わる

【書籍176ページ】

データセレクタ これも作るw 

データセレクタ これも作るw

データセレクタ製作中 

データセレクタ製作中

データセレクタ完成! 

データセレクタ完成!(うそ。一部未完。)

ダウンロード dataSelector.gdr (2.6K) 

シンボルに登録して再利用可能にする 

シンボルに登録して再利用可能にする

登録して使えるようになった 

登録して使えるようになった

こちらはデータセレクタ S0とS1がともにLoだと・・・ 

こちらはデータセレクタ S0とS1がともにLoだと・・・

ダウンロード dataSelector.gdr (2.6K) 

このAND素子だけがはたらいて・・・

このAND素子だけがはたらいて・・・

このI0の入力だけが出力され、他の入力は捨てられる 

このI0の入力だけが出力され、他の入力は捨てられる

S0がLo、S1がHiだと・・・

S0がLo、S1がHiだと・・・

このAND素子だけがはたらくので・・・ 

このAND素子だけがはたらくので・・・

入力I2だけが出力に反映されて、あとの入力は捨てられる 

入力I2だけが出力に反映されて、あとの入力は捨てられる

【書籍185ページ】

74HC161の回路図 うへえ 

74HC161の回路図 うへえ

ダウンロード 4bitfullAdder0.gpt (0.3K) 

ちなみに中身はこんな感じ 

ちなみに中身はこんな感じ(@su_exs氏作成)

矢印のか所が全部Hiだと・・・ 

矢印のか所が全部Hiだと・・・

ここに集まって桁が上がるはずなのだが・・・ 

ここに集まって桁が上がるはずなのだが・・・

ここでGNDで殺しているので桁上がりは起きないです 

ここでGNDで殺しているので桁上がりは起きないです

CLR#がLoだと・・・ 

CLR#がLoだと・・・

これらのAND素子にLoが入力されるので・・・ 

これらのAND素子にLoが入力されるので・・・

すべてのフリップフロップにLoが入力されることになります 

すべてのフリップフロップにLoが入力されることになります

LOAD#がLoだと・・・ 

LOAD#がLoだと・・・

これらのAND素子がはたらいて入力ABCDがフリップフロップに入力される 

これらのAND素子がはたらいて入力ABCDがフリップフロップに入力される

逆にLOAD#がHiだと・・・ 

逆にLOAD#がHiだと・・・

こちら側のAND素子がはたらいて現状の状態を維持する 

こちら側のAND素子がはたらいて現状の状態を維持する

左から順にABCDにHiをセットしている 

左から順にABCDにHiをセットしている

左から順にABCDがHiにセットされている

左から順にABCDがHiにセットされている

【書籍191ページ】

ダウンロード 1bitCPU.gdr (9.9K) 

ダウンロード 1bitCPU0.gpt (0.5K) 

ダウンロード 74hc161.gdr (8.5K) 

ダウンロード 120324-RegisterSelecterTest-120326-1700.gdr (10.0K) 

ダウンロード 120324-test04.gdr (1.7K) 

4つのレジスタと4bitのデータセレクタを接続 

4つのレジスタと4bitのデータセレクタを接続

こちらがレジスタ 

こちらがレジスタ

こちらがデータセレクタ 

こちらがデータセレクタ

あとでプログラムカウンタとして使うため、レジスタのカウンタ機能を復活させる

あとでプログラムカウンタとして使うため、レジスタのカウンタ機能を復活させる

レジスタにHLLL、LHLL、LLHL、LLLHをLOADしてみると、うまくいっている 

レジスタに0001、0010、0100、1000をLOADしてみると、うまくいっている

フリップフロップが1つだけの1bitCPU 

ここでフリップフロップが1つだけの1bitCPUをつくってみた。

ダウンロード 120326-1bitResister.gdr (1.8K) 

処理はそのまま転送か反転の2種類だけ 

処理はそのまま転送か反転の2種類だけ

この部分の入力がHならただの転送で、Lなら反転になる 

この部分の入力がHならただの転送で、Lなら反転になる

矢印のところで下のQ#が反転している 

矢印のところで下のQ#が反転している

ダウンロード 120326-1bitResister0.gpt (0.2K) 

レジスタとデータセレクタのテストをしてみるため、4つめのレジスタに直接入力を付ける 

レジスタとデータセレクタのテストをしてみるため、4つめのレジスタに直接入力を付ける

ダウンロード 120324-RegisterSelecterTest-120326-17000.gpt (0.5K) 

まずレジスタ4に1010を入力し・・・ 

まずレジスタ4に0101を入力し・・・

ここですね・・・ 

ここですね・・・

セレクタで転送元をレジスタ4に設定し・・・ 

セレクタで転送元をレジスタ4に設定し・・・

レジスタ1だけ転送を受け入れる(LOAD)ようにすると・・・ 

レジスタ1だけ転送を受け入れる(LOAD)ようにすると・・・

レジスタ1に1010が入力されています(図はQ#なので反転して0101になっています) 

レジスタ1に0101が入力されています(図はQ#なので反転して1010になっています)

次の転送元はレジスタ1で・・・ 

次の転送元はレジスタ1で・・・

転送先はレジスタ2です 

転送先はレジスタ2です

レジスタ2に1010が入力されたことがわかります 

レジスタ2に0101が入力されたことがわかります

最後はレジスタ2の内容をレジスタ3に転送します 

最後はレジスタ2の内容をレジスタ3に転送します

レジスタ3に1010が入力されました 

レジスタ3に0101が入力されました

これは桁上り(Cin)を込みにした全加算器 

これは桁上り(Cin)を込みにした全加算器

ダウンロード fullAdder.gdr (3.9K) 

入力Aと入力BがH、桁上り入力CinがLのときは・・・ 

入力Aと入力BがH、桁上り入力CinがLのときは・・・

このANDゲートがHを出力して桁が上がる(C) 

このANDゲートがHを出力して桁が上がる(C)

AだけHの場合は・・・ 

AだけHの場合は・・・

このANDゲートがHを出力する(S) 

このANDゲートがHを出力する(S)

A+BがSと桁上りのCに反映されている 

A+BがSと桁上りのCに反映されている

先ほどの1bit全加算器を4個つなげると、4bit全加算器 

先ほどの1bit全加算器を4個つなげると、4bit全加算器

ダウンロード 4bitfullAdder.gdr (2.2K) 

0001+0001=0010、0010+0010=0100、0100+0100=1000、1000+1000はC出力、Cinのみは0001 

0001+0001=0010、0010+0010=0100、0100+0100=1000、1000+1000はC出力、Cinのみは0001

ダウンロード 4bitfullAdder0.gpt (0.3K) 

レジスタ+セレクタ、にALU(4bit全加算器)をつなげた 

レジスタセレクタ、にALU(4bit全加算器)をつなげた

ダウンロード 120327-AluTest.gdr (11.3K) 

4つめのレジスタに0001をセットして1つめのレジスタに転送し、 

4つめのレジスタに0001をセットして1つめのレジスタに転送し、

ダウンロード 120327-AluTest0.gpt (0.6K) 

0001+0001=0010 

0001+0001=0010

0010+0101=0111 

0010+0101=0111

0111+0001=1000 

0111+0001=1000

キャリーフラグとデコーダをつくり、4bitCPUを完成させます。

キャリーフラグをALUに接続する 

キャリーフラグをALUに接続する

ダウンロード 120329-FragTest.gdr (11.8K) 

1111に0001を足すと、CF出力がHになる 

1111に0001を足すと、CF出力がHになる

ダウンロード 120329-FragTest0.gpt (0.5K) 

出力(上)と入力(下)を付ける

出力(上)と入力(下)を付ける

ダウンロード 120329-OutTest.gdr (12.2K) 

上から入力3、加算2、出力5

上から入力3、加算2、出力5

ダウンロード 120329-OutTest0.gpt (0.6K) 

デコーダ回路をつなげる

デコーダ回路をつなげる

うまく動かなかったのでLOAD0~3とセレクタを出力してみたら、セレクタのつなぎ方が間違っていたことが判明

うまく動かなかったのでLOAD0~3とセレクタを出力してみたら、セレクタのつなぎ方が間違っていたことが判明。

ダウンロード 120329-DecoderTest-120404.gdr (14.7K) 

4bitのオペレーションコードを入力して、それが正確に動作しているかを見てみると・・・

 4bitのオペレーションコードを入力して、それが正確に動作しているかを見てみると・・・

ダウンロード 120329-DecoderTest-1204040.gpt (0.7K) 

正常に動いています。長い旅が終わりました・・・

正常に動いています。長い旅が終わりました・・・ 

最後に、問題が起こるたびにいつも正確無比なアドバイスをくれた@su_exsくんに感謝して、このシリーズを終わります。ここまで読んでくださって、ありがとうございました。