CLOSE

音の出る CPU(仮)(全2記事)

Rust・WebAssembly・WebGLで作る回路シミュレータ CADに書いたCPUの回路図がそのまま動く

Kernel/VM探検隊はカーネルや仮想マシンなどを代表とした、低レイヤーな話題でワイワイ盛り上がるマニアックな勉強会です。KOBA789氏は、シミュレータとCADの制作について発表しました。全2回。後半は、回路CADの制作方法について。前半はこちら。

自作CADに求めること

KOBA789氏(以下、KOBA789):シミュレータができたので、次はCADを作っていきます。書いた回路図がそのまま動くCADがなかなかないので、私はCADに書いた回路図がそのまま動くことを一番求めていました。

大抵の場合、回路を書くCADとシミュレータが別々になっています。まじめな回路を組むのであればそのほうが楽なのですが、だいたいタイミングチャートのかたちで表示されるんですよね。

プローブをいろいろなところにくっつけて、そのプローブの値が時間経過でどうなったかというタイミングチャートがバーッと出るわけです。たくさんのピンの状態、配線の電位の状態を俯瞰するという意味では、時間方向でも見られるので非常にいい表示方法なのですが、私はリアルタイムにガチャガチャ動いている様子を画面上で見たい。動いて触れる回路図がほしかったので、そのように作ることにしました。

さらに、できればその動作は60fpsでヌルヌル動いてほしいんです。紙芝居みたいな画面が出てきて、ガッチャガッチャとなってるとやっぱり興醒めなわけです。実物は60fps以上で動くので、モニターが60fpsなのはしょうがないとして、そのモニターのハードウェア限界では動いてほしいんです。

これからCPU作ろうと言ってるので、小さい回路だけしか動きませんは話にならないのでね。回路規模が大きくなってもシミュレーションをなめらかにしたいと考えています。

GUIはRust・WebAssembly・WebGLで制作

いまどきGUI(Graphical User Interface)を作るといったらたぶんブラウザなんですよ。私は得意なのでよくブラウザで作るのですが、そうするとReactとTypeScriptでバーンみたいな感じになります。

回路図みたいに描画する要素がメチャメチャ増えるとDOMでは遅すぎるし、さっき60fpsで動かすとか言ったし、しかもシミュレーションしている最中は回路中のいろいろなものの状態が目まぐるしく変わるので、それを書き換えて回る必要もある。

TypeScriptやJavaScriptで座標計算をしまくるコードを実際に書いたのですが、あまりにキツいんですね。演算子のオーバーロードがないので、ベクトルとベクトルの足し算ですらメソッド呼び出しになってしまいます。カッコとメソッド呼び出しのドットがメチャメチャ大量に出てきて非常にキツいコードになります。

目に悪すぎて開発意欲をメチャメチャ削いでくるし、遅いのでこれはなしとなりました。

そんなわけでRustとWebAssemblyでWebGLだ! という結論になりました。メチャクチャな感じになってきたのですが、こういうアーキテクチャにします。

WebGLを一応説明しておくのですが、JavaScriptからOpenGLのようなものが叩けるAPIです。ウィンドウの中のOpenGLのコンテキストがごそっと取れて、それに向かってOpenGLのコマンドをJavaScriptから発行できるのが、WebGLです。

そんな設計なので、余計なものがぜんぜんなくて速いです。ほぼOpenGLが露出しているのはいいこともあるのですが、悪いこともあります。JSのようなスクリプトの言語との相性が最悪です。これをJSで使う人はかなり忍耐力があると思います。私は忍耐力がなかったのでRustで使うことにしました。

OpenGLに詳しい方はわかると思うのですが、速くて最高だと思われたWebGLは、三角形を塗りつぶすことしかできません。円とかが書けないし、線分も三角形を2枚使うし、なんなら文字も書けないし非常に不便極まりないです。

CADに使うにはちょっと機能が足りてなさすぎるんじゃないの? という感じですが、気合いで全部実装しました。

いわゆるGPUを直接叩くGUIの設計はいろいろな種類があるのですが、今回採用したのはImmediate mode GUIというタイプのアーキテクチャです。これはどういうものかというと、60fps、1秒間に60回全フレームを1から描き直します。

256×256のビットマップで画面を区切って、その領域が再描画されていなかったらそこのビットマップは使い回す、という賢いことは一切しません。

一切せずに、毎回毎回1秒間に60回やっているにもかかわらず1秒間に60回すべての画面を描き直しています。このアーキテクチャはゲームエンジンと非常に相性がいいことで知られています。なぜならゲームは60fpsで毎回描き直しているからです。

Dear ImGuiとかUnityのIMGUIとか、みんなImmediate mode GUIのライブラリにIMGUIと名前を付けちゃいがちですが、こういうライブラリが有名です。今回のCADでもこのアーキテクチャを採用していて、Dear ImGuiのコードをだいぶ参考にしました。

やっぱり気になるところは毎フレーム描いたら遅くないのかということなんですが、実は現代のGPU自体はメチャメチャ速いんですよ。メチャメチャ速いんですが、それでも動きがカクついたりすることがあるじゃないですか。

あれは何かというと、GPUはCPUからのRPCで操作しているのですが、そのRPCのコマンド発行で時間を食っているんですね。無駄にCPUが待たされていたり、GPUが遊んでいたりして、それで無駄に時間を食って遅くなっています。

