Show HN: 離散論理ネットワークカードの製作
(qdiv.dev)離散論理ネットワークカードの製作記
この記事は、離散論理回路を使って完全なコンピュータシステムを構築する過程を扱うシリーズの一部。これまでに、HTTPサーバーやLANゲームなどのネットワークアプリケーションを実行できるコンピュータを作成してきた。
概要
- 昨年、10BASE-Tイーサネット信号をSPIに変換し、その逆変換も行う物理層アダプターを製作した。当時はSTM32マイクロコントローラーを使って動作をテストしていたが、今は自作コンピュータに接続するためにMAC層モジュールを実装している。
- 2つのアダプターはいずれも全二重で、独立した送信部と受信部を備えている。
受信機
受信機の動作概要:
- SPIシリアルデータがバイト単位のパラレルデータに変換され、バイトクロックが抽出される。
- 最初の6バイトが宛先MACアドレスの基準値と比較され、一致しないフレームは破棄される。
- バイトが静的RAMバッファに書き込まれる。
- フレームが終了すると受信機は無効化され、ユーザーが受信機を再起動するまで追加のフレームは拒否される。バイトカウンターは停止し、その値がユーザーに提供される。
データ収集
- シリアルSPIデータをバイトストリームに変換する必要がある。
- シリアルデータはシフトレジスタ(
U32)に取り込まれる。U30とU31はそれぞれビット数とバイト数をカウントする。 - 静的RAM書き込み信号
recv_buf_weはDフリップフロップU29Bを使って生成される。この信号は入力データの各8ビットの後に短時間だけLowになる。 - 受信したバイトは6116(
U20) 2kB静的RAMバッファに記録される。 U13、U16、U18はアドレスマルチプレクサを構成し、バイトカウンターまたはシステムアドレスバスのいずれかをSRAM(U20)のアドレス入力として選択する。- 3状態バッファ
U21が受信したバイトをRAMへ渡す。
MACアドレスフィルタリング
- イーサネットトラフィックを分析したところ、フレームはたいてい小さなグループ(短い遅延で区切られた3〜4個のフレーム)で届くことが分かった。1つのグループ内のフレームは通常、互いに異なる宛先MACアドレスを持っている。
- そのため、このコンピュータがMACごとに受信フレームをフィルタリングしつつ、受信機を十分な速さで再起動して自分宛てのフレームを取りこぼさずに捕まえるのは無理だと考えるようになった。ハードウェアによるMACアドレスフィルタリングが必要だった。
- ユーザー定義のMACアドレスをどこかに保存し、最初の6つの受信バイトと比較する方法は複雑すぎる。単一バイトの繰り返し(例: FE:FE:FE:FE:FE:FE)にすることもできるが、面白みに欠ける。
- そこで、自分のMACに少し変化を持たせるため、バイトインデックスの関数として作ることにした:
- ビット0は0に固定
- ビット1は1に固定
- ビット2〜4はバイトインデックスの反転
- ビット5〜7は1に固定
- この規則を使うと、MACアドレスは
FE:FA:F6:F2:EE:EAになる。また、ARPを動作させるにはブロードキャストMACFF:FF:FF:FF:FF:FFも受け付ける必要がある。
送信機
- 受信機と同様に、送信機はFCS生成を実装しておらず、これはソフトウェア側で処理される。
- 送信機をさらに単純化するため、固定長フレームのみをサポートすることにした。こうすると複雑なデジタルコンパレータが不要になり、フレーム送信ロジックはバイトカウンターの単一ビットにだけ依存すればよい。
- フレーム長は1024バイトに設定した。これは一般的なMTUである1500バイトに近い。
- 10BASE-Tで必要なフレームプリアンブル(0x55のシーケンスの後に0xD5が続くもの)も1024バイトに含まれ、ソフトウェアからロードする必要がある。
カウンター
- 受信機と同様に、ビット(
U12)とバイト(U14)を数えるために2つのカウンターが使われる。 - 最初のカウンターには内蔵発振器の20MHzクロックが供給される。
- 20MHzは直接は使われず、少なくとも2分周される。これにより、発振器のデューティサイクルが出力信号に影響しなくなる。
データフロー
- RAM(
U22)のアドレス入力を選択するため、受信機と同じ3つの74HC157マルチプレクサ(ここには表示されていない)が使われる。 U23はデータをRAMにロードするために使用される。U24は現在送信中のバイトの中間保存領域として機能する。ここでの考え方は自作のVGAパイプラインに似ている。- バイトカウンター74HC4040はリップルカウンターであり、安定化に時間がかかるため、
U24がRAM出力がまだ有効でない間も安定した出力を提供する。 - このデータはシフトレジスタ
U28に供給され、ビット単位でシフトされる。
CPUインターフェース
プログラマーの観点では、このイーサネットアダプターのインターフェースは次のようになっている:
- 2つのフレームバッファはいずれも
0xF000にマップされている。 - 2つの読み取り専用レジスタがある:
0xFB00の8ビットステータスレジスタには2つのフラグがある:RX_FULL- フレームを受信済みTX_BUSY- フレームを送信中
0xFB02の16ビット受信データ長レジスタ
0xFB00に任意の値を書き込むと受信機が再起動する。0xFB01に任意の値を書き込むと送信が開始される。- 自作CPUは割り込みをサポートしていないため、割り込みはない。
プログラミング
ネットワーク対応は欲しかったが、TCP/IPスタックを自分で実装したいとは思わなかった。また、最初のコンパイラはひどい出来で、アセンブリでプログラミングするのも面倒だったため、まともなCコンパイラが欲しかった。そこでCコンパイラを作った。これはuIP 1.0(小型TCP/IPライブラリ)をコンパイルできる程度には成熟している。自作CPUのコード密度は非常に低いにもかかわらず、uIPはRAMに収まるほど十分小さく、実際のアプリケーション用の空き領域も残っている。
ネットワーク性能は非常に低いが、商用CPUや専用チップを使っていないことを考えると、それでも十分に満足している:
- 平均ping往復時間 85ms
- HTTPサーバーのダウンロード速度 2.6kB/s(SDカードから静的ファイルを配信)
プロジェクトリポジトリ
モデル、回路図ファイル、PCB図面はGitHubにある。
GN⁺の意見
- このプロジェクトは、開発者のハードウェアに対する深い理解と情熱を示している。すべてを自分で実装しようとする試みは非常に印象的だが、実用性の面では疑問も残る。
- 現代のコンピューティングシステムは非常に複雑かつ専門化されており、すべてをゼロから実装するのはきわめて非効率だ。特にネットワークプロトコルスタックのように、よく確立され最適化された領域では、既存実装を活用するのが賢明だ。
- それでも、このようなプロジェクトの教育的価値は非常に高い。低レベルのハードウェアとソフトウェアがどのように相互作用し、プロトコルがどのように実装されるのかを直接体験できるからだ。
- また、近年の開発者のあいだでハードウェアへの理解が薄れつつある状況において、このようなプロジェクトはコンピュータシステムの基盤を思い起こさせる貴重な例になり得る。
- 惜しい点は性能が非常に低いこと。実用性を高めるには、さらに最適化された実装が必要に見える。ただし、それがこのプロジェクトの主目的ではないようだ。
1件のコメント
Hacker Newsのコメント