3 ポイント 投稿者 GN⁺ 2024-04-10 | 1件のコメント | WhatsAppで共有

離散論理ネットワークカードの製作記

この記事は、離散論理回路を使って完全なコンピュータシステムを構築する過程を扱うシリーズの一部。これまでに、HTTPサーバーやLANゲームなどのネットワークアプリケーションを実行できるコンピュータを作成してきた。

概要

  • 昨年、10BASE-Tイーサネット信号をSPIに変換し、その逆変換も行う物理層アダプターを製作した。当時はSTM32マイクロコントローラーを使って動作をテストしていたが、今は自作コンピュータに接続するためにMAC層モジュールを実装している。
  • 2つのアダプターはいずれも全二重で、独立した送信部と受信部を備えている。

受信機

受信機の動作概要:

  • SPIシリアルデータがバイト単位のパラレルデータに変換され、バイトクロックが抽出される。
  • 最初の6バイトが宛先MACアドレスの基準値と比較され、一致しないフレームは破棄される。
  • バイトが静的RAMバッファに書き込まれる。
  • フレームが終了すると受信機は無効化され、ユーザーが受信機を再起動するまで追加のフレームは拒否される。バイトカウンターは停止し、その値がユーザーに提供される。

データ収集

  • シリアルSPIデータをバイトストリームに変換する必要がある。
  • シリアルデータはシフトレジスタ(U32)に取り込まれる。U30U31はそれぞれビット数とバイト数をカウントする。
  • 静的RAM書き込み信号recv_buf_weはDフリップフロップU29Bを使って生成される。この信号は入力データの各8ビットの後に短時間だけLowになる。
  • 受信したバイトは6116(U20) 2kB静的RAMバッファに記録される。
  • U13U16U18はアドレスマルチプレクサを構成し、バイトカウンターまたはシステムアドレスバスのいずれかを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を動作させるにはブロードキャストMAC FF: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件のコメント

 
GN⁺ 2024-04-10
Hacker Newsのコメント
  • このプロジェクトは、ハードウェアMACアドレスフィルタリングを実装したカスタムコンピュータ向けのイーサネットカードを作ったもので、作業過程の推論スタックトレースが教育的で素晴らしい。
  • 一般的なPC向けイーサネットカードの最小実装も似たようなものになるだろうが、PCのCPUでチェックサムを計算し、USBなどで接続することになるだろう。
  • このプロジェクトのために、Cコンパイラ、リンカ、libcなどを自作したのが印象的だ。
  • こうしたプロジェクトに注がれた情熱と努力に感嘆し、引退後にはこのようなハードウェア/ソフトウェアのプロジェクトをやってみたい。
  • 昔のEtherlink 3c501イーサネットカードは性能が良くなかった。
  • ディスクリートロジック回路でネットワークカードを作ったように見える。(ディスクリートロジックのネットワークカード、という意味ではなく)
  • すべてのネットワークカードがディスクリートロジック素子で作られているわけではないのか。(素朴な質問)
  • このコンピュータセットアップのモジュール性は素晴らしい。
  • シンプルかつ効果的に説明している点が印象的で、大いに励まされるに値する。