#自己紹介
こんにちは。ぱたろうです。Twitterはこちらです。
現在中学3年生のCPUアーキテクトです!
電磁石式自作CPUを複数機作って互いに接続させてネットワークにしました!!
それからYouTubeでもこういう映像を出したりしていました!
未踏ジュニアでの僕の発表はこちら
追記 : スーパークリエイターに認定されました!ありがとうございます!
#はじめに
日々の生活において、低いところからみればCPU、高い所からみればインターネット、というように、私たちは色々なテクノロジーに強く依存しています。
が、しかし、私たちの多くはCPUやインターネットの表面上の動きは理解していてもその深い中身までは理解していません。
私たちにとってCPUやインターネットといったものは ――アーサーCクラークの「高度に発達した技術は魔法と見分けがつかない」という言葉を借りるならば―― 誰でも使えるけど、誰も説明できないもの、すなわち**「魔法」**なのです。
しかし、いくら魔法といえどもこれらは全て私たちと同じ人間が作り出したものですから、やっぱり理解することが可能だと僕は思うのです。
ですから、【Spaghetianのネットワークでつくったもの】の章からはネットワークや回路についての詳しい説明を行うので、「自作CPUできるよ!」や「論理回路よめる!」といった方は、【Spaghetianのネットワークでつくったもの】の章までは読み飛ばしていただいて構いません。
しかし、低レイヤに興味があるけどやったことのない方、特に「自作CPUやったことないよ」、「CPUってどう動いているのか知らないよ」という方は、読み飛ばさずにきちんと【CPUの動き】の章まで読んでいただいて、「CPUチョロくない?ぜんぜん魔法じゃなくない?自作CPUでネットワークって、オレ・私でもできちゃうんじゃない!?」と思ってもらい、その先を読み進めてもらいたいと思うのです。
本当にできるの!?と思うかたもいらっしゃると思います。僕が作った自作CPU、Spaghetianのかっこいい映像があるので、ここでみてください!
#つくった動機
- 低レイヤに強い興味があった
- チューリングマシンをPythonで組んで、万能チューリングマシンを考えたりしているうちに自作CPUをやってみたくなった
- 自作CPUにすこし理解があったから
- CPUやインターネットといった私たちに非常に身近なのに、理解されず「魔法」とされている技術を「実はそれは魔法ではないんだ」と示したかった(これが一番の理由)
- 未踏ジュニアという小中高生クリエータ支援プログラムへ応募をしてみたかったから
- 自作CPUなど低レイヤについて話がわかる人がいなくてさみしかった
といった理由がありました。
#CPUの動き
CPUの命令は「オペコード」と「オペランド」の二つで一組になっています。
たとえばですが、Pythonで標準出力のプログラムだと以下のようになりますよね。
print("Hello")
これをCPUの命令に例えると、print関数が「オペコード」、"Hello"という引数が「オペランド」になります。
※命令とは「オペコード」と「オペランド」が組み合わさったもの。プログラムとは命令が集まったものです。
あなたがCPUの視点になって考えてみてください。
※「あなた」は現実世界の話ではなく、CPUの世界、比喩の世界の話です。
あなたは命令を実行する回路で、命令の実行を任されています(ようするに下っ端です。なので雑用もしてもらいます)。ひとつの命令を実行するのに1日かかるとしましょう。なので、あなたがいるCPUは1クロックが1日、というわけですね。遅い(・´з`・)。
※1クロックとは、CPUが一つの命令を実行する時間のこと。CPUによってクロックは違う。クロック周波数とか言ったりするらしい。
ちなみに、上司であるプログラムカウンタさんもあなたと同じ命令を実行する回路の一種(非常に特殊)ではあるのですが、全体に指令を出す、というとても重要な役職についているので、あなたの上司、ということにしておきましょう(後述)。
CPUが起動される前に必ず、顧客がプログラムを渡してきます。これは機械語で書かれていて、あなたは読めません(会社の立場で、という意味ではなく能力的に不可能、という意味で)。
※機械語は二進数ですが、どうやって実際のCPUが1と0を回路で判別しているかというと、回路に電気が流れている(ONの状態)を1、電気が流れていない(OFF)状態を0と便宜上呼ぶわけです(これがデジタル)。アナログコンピュータは電気が流れているかどうかの判別ではなく、その電圧の高さだったりをはかったりするらしい。
顧客がプログラムを渡しおわったら、CPUが起動されます。プログラムカウンタさんはCPUがメモリのどの番地の機械語を実行すればよいのか、という重要な情報を持っているのです。
そこで、あなたはプログラムカウンタさんに「この番地へ行け」と命令されます。あなたは言われるがままにその番地の機械語のデータをとってきて、もう一人の上司であるデコーダさんに取ってきたデータを渡します。デコーダさんは機械語でかかれたデータを読むことができて(会社の立...云々)、あなたにもわかるようなデータにしてくれるのです。デコーダさんが解読しおわったら、デコーダさんは解読したあとのデータをくれるので、あなたはそれを元に命令を実行します(足し算とか)。命令を一つ実行したらそれで一日が終わります。これを顧客が渡してきたプログラムが終了するまで繰り返すのです。
ちなみに、Spaghetianは4bit CPUと呼ばれるもので(何をもってN bit CPU と呼ぶのか、という定義はなくとてもあいまいですが...)一度に4bitしか処理できません。そのため、Spaghetianは最高でも16行のプログラムしか書けないのです(0行目 ~ 15行目の全16行。数学の世界(?)プログラマの世界(?)では0を基準とするのが普通らしいです)。
そこで、あなたは「仕事は長くても16日でおわるじゃ~ん」と思ったかもしれません。しかしながら、残念なことにそれは違います。ここで先ほど「後述する」、としたプログラムカウンタさんが出てくるのです。
実はあなたはプログラムカウンタさんに対してなんらかの命令の実行(=処理)をすることが可能です。つまり、場合によってはあなたは上司に向かって指令を出すことができるのです。
それが「ジャンプ」や「条件付きジャンプ」といった命令です。
プログラムカウンタさんはCPUがどの番地の機械語を実行すればよいのか知ってはいるものの、実はプログラムカウンタさんは持っているデータに対して1日ごと(1クロックごと)に1足している(=インクリメントしている)にすぎません(とは言いつつ、これは重要で、自分の書いたプログラムが上から順番にきちんと処理(=逐次処理)されないと困りますよね)。
ですから、あなたは(これもまたデコーダさんが渡してくれたデータに従って)プログラムカウンタさんに「持っているデータを○○に書き換えなさい」と命令ができるのです。
これが「ジャンプ」と呼ばれる命令です。また、「条件付きジャンプ」はその言葉の通り、指定された条件があっていれば(=true)プログラムカウンタさんに対して指令を出すことができる、というものです。
そして、これによって今いる番地より前の番地に戻れば...あなたの仕事は長引くのです。
※ジャンプ命令は高水準言語で言えばfor文やwhile文といった繰り返しに使うことができ、条件付きジャンプ命令はif文などの条件分岐に使うことができます
※また、実際のSpaghetianではROM(DIPスイッチ)によるプログラムでした
DIPスイッチでのプログラミングを素手でやるとだんだん爪が痛くなってきます。ですから、僕は竹串プログラミングということをやっていました。
竹串プログラミング↓
#Spaghetianのネットワークでつくったもの
↓ネットワークの模式図
※三機のCPUはどれも同じ機能を持っていて、決して後述する「オンライン卓球ゲーム」をするためだけの「専用機械」ではなく、きちんとした「汎用機械」です。また、Clock Generatorが独立してありますが、実際はServerのクロックをClient A, Bに送信しているだけです。
実はこのCPUはリレーという素子を使っています(図では少ししかリレーを使用していませんが、これは模式図です)。CPUというのはLSIなどの半導体でできているのが常識ですが、半導体は小中高学生、そして大半の大人にとっても魔法に近い技術だと感じ、それは僕の動機にはあわなかったので、小学五年生のときに習った電磁石でできている「リレー」という部品を使うことにしました。
また、基板は使わずに、ブレッドボードというものを使用しました。半田付けなどの作業は初心者にとっては大きな壁となりますし、ブレッドボードのように穴に配線を刺すだけの簡単な回路の実装方法の方が僕の目的に適っていると思ったからです。
また、Clock Generatorには「手動クロック!」と書いてありますが、結局は自動クロックとなりました(そのほうがかっこいいので...)。
※リレーについての分かりやすい説明をしているサイトはこちら!
このネットワークの説明をする前に、僕がこのネットワークで主に何を動かしたのかを説明します。
僕はこのネットワークで「オンライン卓球ゲーム」を動かしました。Client AとClient Bがゲームのプレイヤーで、それぞれのCPUのMonitor Aにゲームが表示されます。
どういうゲームかというと、Monitor Aを卓球台に見立てて、光っているランプの場所にボールがあり、それが順々に動いていくので、はじっこにボールが来た時にそっち側にいたプレイヤーがタイミングよく打ち返して(Push Switchを押して)ラリーを続ける、というゲームです。ラリーに失敗するとCPUが停止し、失敗したClientが負けになります。
Monitor Aは電球が4個並んだもので、図にするとこんなかんじ↓
○が光っているランプ
●が消えているランプ
- ●●●○ Client Bがボタンをタイミングよく押す。失敗したらゲーム停止。
↓ - ●●○●
↓ - ●○●●
↓ - ○●●● Client Aがボタンをタイミングよく押す。失敗したらゲーム停止。
↓ - ●○●●
↓ - ●●○●
↓ - に戻る
これをどちらかのプレイヤーが打ち返すのに失敗するまで繰り返します。
#ネットワークのハードウェア的な説明
ソフトウェア的な話は次章の【命令セット】以降はなします。ハードウェアはどうでもいい、という方はここを飛ばしてください。
このネットワークを構成しているServer, Client A, Client Bの三機のCPUはどれも同じ機能を持っていて、決して「オンライン卓球ゲーム」をするためだけの「専用機械」ではなく、きちんとした「汎用機械」です。
つまり、三機のCPUは表面上Server, Client A, Client Bの動きをしているだけであって、中身はただデータのやり取りを行っているだけ、ということです。
図を見ればわかりますが、この三機のうち、ServerはClient A, Bの両方とつながっていますが、Client同士は直接は繋がっていません(Serverを通してつながっている)。
----を通信線に見立てるとこんなかんじ↓
Client A ---- Server ---- Client B
通信線はおおまかにClientとServer間で以下のものがあります
- クロック共有線(1bit)
- ServerからClientへのデータ送信線(4bit)
- ClientからServerへのデータ送信線(4bit)
- ClientからServerへのデータ送信線(1bit)
クロック共有線はServerからClient A, Bに伸びていて1bitです。また、Spaghetianはリレー式CPUなので、一行のプログラムを処理するのに数十msかかり、そのまま全CPUを同期させてしまうと、プログラムの処理中に通信で外部入力が入ったりしてCPUが混乱するので、Serverから発信されているクロックはわざと数十ms遅延させて発信されています。どれくらい遅延させているかは割と適当です。
しかし、「CPUの実行中には外部の入力は受け付けなければいいじゃーん」とあなたは思うかもしれません。僕も思います。が、これはしょうがなかったのです...
Spaghetianを製作中の僕は未踏ジュニアで支援をしてもらってかなりの数のリレーを使わせてもらったのですが、それでもやはり足りなかったり、煩雑な回路を作るのが面倒に感じたりで、できることならリレーを節約したかったのです。なので、僕はレジスタにD-FFではなく、Dラッチ回路を使ってしまったのです(Dラッチの方が圧倒的に使うリレーの数は少なく済みます。D-FFとDラッチについては後述します)。
D-ラッチはクロックがONになったら入力からのデータが出力へ筒抜けしますから、データを受け付けないようにすることができなかったのです(これは分かりやすく伝えるための嘘です...受け付けないようにすることはできなくはないけど、それはあまりスマートじゃないと感じたのでやめました)。
※レジスタとは、プログラムが書き込まれているメモリではなく、プログラミングで言えば変数のようなもの。自分で宣言してつくったりすることはできないが、一時的なデータ置き場として使える。分かりづらいと思った方はこちらへ。
話を戻してネットワークについてです。
Server, Client間の通信線はどの方向も4bitです。理由はもちろんSpaghetianが4bit CPUで一度に4bitしか処理することができないからです。
とは言えども16行だけのプログラミングでも十分に工夫は沢山出来ます(条件分岐やループもあるので自由度は高いです)。
また、ClientからServerへのデータ送信線(1bit)は、Clientが必要なタイミングでボタンを押しているかを判定するための通信線です。
この章では結局通信線についての説明しかしていませんが、僕はネットワークというのはそういうもの(ハードウェア的な説明があまりないもの)で、ネットワークの本質はソフトウェアにあるのだと思うのです。
#命令セット
####命令の書き方
※再掲
CPUの命令は「オペコード」と「オペランド」の二つで一組になっています。
たとえばですが、Pythonで標準出力のプログラムだと以下のようになりますよね。
print("Hello")
これをCPUの命令に例えると、print関数が「オペコード」、"Hello"という引数が「オペランド」になります。
オペコードは命令、オペランドは引数だと思ってください。
Spaghetianの命令は
オペランド オペコード
の順で書かれています。
####アセンブリとは
一つの命令はCPU上では二進数でうごいています。ですが、それは人間には読みにくいです。なので、機械語と一対一対応したもう少し分かりやすいものがアセンブリなのです。
たとえば、Spaghetianでの加算命令は0000ですが、それをアセンブリにすると「ADD」(英語で足す、とかいう意味)になります。
####具体的な命令達
引数にImが描いてあるやつは、イミディエイトデータ(即値)というやつで、Imのデータを直接使う。Imでないときは引数の場所にあるメモリのデータを使う。
たとえばADD 1010だったら、メモリの1010番地のデータを足すのではなく、1010を直接足すのです。
Serverの命令セット
番号 | アセンブリ | 機械語 | 動作 |
---|---|---|---|
0 | ADD Im | 0000 | AレジスタのデータとImのデータを足し、加算された結果をAレジスタに代入する。 |
1 | LDA Im | 0001 | AレジスタにImの値を代入 |
2 | JMP Im | 0010 | Imの値をプログラムカウンタに代入(Imのデータにジャンプするということ) |
3 | LDB Im | 0011 | BレジスタにImを代入 |
4 | IFBJMP Im | 0100 | I/Oポート1に入力があれば、Imの値をプログラムカウンタに代入(I/Oポート1はClient Bから入力が入る側) |
5 | OUT Im | 0101 | Imの値をI/Oに出力 |
6 | IFAJMP Im | 0110 | I/Oポート2に入力があれば、Imの値をプログラムカウンタに代入(I/Oポート2はClient Aから入力が入る側) |
7 | EQJMP Im | 0111 | AレジスタとBレジスタの値が同じであれば、Imの値をプログラムカウンタに代入 |
Client Aの命令セット
番号 | アセンブリ | 機械語 | 動作 |
---|---|---|---|
0 | ADD Im | 0000 | AレジスタのデータとImのデータを足し、加算された結果をAレジスタに代入する。 |
1 | LDA Im | 0001 | AレジスタにImの値を代入 |
2 | JMP Im | 0010 | Imの値をプログラムカウンタに代入(Imのデータにジャンプするということ) |
3 | LDB Im | 0011 | BレジスタにImを代入 |
4 | IFBJMP Im | 0100 | I/Oポート1に入力があれば、Imの値をプログラムカウンタに代入 |
5 | OUT Im | 0101 | Imの値をI/Oに出力 |
6 | IFAOUT | 0110 | I/Oポート2に入力があれば、1bit ONを出力する |
7 | EQJMP Im | 0111 | AレジスタとBレジスタの値が同じであれば、Imの値をプログラムカウンタに代入 |
Client Bの命令セット
番号 | アセンブリ | 機械語 | 動作 |
---|---|---|---|
0 | ADD Im | 0000 | AレジスタのデータとImのデータを足し、加算された結果をAレジスタに代入する。 |
1 | LDA Im | 0001 | AレジスタにImの値を代入 |
2 | JMP Im | 0010 | Imの値をプログラムカウンタに代入(Imのデータにジャンプするということ) |
3 | LDB Im | 0011 | BレジスタにImを代入 |
4 | IFBOUT | 0100 | I/Oポート1に入力があれば、1bit ONを出力する |
5 | OUT Im | 0101 | Imの値をI/Oに出力 |
6 | IFAJMP Im | 0110 | I/Oポート2に入力があれば、Imの値をプログラムカウンタに代入 |
7 | EQJMP Im | 0111 | AレジスタとBレジスタの値が同じであれば、Imの値をプログラムカウンタに代入 |
※Client A, Bの命令セットの違いは[番号]4, 6の部分です。
また、プログラムカウンタが15(最後の番地)を指ししてした時、クロックは停止されます(=CPUの実行終了)。これはハードウェアで実装されています。
#ネットワークのソフトウェア的な説明
では、命令セットの説明等を踏まえて、Server, Client A, Bのプログラムを載せていこうと思います。
####Serverのプログラム
番地 | アセンブリ | オペコード | オペランド |
---|---|---|---|
0 | OUT | 0101 | 0001 |
1 | OUT | 0101 | 0010 |
2 | OUT | 0101 | 0100 |
3 | OUT | 0101 | 1000 |
4 | IFAJMP | 0110 | 0110 |
5 | JMP | 0010 | 1111 |
6 | OUT | 0101 | 0100 |
7 | OUT | 0101 | 0010 |
8 | OUT | 0101 | 0001 |
9 | IFBJMP | 0100 | 0001 |
10 ~ 15番地には0000 0000 (=NOP命令)が代入されています。
※NOP命令というのは、なにもしない命令のこと。ADD 0 はAレジスタに0を足すだけなで、結果として何も起きないからNOP命令となる。
再掲 オンライン卓球ゲームの図
- ●●●○ Client Bがボタンをタイミングよく押す。失敗したらゲーム停止。
↓ - ●●○●
↓ - ●○●●
↓ - ○●●● Client Aがボタンをタイミングよく押す。失敗したらゲーム停止。
↓ - ●○●●
↓ - ●●○●
↓ - に戻る
0 ~ 3の番地は上の図でいうと、1. ~ 4. です。
4番地ではClient Aから入力があれば0110(十進数で言うと6)番地に飛びます。Client Aからの入力がなければジャンプはしないので5番地に来て、1111(十進数で言うと15)番地にジャンプし、クロックは停止します。
6 ~ 8番地は0 ~ 3番地同様、上の図でいうと4. ~ 1. です。
9番地も4番地同様、ClientBから入力があれば0001(十進数で言うと1)番地にジャンプします。
また、入力がなければ10 ~ 15はすべてNOPなので、9番地でClient Bから入力があればなければそのまま15番地まで行ってクロックが停止します。
このようにして、サーバーは処理しているのです。
追記 : Twitterにて「Serverのプログラムの表に9番地が抜けてます(IFBJMP Im 0100 0001で合ってますか?)」というリプライをいただきました。その通りです!ごめんなさい!
####Client Aのプログラム
番地 | アセンブリ | オペコード | オペランド |
---|---|---|---|
0 | ADD | 0000 | 0000 |
1 | ADD | 0000 | 0000 |
2 | ADD | 0000 | 0000 |
3 | IFAOUT | 0110 | 0000 |
4 | IFAOUT | 0110 | 0000 |
####Client Bのプログラム
番地 | アセンブリ | オペコード | オペランド |
---|---|---|---|
0 | ADD | 0000 | 0000 |
1 | ADD | 0000 | 0000 |
2 | ADD | 0000 | 0000 |
3 | ADD | 0000 | 0000 |
4 | ADD | 0000 | 0000 |
5 | ADD | 0000 | 0000 |
6 | AD | 0000 | 0000 |
7 | ADD | 0000 | 0000 |
8 | IFBOUT | 0100 | 0000 |
9 | IFBOUT | 0100 | 0000 |
Client A, Bのプログラムはこうなっています。
ServerのプログラムでClientからの入力が必要になったときにだけ出力するようになっています。
※このオンライン卓球ゲームでは、打ち返しボタンをずっと押していれば勝ててしまいます。ですが、僕は性善説を信じています。
また、Server, Client A, Client Bをネットワークにしないで動かした場合はプログラムカウンタは独立して動くのですが、ネットワークにした時はServer, Client A, Client Bを同期させるために、Serverのプログラムカウンタの値を配線でClient A, Client Bに流すようにしています。
そう考えるとServerがほとんどのプログラムを担っていて、Client側は1行のプログラムだけで済んでしまいます。が、それでもネットワークはネットワークなのです(どうにか)!!
ちなみに、このネットワークのゲームが動いている動画はこちらにあります。
#回路図の説明
僕が設計したリレーの回路は論理回路を最小単位としていないことがあります。理由は以前にも述べたように、「節約」です。回路の最小単位を「論理回路」にするのではなく、「リレー」自体にした方が、リレー式CPUの時はリレーを節約することができることがあります!
では、ここからは(全て手書きです)回路図について説明をしていきたいと思います。
####一機のCPUの回路図
これまでに説明したことがあったりで、多少回路は違うけど...許してください...
番号 | 何か | 説明 |
---|---|---|
1 | プログラムカウンタ | 説明した通り |
2 | ROM | プログラムを置いている。本当はちゃんとしたメモリにしたかったが、リレーを馬鹿みたいに使うことになってそれは辛いのでROMにした。DIPスイッチとゆーやつでできている |
3 | デコーダ | 説明した通り |
4 | Aレジスタ | 説明した通り |
5 | Bレジスタ | Aレジスタと同じだが、できることはAより少ない(比較くらいにしか用途がない) |
6 | 加算器 | 加算をする |
7 | コンパレータ | 条件分岐を行う |
8 | Auxiliary register | Aレジスタに加算をする時に使う予定だった。結局必要なかったのでつくってない。 |
####ネットワーク全体回路図
3機のCPUをつなげたやつ。5本線のやつは4bitのデータとDラッチのクロック(の予定だったが、【ネットワークのハードウェア的な説明】で説明したように4bitになっている。クロックはCPUのクロックを流用することにした)。1bit線はCPUのクロック線。
####リレーについて
僕が使ったリレーはこちら(24V駆動)
これの使い方は、こちら(これは3Vのものですが、24Vのものと仕様は変わらないので)
####論理回路の回路図
こんなの
####RSラッチとDラッチ
※訂正
My-FF!(D-FF)とかいてあるやつはDラッチという回路です。
####RS-FFとは
Setがオンになったとき、ON(=1)が記憶される。Resetがオンになったとき、OFF(=0)が記憶される。
ここで以下の疑問が出てくると思います。
- 両方OFFになったらどうなるの?
- 両方ONになったらどうなるの?
説明します!両方OFFになった時は直前に記憶されていたやつが引き継がれます(データを記憶するんだから当たり前と言えばあたりまえ)。
たとえば、SetがONでResetがOFFのとき、ONが記憶され、このままSetをOFFにすると、そのままONが記憶され続けます(そういうこと)。
両方ONの時は...どうなるかは時と場合によります。ですので、両方ONにすることは避けましょう。
####D-FFとは
カメラを想像してください。カメラはスイッチを押した瞬間のデータを記憶しますよね。D-FFもそれと同じで、クロックがONになった瞬間の入力を記憶します。
ですので、クロックがONになった瞬間以外(たとえばONの間)に入力に何を入れてもなにも起きません。
####Dラッチとは
D-FFと違う点は、クロックがONの間のデータをを記憶することです。つまり、クロックが立ち上がってから、OFFになるまでの間、出力と入力は一致します。
※写真にはMy-FF!(D-FF)と書いてありますが、実際はDラッチです。
また、左側のProgram Counter Mark Iというやつは没になりました。これは1bit CPUなどの小規模には向いているのですが、4bitとなるとあんまり向いていない気がしたので...
混乱される前に言っておきます!この回路図はD-FFの回路図ではなく、Dラッチの回路図です!
####4bitのレジスタと比較器
レジスタは一個前で説明したDラッチを使っています。
比較器は説明することはありません。そのまんまです...
####D-FF
裏に描いてあるやつが少しうつっていますが、気にしないでください!
この回路を設計した経緯として、やっぱり「リレーを節約したい」という切な願いがありました。で、既存のD-FFの作り方(ここ)だとリレーが13個必要なのです。D-FFはプログラムカウンタやレジスタで使用しますから、例えばプログラムカウンタだけでもリレーを52個使うことになってしまうのです(4bitなので)。
そこで僕は「クロックがOFFからONになる瞬間に一瞬ON(パルス)を出して、それをDラッチに流せばいいんじゃね〜!?」と思ったのです。
これを作るための僕が一番最初に思いついた回路の説明をします。リレーは動作する時鉄片が物理的にスイッチングするのでそこにほんとに少しの時間がかかります、僕が使用したリレーは5msでした。
そこで僕は思ったのです。「動作中は5msOFFになるってことは、それをNOTで出せば5msのパルスが出せるじゃん!!」
そこで実験したのですが、敢えなく失敗に終わりました。理由はお分かりでしょうか...
5msのOFFのパルスをNOTに通すと、NOTもリレーの回路でできていますから、それも動作に5msかかるのです。なので、理論上は少しもONのパルスは出ないのです。
※「理論上は」とは言えどもやっぱり実験をしているとたまにほんの少しだけパルスが出ることがありました。
これはとても重要で、例えばですが、ここで僕が5msのパルスを出すことに成功したとしましょう。これをDラッチに繋いでみます。が、それも実際は動作しません。なぜかというと、Dラッチには3つのリレーが組み合わさってできていますから、(Dラッチの状態によりますが)大体動作するまでに10 ~ 15ms必要になります。ですから5ms出たところで動作するかと言えば、それは間違いなのです。
じゃあどうすればいいの!?と思いますよね、こうなるような回路を作ればいいのです。
パルスが出続ける時間 >= Dラッチの動作に必要な時間(10 ~ 15ms)
お気づきでしょうか、この条件を満たしているのが以下の回路図なのです!
この回路では、リレーを9個しか使用していません、大幅に減りましたね!
※Dラッチに3つ, RSラッチに2つ, BUFに1つずつ、他リレーが2つで9個ですね
Dラッチの回路以外の回路はパルスを出す回路で、パルスを出す回路にもDラッチと同じものが入っているのがわかるでしょうか(Dラッチとは書かれていないが、実際Dラッチと同等の回路になっている)。
クロックが入った瞬間にパルスを出す回路内部のRSラッチを動作させ、RSラッチが0 ~ 1になる時間をDラッチが受け取るクロックとなっています。
####インクリメンタ
無駄な情報があってごめんなさい💦 黒い線で囲ってあるところがインクリメンタです。
これはそのままです。特に説明することはありません。
####プログラムカウンタ
D-FFを4つ並べ、D-FFの入力をインクリメンタの出力に、 D-FFの出力をインクリメンタの入力に繋げて、D-FFのクロックをCPU全体のクロックに繋げればほぼ完成ですが、ジャンプ命令が来たときにジャンプする値とインクリメンタからの出力が被さらないようにリレーで信号切り替えを行う必要があります。
####信号切り替えるやつ
上のプログラムカウンタで書いた「リレーで信号切り替えを行う必要があります。」の回路です。
これです。これを4つ並べれば信号を切り替えできます。
IN2がインクリメンタからの入力、IN3がジャンプ命令の時の入力で、IN1がONの時はインクリメンタからの入力が入り、OFFの時はジャンプ命令からの方のが入ってきます
####デコーダ
右側にI1, I2, I3, I4と並んでいますね、これが入力です。I1には1桁目を、 I2には2桁目を...
という感じで入力を進めます。これも回路図の通りですね。
I1で1桁目が0か1かを判別し、I2で1桁目の結果を受けて0か1かを判別し...という具合で3, 4桁目もやっていきます。デコーダは全てのパターンを構成してやらないといけないのが大変ですよね。
####コントローラ
卓球ゲームをプレイするためのコントローラです!写真!↓
終わりです!これであなたもCPUアーキテクト!
#さいごに
####謝辞
未踏ジュニアでもほとんどの方がソフトウェア的なプロダクトをやっている中、やっぱり同期のそういう技術的な話にはなかなかついていけなかったりで少し寂しくも思いましたが、ソフトウェアのアイデアなどは面白そうなのばかりでそれはそれでとても刺激的な半年間でした。
また、寺本PM(Twitter)には秋田先生(Twitter)を紹介していただき、お二人にはめちゃくちゃお世話になりました。僕のSpaghetianが動く状態で完成させることができたのも秋田先生のおかげです。
それ以外にも寺本PMには未踏卒業生のかでんさん(Twitter)を紹介していただいて技術的な話をする場を設けていただいたり、雪花の方を紹介していただいてSpaghetianのデザインについてお話しする機会をいただいたりで(最終的にはただのスチールラックに詰めるだけになってしまいましたが、このミーティングを踏まえていつか自作CPUを水族館の水槽の中に沈めてみたいという夢ができました!)、コロナ期間中でも濃い時間を過ごすことができました。
Spaghetian Netが完成したのは未踏ジュニアで金銭面、技術面、精神面の支援を受けられたおかげです!感謝!
追記 : 寺本さんが記事を書いてくださっているのでリンク貼っておきます。
####目指せCPUアーキテクト!
これであなたもCPUアーキテクト!(になれます。自分で設計を始めてからがCPUアーキテクトです!!がんばってください!)
私たちの生活に最も浸透していて、そして身近で、なくてはならないもの。誰もがそこにあることを当たり前だと思っていて、使うのは簡単すぎるが故に誰も意識しないもの、それはCPUです。
そして、CPUを設計するのがCPUアーキテクトという仕事です。
ですから、人類に最も影響力を持っている人間はアメリカの大統領でもなく(習近平?笑)、それは他ならぬCPUアーキテクトなのです。
そこで、誰も説明できない、理解できないと思われている魔法の技術、CPUをみんなで理解しようじゃないか!というのが僕の未踏ジュニアでのプロジェクトでした。自作CPUなんていうのは私たちが使っているCPUとは比べ物にならないとはいえ、オームの法則なんてわからなくても誰でもできちゃうものなのです。
※SpaghetianではLEDの抵抗以外抵抗を使用していません。LEDの抵抗も大抵1kΩでなんとかなると思います。オームの抵抗なんて分からなくても自作CPUなんて怖くない!
「抵抗を計算しないの怖い」と思った人は実店舗に行って店員さんに聞いてみるか、Twitterで誰か教えてツイートをするとかをお勧めします。
ちなみに、この記事で説明した回路図の意味が全くわからない人が大半だと思います。ですが、この回路図の通りに作れば動きます!自分で作ってみるうちにいつかわかると思います!プログラミングの写経と同じ!
####自作CPUやりたいけどググり方がわからない人
CPUの作り方をネットで懇切丁寧に教えてくれるサイトは多分ないので、ググりかたのおすすめです
- 自作CPUってどうやってやるんだろう🤔
- そもそもCPUってどーゆー仕組み?
- CPUの仕組みをググる
- CPUってプログラムカウンタとかデコーダ等々回路が必要なんだね〜
- プログラムカウンタってインクリメントする回路と、N bitのD-FFとやらが必要なのか
- 「D-FF 回路図」 とか 「インクリメント 回路 作り方」とかググる。出てこなかったら一生懸命自分で考える
最悪「カウンタ」でググって、それを秋月のサイトか何かで見つけて、データシートをみちゃったりもいいかと思います。
というようなことを繰り返せばだんだんわかってくると思います。各回路が出来上がったらそれを「どう繋げれば動くのか」は自分で考えてやってみてください。
ちなみに、僕自身プログラムカウンタをそのままググったり、インクリメントする回路を調べても全然出てこなくて大変な思いをしたことがあります。そこで界隈では有名な名著『CPUの創りかた』を読んだのですが、プログラムカウンタの章では回路図自体は載っていなくて、ただ単にどのICを使うかしか書いてありませんでした(もしかしたら僕の見落としかもしれません🙏そもそもデータシートを見れば良い話だったのですが...)。「これは困ったなあ」ということで上記のような調べかたをした次第です。
また、本記事ではきちんとプログラムカウンタの作り方を載せています。自作CPUをやりたい方の力になれば嬉しいです!
####質問などについて
本記事、もしくはSpaghetian等々僕に質問がある場合はここのコメント欄、もしくは
Twitter : https://twitter.com/38912pataro
にお願いします。