なので、コマンド数自体を削ればアホほど速くなります。1フレーム描く時にドローコールという最後に画面を描画するコマンドがあるのですが、今回はこいつの回数を1フレームあたり1回に抑えることによってメチャメチャ高速化しています。

回路のデモ

ここからデモします。これはシミュレータの動きをデモするためだけに作ったどうしようもない回路です。今何が起きているかというと、接点、コイル、接点、コイルと互い違いに全部並んでいます。

ここに再生ボタンがあるのですが、こいつをバチっと押すと、端から順番にスイッチが入っていって、この30番目までダラダラダラダラっとドミノ倒しみたいになります。

やってみます。ここのスイッチは人間が押さなきゃいけないので押します。カチッ。ダラダラダラダラ……丸が端から順番にダラダラダラダラってこんな感じになっています。

これおもしろいのが、ここのINと書いてあるやつをR30にして、こいつを逆向きにすると、振動するようになるんですね。R30がスイッチオンするとここの接点が切れるので、今度は端から切れ始める。

やってみますよ。ピッ。こういう動きをします。この動作の遅さと、接点がパチパチ動いているこの感じが電磁リレーの醍醐味です。

最後にもうちょっとコンピューターっぽいことをやって終わりにします。こちらは全加算器です。こちらに入力A、B、こちらにOutがあるのですが、このAを1個入れるとこれがOutなのですが、今はゼロなのでビットが立っていません。Aに1個入れるとビットが立って、Bにも入れるとOutは消えてCarryが上がります。同時に負論理も一緒に出ているのですが、Carryが上がりました。

ここにCarryを突っ込むと、Outも上がって2ビット立った状態で全加算器ができています。こういう回路になっています。

というわけで、私の発表は以上になります。ありがとうございました。

司会者:ありがとうございました。質問が何点かあるのでお伝えします。まずこの描画は、SVGではダメなんですか? というコメントがありました。

KOBA789:たぶんSVGでもある程度の規模まではいけるはずで、かつ、SVGのほうが絶対に実装は楽です。ただ、配線の本数が何十万になってくるとおそらく厳しいというのがあってやめています。

あとSVGにしてしまうと、回路CADの中で持っている内部の回路図のデータ構造と、SVGの表示のためのデータ構造をいちいち同期する丁寧なコードを書かなきゃいけなくなります。そのプログラミングがちょっと面倒なんですね。

今回Immediate mode GUIにした理由がもう1つあります。回路CADの内部状態を毎度毎度、描画命令にバカ正直に全部トランスレートしてあげれば、確実に整合性の取れた表示ができます。そこがやっぱり利点かなと思っています。

司会者:うんうん、コードもシンプルにやるということですね。あと技術的な質問ではないのですが、なぜ小学生の時にリレー300個も買ったんですか? という質問もありました。

KOBA789:当時から電磁リレーで計算機を作りたかったんです。なので実は夢がまだ20年弱ほど叶っていないということですね。

司会者:意外と長年だった(笑)。あともう1つ、やっぱりみんなこのパチパチのCADを見て、「リレーの音が聞こえてくる」「音が鳴ってほしい」と。サウンド再生してほしいというコメントが大量に来ていたので、見事に意図が伝わっているんじゃないかなと思いました。

KOBA789:本当はWeb Audio APIで音が鳴るところまで仕込みたかったのですが、ちょっと実装が間に合わなかったので、そこは近いうちに実装しておもしろ動画を投稿しようと思います(笑)。

司会者:WebGLはWebAssemblyから直接触れるという理解で合っていますか? というコメントがありました。

KOBA789:直接ではなくて、OpenGLのようなAPIにもかかわらず1回JavaScriptの世界を通すことにはなります。JavaScriptの世界を通る部分は、さっき言ったGPUへのコマンド呼び出しの部分だけです。そのコマンド呼び出しも、そもそも重い処理なので、あまりオーバーヘッドにはならない感じになっています。

司会者:HDLみたいなものは作らないのですか? というちょっとふわっとした質問がきています。

KOBA789:HDLは、効率良く設計するにはいいんですが、楽しくないんですね。動きを見る場合には、やっぱりこうやって整列された回路図があったほうがパーツの位置関係がわかるので、見て楽しいんです。視覚的に。

HDLで書いてしまうと、HDL自体には2次元や3次元でのレイアウトの情報はありません。書きやすいんですが、やっぱり楽しくないので(笑)。趣味でやっている以上楽しくないといけないので、こういうふうにしています。

司会者:ありがとうございます。

続きを読むには会員登録
(無料)が必要です。

会員登録していただくと、すべての記事が制限なく閲覧でき、
著者フォローや記事の保存機能など、便利な機能がご利用いただけます。

無料会員登録

会員の方はこちら

関連タグ:

この記事のスピーカー

同じログの記事

コミュニティ情報

Brand Topics

Brand Topics

  • 今までとこれからで、エンジニアに求められる「スキル」の違い AI時代のエンジニアの未来と生存戦略のカギとは

人気の記事

新着イベント

ログミーBusinessに
記事掲載しませんか?

イベント・インタビュー・対談 etc.

“編集しない編集”で、
スピーカーの「意図をそのまま」お届け!