Open33

100日後に完成するCPU 作業メモ

tomo_makestomo_makes

モチベーション

目次

Week 1

  • Day 1 logisim-evolutionのインストール
  • Day 2 ANDゲート、ORゲートの動作を試してlogisimに慣れる
  • Day 3 真理値表の確認と回路の自動生成
  • Day 4 組合せ回路 - 桁上がりを考慮しない半加算器を作ってみよう
  • Day 5 組合せ回路 - 4 bitの加算回路を作ってみよう
  • Day 6 組合せ回路 - 3 bit加算回路と10進数の7セグLED表示で簡易電卓に仕上げる
  • Day 7 順序回路の導入 - Dフリップフロップに挑戦

Week 2

  • Day 8 順序回路 - SRラッチ、DラッチからDフリップフロップまでをおさらい
  • Day 9 組合せ回路+順序回路 - 3bit加算回路の電卓にメモリ機能を加える
  • Day 10 命令セット (ISA) に想いを馳せる
  • Day 11 ADD, NOP 2命令を持つCPUみたいなものができた
  • Day 12 レジスタ2つの入出力を、マルチプレクサで切り替える (失敗)
  • Day 13 2つの命令、4つのステップで「111-11」の引き算をする
  • Day 14 プログラムの手動実行から自動実行へ - ROMの仕組みを知ろう

Week 3

  • Day 15 ROMにプログラムを書き込み、カウンタと接続する
  • Day 16 プログラムを自動実行するには - 「111-11」を永遠に計算し続ける機械

GitHub

  • TBD

参考文献、書籍

YouTube

tomo_makestomo_makes

Day 5 組合せ回路 - 4 bitの加算回路を作ってみよう

tomo_makestomo_makes

加算器の派生として、ALUに入る前に、1の補数やそれを作る回路に触れておきたい。
(CODE 第1版 13章参照)

tomo_makestomo_makes

Day 6 組合せ回路 - 3 bit加算回路と10進数の7セグLED表示で簡易電卓に仕上げる

tomo_makestomo_makes

7セグメントLEDデコーダは、logisimで真理値表から論理回路を自動生成する機能を使って作った。
真理値表はせっかくなのでと手打ちしてみた。これをtxtファイルとしてlogisimにインポートできる。

# Truth table
# 4 bit to 7 segment display

d c b a | A B C D E F G
~~~~~~~~~~~~~~~~~~~~~~~
0 0 0 0 | 1 1 1 1 1 1 0
0 0 0 1 | 0 1 1 0 0 0 0
0 0 1 0 | 1 1 0 1 1 0 1
0 0 1 1 | 1 1 1 1 0 0 1
0 1 0 0 | 0 1 1 0 0 1 1
0 1 0 1 | 1 0 1 1 0 1 1
0 1 1 0 | 1 0 1 1 1 1 1
0 1 1 1 | 1 1 1 0 0 0 0
1 0 0 0 | 1 1 1 1 1 1 1
1 0 0 1 | 1 1 1 1 0 1 1
1 0 1 0 | 1 1 1 1 1 1 0
1 0 1 1 | 0 1 1 0 0 0 0
1 1 0 0 | 1 1 0 1 1 0 1
1 1 0 1 | 1 1 1 1 0 0 1
1 1 1 0 | 0 1 1 0 0 1 1
1 1 1 1 | 1 0 1 1 0 1 1

視認性のため、入力を d, c, b, a と並べたがこれでよかったかどうか。
最初は4bit加算回路と対応する7セグメントLED 多桁表示をするつもりだったけど、10の位を簡易に 0,
表示切り替える以上の時間が取れなかったので、3bit加算回路にしておいた。

tomo_makestomo_makes

Day 7 順序回路の導入 - Dフリップフロップに挑戦

tomo_makestomo_makes

クロック立ち上がり時の入力が保持されます。ただ立ち上がり、立ち下がりといった状態遷移以外でも出力が変化してしまっているようです。これで正しいのかな。

ここの問いは、クロックをパルスで供給していなかったため、振る舞いとしては正しかった。
ただ、CPUとして使う際にはパルスとして供給するべきだった。Day 8を参照。

tomo_makestomo_makes

クロックを動かしてのシミュレーション開始には、左から1番目、3番目のボタンを押す。

tomo_makestomo_makes

Day 8 順序回路 - SRラッチ、DラッチからDフリップフロップまでをおさらい

tomo_makestomo_makes

Day 7からはいよいよ順序回路に入った。
ラッチ、フリップフロップの理解があいまいなまま、なんとなくDフリップフロップらしいものを作ろうとしてしまったので、Day 8でおさらいすることに。
ブレッドボード 8bit CPU製作者のBen Eater氏のチュートリアルを見返す。今後の設計指針に、他も参考に見返しておきたい。
また発振回路やラッチ、フリップフロップにおいて、「出力を入力に戻すという形態」で、「各ゲートの動作時間」をうまく使っていることをおさえておきたい。

https://eater.net/8bit

https://www.youtube.com/watch?v=KM0DdEaY5sY

