3 Punkte von GN⁺ 2024-04-10 | 1 Kommentare | Auf WhatsApp teilen

Bau einer Karte für diskrete logische Netzwerke

Dieser Artikel ist Teil einer Serie, die den Aufbau eines vollständigen Computersystems mit diskreten Logikschaltungen behandelt. Bisher wurde ein Computer gebaut, der Netzwerkanwendungen wie einen HTTP-Server oder LAN-Spiele ausführen kann.

Überblick

  • Im vergangenen Jahr wurde ein Physical-Layer-Adapter gebaut, der 10BASE-T-Ethernet-Signale in SPI umwandelt und umgekehrt. Damals wurde die Funktion mit einem STM32-Mikrocontroller getestet; jetzt wird ein MAC-Layer-Modul implementiert, um ihn mit dem selbstgebauten Computer zu verbinden.
  • Beide Adapter sind Vollduplex und verfügen über getrennte Sende- und Empfangsteile.

Empfänger

Zusammenfassung der Empfängerfunktion:

  • Serielle SPI-Daten werden in byteweise parallele Daten umgewandelt, und ein Byte-Takt wird extrahiert.
  • Die ersten 6 Bytes werden mit der Ziel-MAC-Adressreferenz verglichen; Frames ohne Übereinstimmung werden verworfen.
  • Die Bytes werden in einen statischen RAM-Puffer geschrieben.
  • Wenn der Frame endet, wird der Empfänger deaktiviert, und weitere Frames werden abgewiesen, bis der Benutzer den Empfänger erneut startet. Der Byte-Zähler stoppt, und sein Wert wird dem Benutzer bereitgestellt.

Datenerfassung

  • Serielle SPI-Daten müssen in einen Bytestrom umgewandelt werden.
  • Die seriellen Daten werden in das Schieberegister (U32) geschoben. U30 und U31 zählen jeweils Bits und Bytes.
  • Das statische-RAM-Schreibsignal recv_buf_we wird mit dem D-Flipflop U29B gebildet. Dieses Signal geht nach jeweils 8 Bit der Eingangsdaten kurz auf Low.
  • Empfangene Bytes werden in den 2-kB-Static-RAM-Puffer 6116 (U20) geschrieben.
  • U13, U16, U18 bilden einen Adressmultiplexer, der entweder den Byte-Zähler oder den System-Adressbus als Adresseingang für das SRAM (U20) auswählt.
  • Der Tri-State-Puffer U21 leitet die empfangenen Bytes in den RAM weiter.

MAC-Adressfilterung

  • Bei der Analyse von Ethernet-Traffic wurde festgestellt, dass Frames normalerweise in kleinen Gruppen ankommen (3–4 Frames, getrennt durch kurze Verzögerungen). Die Frames innerhalb einer Gruppe haben in der Regel unterschiedliche Ziel-MAC-Adressen.
  • Das führte zu der Vermutung, dass der Computer empfangene Frames nicht schnell genug nach MAC filtern und den Empfänger nicht schnell genug neu starten könnte, um für ihn bestimmte Frames zu erwischen. Eine Hardware-MAC-Adressfilterung war nötig.
  • Eine benutzerdefinierte MAC-Adresse irgendwo zu speichern und dann mit den ersten 6 empfangenen Bytes zu vergleichen, wäre zu kompliziert. Man könnte sie auch aus der Wiederholung eines einzelnen Bytes machen (z. B. FE:FE:FE:FE:FE:FE), aber das wäre langweilig.
  • Um der eigenen MAC etwas Variation zu geben, wurde sie als Funktion des Byte-Index definiert:
    • Bit 0 ist fest auf 0 gesetzt
    • Bit 1 ist fest auf 1 gesetzt
    • Bit 2–4 sind die Invertierung des Byte-Index
    • Bit 5–7 sind fest auf 1 gesetzt
  • Mit dieser Regel ergibt sich die MAC-Adresse FE:FA:F6:F2:EE:EA. Damit es auch mit ARP funktioniert, muss außerdem die Broadcast-MAC FF:FF:FF:FF:FF:FF akzeptiert werden.

Sender

  • Ähnlich wie beim Empfänger implementiert der Sender keine FCS-Erzeugung in Hardware; diese wird in Software ausgeführt.
  • Um den Sender weiter zu vereinfachen, wurde entschieden, nur Frames mit fester Länge zu unterstützen. Dadurch ist kein komplexer digitaler Komparator erforderlich, und die Frame-Übertragungslogik hängt nur von einem einzelnen Bit des Byte-Zählers ab.
  • Als Frame-Länge wurden 1024 Bytes gewählt, was nahe an der üblichen MTU von 1500 Bytes liegt.
  • Auch die für 10BASE-T benötigte Frame-Präambel (eine Folge von 0x55, gefolgt von 0xD5) ist in diesen 1024 Bytes enthalten und muss von der Software geladen werden.

Zähler

  • Wie beim Empfänger werden zwei Zähler zum Zählen von Bits (U12) und Bytes (U14) verwendet.
  • Der erste Zähler wird mit dem 20-MHz-Takt des integrierten Oszillators gespeist.
  • Die 20 MHz werden nicht direkt verwendet, sondern mindestens durch 2 geteilt. Dadurch beeinflusst das Tastverhältnis des Oszillators das Ausgangssignal nicht.

