· 8分で読了

2020年の振り返り

この記事は中国語から自動翻訳されたものです。翻訳によりニュアンスが失われている場合があります。

背景

2020年は混乱の1年であり、同時に僕にコンピュータの本質を再考させてくれた1年でもあった。この1年、僕は自分の得意分野ではない領域で多くの挑戦をしてきたが、基本的にはある一つのテーマを軸にしていた。それは「低レイヤーの再認識」だ。

僕は高校(正確には実業高校)で電子科を専攻していた。進学が主流の時代、実習の授業はあったものの、どちらかといえばマニュアル通りの作業という感覚が強く、大半の時間は勉強と問題演習に費やしていた。唯一幸いだったのは、普通科の高校ほど勉強の負担が重くなかったことで、そうでなければ台湾科技大学には合格できなかったかもしれない。

実業高校時代に少し残念だったのは、ものづくり(手を動かして何かを作ること)にあまり興味が持てなかったことだ。それに、授業の大部分ははんだ付けやブレッドボードの配線、線が重なってはいけない、ジャンパーしてはいけないといった指導で、僕のような手先が不器用な人間にはかなり苦痛だった。

実際、電子科にいた頃は電子工学そのものにも大して興味がなく、まさか後にプログラミングで生計を立てることになるとは予想もしていなかった。だがそのおかげか、最近になってこうした低レイヤーの技術に興味を持ち始めた。

そもそもこの問いに立ち返ると、答えはコンピュータをどれだけ深く理解しているかによって変わる。ダイオードやトランジスタ、レジスタ、CPUの仕組み、OSなど、どの領域の知識も一生を費やしても探求し尽くせないかもしれない。本当に奥が深い。

僕にとって今年は、コンピュータとは何なのかをじっくり理解するための1年だった。専門家ではないものの、その中に多くの面白さを見出すことができたし、会社でも同じように低レイヤーに興味を持つ同僚を見つけることができた。

電子科での学びとの重なり

実業高校で電子科の知識を学んでいた頃は、まさかこれらの知識が後になってこれほど役に立つとは思っていなかった。例えばブリッジ整流、ダイオード、フィルタリング、安定化回路といったものは、充電器などでよく使われる回路だ。これらは試験のために何百回も計算しただけでなく、実習の授業でブリッジ整流回路を組んで実験させられたりもした。

CPUが加算を行う際には加算器を実装する必要があり、それには半加算器や全加算器がある。これも授業で真理値表を一つずつ学び、ロジックゲートを使ってブレッドボード上に少しずつ実装していった(もちろん直接ICを使うこともできるが)。

CPUの動作にはクロックが必要で、一般的には水晶発振子を使うか、別途クロックジェネレータを接続する。なるほど、昔死ぬほど苦労して勉強したNE555回路は、CPUを動かすためのクロックを生成できるのか!(もちろん今は内蔵されているが)

当時は意味不明だったフリップフロップが、実はレジスタを実装するための基礎だったのだ。基礎を理解すればするほど、かつて高校時代にすでに一通り通ってきた道だったのだと気づいた。ただ当時は、それらの知識を結びつけることができていなかっただけなのだ。

こうした低レイヤーに関わる知識には一種の神秘性がある。一つには参入障壁が比較的高いこと。誰も毎日チップを買ってブレッドボードに挿したりはしないし、個々の知識に対する理解も必要とされる。もう一つは、ネット上の情報があまりにも少ないことだ。キーワードで検索しても長い時間をかけてようやくあるフォーラムの何番目かのコメントに答えが見つかることもあり、問題に直面したときは自力で解決策を模索しなければならないことが多い。

再び基礎へ立ち返る

そうした背景から、2020年の僕の課題は「できる限り低レイヤーに近づくこと」だった。ハードウェアでも、OSの仕組みでも、プログラミング言語の動作原理を理解することでもいい。とにかく低レイヤーへの理解が深まるものなら何でもよかった。

そこで今年の初めにArduinoを購入した。Arduinoなんて他人がお膳立てした出来合いのものじゃないかと思う人もいるかもしれない。確かにその通りだが、まずはここから始めればいいと思った。センサーを使う際も、他人が書いたライブラリをいきなり使うのではなく、自分でデータシートを読んで使い方を調べ、どうしてもダメならライブラリの実装を見てみる、というアプローチを取った。

今年の7月、僕はArduinoとESP32を使って空気質モニタリングアプリを作った。内部ではMQTT、DHT11、MH-Z14Aを使用し、データ通信にはUARTを用いた。単にライブラリを流用するのではなく、MH-Z14Aに関してはデータシートをしっかりと読み込んで実装した。Wi-FiやMQTTの部分は既存のライブラリに頼ったものの、僕にとっては非常に多くの学びがあった。

これだけではまだ足りない。Arduinoという殻に邪魔されたくなかった。そこで僕はAmazonで伝説のMOS 6502を探した。