https://www.youtube.com/watch?v=peCh_859q7Q

https://www.youtube.com/watch?v=YW-_GkUguMM

tomo_makestomo_makes

logisimの Simulate > Timing diagram で見られるタイミングチャートは、複数のLogging Modeがある。 Continuous real-time mode にすると、クロックのパルス間で入力を変化させた時の様子も観察できる。

tomo_makestomo_makes

Day 9 組合せ回路+順序回路 - 3bit加算回路の電卓にメモリ機能を加える

tomo_makestomo_makes

回路図を書き出す

logisim-evolutionのメニューから、 File > Export Image で回路図を書き出してみる。

Half Adder

Full Adder

7 Segment LED Decoder

3-bit Adder with Storage Registers and 7 Segment LED

tomo_makestomo_makes

Day 10 命令セット (ISA) に想いを馳せる

https://x.com/tomo_makes/status/1762123076039508323?s=20

tomo_makestomo_makes

4-bit CPU TD4

『CPUの創りかた』(https://amzn.to/49OKQVK) が初出、自作例が多くネット上にあり、最近では『作ろう! CPU』(https://amzn.to/49rt3nv) に取り上げられています。

8-bit CPU P08

Qiita記事『コンピュータの動作原理』(https://qiita.com/niQSun/items/4d92eab8cce210db4b77) に見つけました。

MIPS

『コンピュータの構成と設計』 (https://amzn.to/439sFbj) いわゆるパタヘネ本の第6版MIPS Editionで詳解。

RISC-V (RV32I)

『RISC-VとChiselで学ぶ はじめてのCPU自作』(https://amzn.to/3SPe8N7) がドンピシャです。

tomo_makestomo_makes

Day 12 レジスタ2つの入出力を、マルチプレクサで切り替える (失敗)

tomo_makestomo_makes
ADD A, im(任意の数a)
INV B, A
ADD B, 1
ADD B, im(任意の数b)

としたら、aの2の補数が取れて、それをbに加算することでb-aが計算できるのでは? と考えたけれど、そこまでは到達できなかった。
エラーの原因が回路の問題か、logisim自体のシミュレーションの問題なのか切り分けが必要。

tomo_makestomo_makes

エラーの理由が分かった。Dフリップフロップで作ったレジスタA、レジスタBに常にクロックを供給していたので、手前のデマルチプレクサの切替えで信号が来ていない時にも、レジスタの書き換え (入力が0なのでリフレッシュ) していた。
クロック供給も、デマルチプレクサの切替えに同期して、有無を制御すれば直る。

INV、ADD 2つの組合せ回路、A、Bの2レジスタを持ち、即値を与えることもできるとすると、

INV A, B
INV B, A
ADD A, im # A = A + im だけでなく A = B + imも可能
ADD B, im # B = B + im だけでなく B = A + im も可能
MOV A, B
MOV B, A

の少なくとも6命令が与えられることになる。

そして、命令、Distination Operand、Source Operandそれぞれを1 bitで指定しているので、

INV A, B # 001
INV B, A # 010
ADD A, im # 100
ADD B, im # 111
MOV A, B # 101 (im = 0)
MOV B, A # 110 (im = 0)

こうした3bitの命令とオペランド指定となる。

tomo_makestomo_makes

Day 13 2つの命令、4つのステップで「111-11」の引き算をする

tomo_makestomo_makes

以下4つの命令を実行した。

ADD A, A, 0011
INV B, A
ADD A, B, 0001
ADD A, A, 0111

ビット列とすると以下になる。

1 0 0 0011
0 1 0 0000
1 0 1 0001
1 0 0 0111
tomo_makestomo_makes

Day 15 プログラムを自動実行するには - ROMにプログラムを書き込み、カウンタと接続する

tomo_makestomo_makes

以下4つの命令に加え、何もしない (0を足す) 命令を4ステップ埋めると良さそう。

ADD A, A, 0011
INV B, A
ADD A, B, 0001
ADD A, A, 0111
ADD A, A, 0000
ADD A, A, 0000
ADD A, A, 0000
ADD A, A, 0000

ビット列とすると以下になる。

1 0 0 0011
0 1 0 0000
1 0 1 0001
1 0 0 0111
1 0 0 0000
1 0 0 0000
1 0 0 0000
1 0 0 0000

ただ、これで実行すると2周目にずれる。レジスタAに初期値があるため。それらをリセットするために以下とする。

ADD A, A, 0011
INV B, A
ADD A, B, 0001
ADD A, A, 0111
ADD A, A, 0000
ADD A, A, 0000
ADD A, A, 0000
ADD A, A, 1100  #レジスタAを0000にリセットするため、1100+100=10000で桁溢れさせている

ビット列とすると以下になる。

1 0 0 0011
0 1 0 0000
1 0 1 0001
1 0 0 0111
1 0 0 0000
1 0 0 0000
1 0 0 0000
1 0 0 1100
tomo_makestomo_makes

Day 16 プログラムを自動実行するには - 「111-11」を永遠に計算し続ける機械