Datenfluss

  • Um die Adresseingänge des RAM (U22) auszuwählen, werden dieselben drei 74HC157-Multiplexer wie im Empfänger verwendet (hier nicht gezeigt).
  • U23 wird verwendet, um Daten in den RAM zu laden.
  • U24 dient als Zwischenspeicher für das aktuell gesendete Byte. Die Idee dahinter ist ähnlich wie bei meiner VGA-Pipeline.
  • Der Byte-Zähler 74HC4040 ist ein Ripple-Counter und benötigt Zeit, um sich zu stabilisieren; U24 liefert daher einen stabilen Ausgang, während die RAM-Ausgabe noch nicht gültig ist.
  • Diese Daten werden in das Schieberegister U28 eingespeist und bitweise verschoben.

CPU-Schnittstelle

Aus Sicht des Programmierers sieht die Schnittstelle meines Ethernet-Adapters wie folgt aus:

  • Beide Frame-Puffer sind auf 0xF000 gemappt.
  • Es gibt zwei schreibgeschützte Register:
    • Das 8-Bit-Statusregister bei 0xFB00 enthält zwei Flags:
      • RX_FULL - ein Frame wurde empfangen
      • TX_BUSY - ein Frame wird gerade übertragen
    • Das 16-Bit-Register für die Länge der Empfangsdaten bei 0xFB02
  • Wenn ein beliebiger Wert nach 0xFB00 geschrieben wird, wird der Empfänger neu gestartet.
  • Wenn ein beliebiger Wert nach 0xFB01 geschrieben wird, beginnt die Übertragung.
  • Es gibt keine Interrupts, da meine CPU keine Interrupts unterstützt.

Programmierung

Ich wollte Netzwerkunterstützung, aber keinen TCP/IP-Stack selbst implementieren. Außerdem war mein erster Compiler miserabel, und das Programmieren in Assembler war mühsam, also wollte ich einen ordentlichen C-Compiler. Also habe ich einen C-Compiler gebaut. Er ist inzwischen ausgereift genug, um uIP 1.0 (eine kleine TCP/IP-Bibliothek) zu kompilieren. Trotz der sehr geringen Codedichte meiner CPU ist uIP klein genug, um in den RAM zu passen, und lässt noch Platz für echte Anwendungen.

Die Netzwerkleistung ist sehr niedrig, aber angesichts der Tatsache, dass weder kommerzielle CPUs noch Spezialchips verwendet wurden, bin ich dennoch sehr zufrieden:

  • durchschnittliche Ping-Round-Trip-Zeit von 85 ms
  • HTTP-Server-Downloadrate von 2.6kB/s (Auslieferung statischer Dateien von der SD-Karte)

Projekt-Repository

Modelle, Schaltplandateien und PCB-Zeichnungen befinden sich auf GitHub.

Meinungen von GN⁺

  • Dieses Projekt zeigt das tiefe Hardwareverständnis und die Leidenschaft des Entwicklers. Der Versuch, alles selbst zu implementieren, ist äußerst beeindruckend, wirft aber Fragen hinsichtlich der Praktikabilität auf.
  • Moderne Computersysteme sind sehr komplex und spezialisiert, sodass es sehr ineffizient ist, alles von Grund auf selbst zu implementieren. Gerade in gut etablierten und optimierten Bereichen wie Netzwerkprotokoll-Stacks ist es klug, bestehende Implementierungen zu nutzen.
  • Trotzdem haben solche Projekte einen sehr hohen Bildungswert. Man kann direkt erfahren, wie Low-Level-Hardware und Software zusammenspielen und wie Protokolle implementiert werden.
  • Außerdem kann ein solches Projekt in einer Zeit, in der das Hardwareverständnis unter Entwicklern abnimmt, als wertvolles Beispiel dienen, das an die Grundlagen von Computersystemen erinnert.
  • Schade ist nur, dass die Leistung sehr gering ist. Um die praktische Nutzbarkeit zu erhöhen, wäre eine stärker optimierte Implementierung nötig. Das scheint jedoch nicht das Hauptziel dieses Projekts zu sein.

1 Kommentare

 
GN⁺ 2024-04-10
Hacker-News-Kommentare
  • Dieses Projekt hat eine Ethernet-Karte für einen benutzerdefinierten Computer erstellt, die Hardware-MAC-Adressfilterung implementiert, und der nachvollziehbare Stack-Trace des Arbeitsprozesses ist lehrreich und hervorragend.
  • Eine minimale Implementierung einer Ethernet-Karte für einen normalen PC wäre vermutlich ähnlich, aber man müsste die Prüfsumme auf der CPU des PCs berechnen und sie etwa über USB anschließen.
  • Beeindruckend ist, dass für dieses Projekt ein C-Compiler, Linker, libc usw. selbst erstellt wurden.
  • Ich bin beeindruckt von der Leidenschaft und dem Aufwand, die in ein solches Projekt geflossen sind, und würde nach meiner Pensionierung gern einmal ein solches Hardware-/Softwareprojekt ausprobieren.
  • Die frühere Etherlink-3c501-Ethernet-Karte hatte keine gute Leistung.
  • Es scheint, als sei eine Netzwerkkarte aus diskreter Logik gebaut worden. (nicht eine „diskrete Logik-Netzwerkkarte“)
  • Nicht alle Netzwerkkarten werden aus diskreten Logikbausteinen hergestellt. (naive Frage)
  • Die Modularität dieses Computer-Setups ist hervorragend.
  • Beeindruckend ist, wie einfach und effektiv es erklärt wurde; das verdient große Anerkennung.