MOS 6502が名機と呼ばれる理由は、十分に安価でありながら性能面でも比較的優れていたため、ファミコンやApple IIなどにこの8ビットCPUが採用されたからだ。さらに、現代のCPUに比べて命令セットや設計が遥かにシンプルであるため、CPUの動作を理解しやすいという利点もある。

最初はワクワクしながら注文して届くのを待っていたのだが、後になってMOS 6502にはEEPROMが内蔵されていないことに気づいた。プログラムをEEPROMに書き込み、それをMOS 6502に読み込ませる必要があるのだ。しかし、現在僕が住んでいる日本で目的のEEPROMを手に入れる手軽なルートが見つからず、この計画は一旦断念することにした。

その代わりに選んだのがAVRだった。現在住んでいる場所の近くにたまたま電子部品店があり、そこにはATmegaシリーズの各種マイクロコントローラが売られていた。そこでいくつか適当に見繕って購入した(ATmega328、まさにArduino Unoで使われているMCUだ)。

ATmega328を使うメリットは、まずブレッドボードにちょうど収まるサイズであること、そして命令セットが比較的シンプルなことだ。さらに、次のようなAVR特有の利点もある:

  • レジスタが32個あり、他のアーキテクチャに比べてかなり多い(x86: 8個、ARM: 16個)
  • ほとんどの命令がわずか1クロックで実行可能
  • 大半のAVRチップはフラッシュメモリとEEPROMを内蔵しており、別途EEPROMを用意する必要がなく、読み込みの効率も良い

アセンブリ言語とハードウェアロジックの理解

ハードウェアの世界では、すべてが非常にシンプルになると同時に、非常に不便にもなる。例えばあるピンからHighを出力させたい場合、純粋なアセンブリ(AVR)では次のように書くことになる:

ldi r16, 0x01
out DDRB, r16
out PORTB, r16

まず 0x01 を r16 レジスタに格納し、次に DDRB レジスタ(data direction)を 0x01 に設定し、そして PORTB を 0x01 に設定する。やっていること自体は digitalWrite とよく似ている。

しかし意外にも、アセンブリ言語は想像していたほど難しくはなかった。もっとも、実務レベルのアセンブリを書くとなるとかなり難しいのだろうけれど。

割り込み(Interrupt)のより深い理解

割り込みメカニズムがどのように動作しているか(ハードウェア回路なども含め)を完全にマスターしたわけではないが、割り込み(Interrupt)についての理解は確実に深まった。

一般的なCPUでは割り込みベクタ(Interrupt Vector)が定義されており、割り込みが発生した際にCPUが何をすべきかが記述されている。そして割り込みを許可するかどうかは、通常 SREG のGlobal Interrupt Enableビットによって制御される。これにはレジスタ操作やビットシフトに対する十分な理解が必要なため、AVRでは通常いくつかの対応関数(avr/interrupt.h)が用意されている。

この部分は非常に面白い反面、トラブルも起こりやすい。トイプロジェクトなら問題ないが、実運用のプロダクション環境ではみんなどのように割り込み機構を管理し、デバッグしているのだろうか。

OS(オペレーティングシステム)を理解する

今年の3〜4月頃、CourseraのOSに関する講義を断続的に受講した。PC(プログラムカウンタ)、IR(Instruction Counter)、カーネルモード、ユーザーモード、アトミック性、スレッド、そしてセマフォ(semaphore)に至るまで理解を進めたが、実装面に関してはまだまだ見当もつかない。それでも、少なくとも「比較的」まともな理解は得られた。最近たまたま『30日でできる!OS自作入門』という本を見かけた。見た目は少しレトロで、多くの細部が省略されているのは間違いないが、面白そうだと思った。いつか時間ができたら挑戦してみたい。エミュレータを動かすより、僕はやっぱり実機で直接テストする方が好きなのだ!

operating system-30

プログラミング言語

今年の初め、たまたま松本行弘氏の著書『まつもとゆきひろ 言語のしくみ』を目にした。その中で彼はゼロから(yacc/lexを使って)プログラミング言語を実装し、その原理や実装方法を一つひとつ解説していた。その完成度の高さにはかなり驚かされた。単なる電卓のような四則演算にとどまらず、文字列、日時処理、数値、乱数、配列、アトミック性など、プログラミング言語として備えるべき基本的な機能が一通り実装されていたのだ。 僕も同じようなことをやってみたいと思ったが、yacc/lexのドキュメントが正直あまり理解できなかったため、C言語をもっと深く身につけてから再挑戦することにした。

もう一つは、IT鐵人賽に参加した際、ゼロから簡易版の Svelte(リアクティブ機能なし)の実装に挑戦し、シンプルなパーサーを書いたことだ。プログラミング言語の端っこに少しだけ触れられた気がする(笑)。

これからも学ぶべきことはまだまだたくさんある!みんなでこの混乱の1年を乗り越え、頑張っていこう!

関連記事

他のトピックを探索