Ayrık mantıkla 10BASE-T ağ kartı yapımı
(qdiv.dev)- Ticari CPU veya özel ağ çipi kullanmadan yapılmış ayrık mantık bilgisayarına 10BASE-T Ethernet gönderme/alma işlevi ekleyen bir donanım yapım yazısı
- Daha önce yapılan 10BASE-T↔SPI fiziksel katman adaptörünün üzerine MAC katmanı modülü eklenerek homebrew computer'a bağlanıyor; verici ve alıcı bağımsız, tam çift yönlü bir yapıda
- Alıcı, SPI verisini baytlara dönüştürüp 2 kB SRAM'e kaydediyor; ilk 6 baytı donanımda kontrol ederek yalnızca
FE:FA:F6:F2:EE:EAveya yayın MAC adresini kabul ediyor - Verici, devreyi basitleştirmek için FCS üretimini ve preamble hazırlığını yazılıma bırakıyor ve yalnızca 1024 bayt sabit uzunlukta çerçeveleri destekliyor
- uIP 1.0'ı derleyebilen bir C derleyicisi de geliştirilerek ağ uygulamaları çalıştırılmış; sonuçlar ortalama 85 ms ping ve 2,6 kB/s düzeyinde HTTP statik dosya indirme hızı
Ayrık mantık bilgisayarına Ethernet eklemek
- Tam bir bilgisayar sistemini ayrık mantık bileşenleriyle yapma çalışmasının devamı olarak, ağ uygulamalarını çalıştırabilen bir Ethernet adaptörü gerçekleştiriliyor
- Daha önce 10BASE-T Ethernet sinyalini SPI'ye dönüştürüp geri çeviren bir fiziksel katman adaptörü yapılmıştı; o dönemde çalışma testleri için STM32 mikrodenetleyici kullanılmıştı
- Bu çalışmanın özü, o adaptörü homebrew computer'a bağlamak için geliştirilen MAC katmanı modülü
- Adaptör tam çift yönlü yapıda; gönderme ve alma birimleri birbirinden bağımsız çalışıyor
Alıcı: SPI verisini çerçeve arabelleğine kaydetme
- Alıcı, SPI seri verisini bayt düzeyinde paralel veriye dönüştürüyor ve bayt saatini çıkarıyor
- Hedef MAC adresi ilk 6 baytta kontrol ediliyor; ölçütlere uymayan çerçeveler reddediliyor
- Alınan baytlar 6116 2 kB SRAM arabelleğine yazılıyor
- Çerçeve bittiğinde alıcı devre dışı kalıyor ve yeniden etkinleştirilene kadar ek çerçeve almıyor
- Bayt sayacı durduktan sonra da değerini koruyor; böylece CPU alınan uzunluğu okuyabiliyor
- FCS donanımda kontrol edilmiyor
-
Veri toplama ve arabellek erişimi
- SPI seri verisi
U32kaydırma yazmacına giriyor;U30veU31sırasıyla bitleri ve baytları sayıyor - D flip-flop
U29B, SRAM yazma sinyalirecv_buf_we'yi üretiyor; bu sinyal her 8 bit giriş verisinde kısa süreliğine düşük seviyeye iniyor - Alınan baytlar
U20olan 6116 SRAM'e yazılıyor U13,U16,U18, SRAM adres girişine bayt sayacını veya sistem adres veriyolunu seçen adres çoklayıcısını oluşturuyorU21, alınan baytları RAM'e aktaran üç durumlu arabellek görevi görüyor- CPU'nun alınan verilere ve uzunluğa erişebilmesi için RAM ve bayt sayacı sistem veri veriyoluna bağlanıyor
U25, alıcı RAM'ini sistem veri veriyoluna bağlıyor- Çerçeve tamamlandıktan sonra bayt sayacı değeri
recv_byte_cntveriyolunda tutuluyor U26,U27, belirli bir adres okuma isteği geldiğinde bu değeri sistem veri veriyoluna aktarıyorU27'nin kalan yarısı, alıcı ve verici durumunu sorgulayan 2 bitlik salt okunur durum yazmacını oluşturuyor
- SPI seri verisi
Donanımsal MAC adresi filtreleme
- Ethernet trafiği analiz edildiğinde çerçevelerin genelde kısa gecikmelerle ayrılmış 3-4'lü küçük gruplar halinde geldiği, aynı grup içinde bile hedef MAC adreslerinin çoğu zaman farklı olduğu görüldü
- Bilgisayarın MAC filtrelemeyi yazılımla yapıp alıcıyı yeniden etkinleştirmesi yeterince hızlı olmayabileceğinden donanımsal MAC filtreleme gerekiyordu
- Özel bir MAC adresini saklayıp ilk 6 baytla karşılaştırma yöntemi fazla karmaşık olduğu için elendi
- Tek bayt tekrarlı MAC adresi de mümkündü; ancak sonunda MAC adresi, bayt indeksinin bir fonksiyonu olarak oluşturuldu
- bit 0 sabit 0
- bit 1 sabit 1
- bit 2~4 bayt indeksinin ters değeri
- bit 5~7 sabit 1
- Bu kuralla oluşturulan MAC adresi
FE:FA:F6:F2:EE:EA - ARP'nin çalışması için yayın MAC adresi
FF:FF:FF:FF:FF:FFde kabul ediliyor U33, veri bit 0 ile bit 2~4'ün istenen değerlerle eşleşip eşleşmediğini karşılaştırıyor;U34Açıkışı bu bitler eşleştiğinde yüksek oluyorU35A, yayın MAC kontrolünü gerçekleştiriyor; bit 0 ve bit 2~4'ün tamamı 1 ise çıkış yüksek oluyor- İki sinyal,
D7veR6kullanan diyot OR ile birleştiriliyor;U35Bise kalan bitlerin tamamının 1 olup olmadığını kontrol ediyor - Tek bir baytın geçerlilik sonucu
U10A'da biriktiriliyor- Çerçeve alınmazken gelen SPI slave select sinyali
ssdüşük seviyede veU10A1'e ayarlanıyor - Çerçeve alımı sırasında değer her alınan baytta güncelleniyor
- Hedef MAC adresi ölçütlere uyuyorsa
U10Adeğeri yüksek kalıyor - Bayt adresi 5'e ulaştığında son değer
U36B'ye latch'leniyor; hedef adres uymuyorsa çerçeve alımı engelleniyor
- Çerçeve alınmazken gelen SPI slave select sinyali
Verici: devreyi basitleştirmek için sabit uzunlukta çerçeveler
- Verici de alıcı gibi FCS üretimini donanımda gerçekleştirmiyor; yazılımla işliyor
- Devreyi azaltmak için verici yalnızca sabit uzunlukta çerçeveleri destekliyor
- Çerçeve uzunluğu 1024 bayt olarak seçildi; bu, yaygın MTU değeri olan 1500 bayta yakın
- 10BASE-T için gereken preamble, birden çok
0x55ve sondaki0xD5'ten oluşuyor; yazılım bunu da 1024 baytın içine yüklemeli - Sabit çerçeve uzunluğu üst protokolleri etkilemiyor
- Üst protokoller paket boyutunu başlıklarda kodluyor
- Gerçek Ethernet çerçevesi uzunluğuna bağlı değiller
-
Gönderim veri akışı
- Gönderilecek veri SRAM'de saklanıyor
- 20 MHz saat 4 bitlik sayaca giriyor; taşma çıkışı bayt saati olarak kullanılıyor
- Yalnızca yazılabilir belirli bir bellek konumuna değer yazıldığında sayaç etkinleşiyor ve çerçeve gönderimi başlıyor
- Paralel bayt verisi, kaydırma yazmacı üzerinden serileştiriliyor
- Alıcıda olduğu gibi
U12bitleri,U14baytları sayıyor - 20 MHz saat entegre osilatörden geliyor; doğrudan kullanılmayıp en az 2'ye bölünerek kullanılıyor
- Bu yöntem, osilatörün görev döngüsünün çıkış sinyalini etkilememesini sağlıyor
-
RAM, kaydırma yazmacı ve zamanlama
- RAM
U22'nin adres girişi seçimi için, alıcıdaki gibi üç adet 74HC157 çoklayıcı kullanılıyor U23, RAM'e veri yüklemek için kullanılıyorU24, o anda gönderilmekte olan bayt için ara depolama görevi görüyor- Bayt sayacı 74HC4040 bir ripple counter olduğundan kararlı hale gelmesi yavaş
- RAM çıkışı henüz geçerli değilken
U24kararlı bir çıkış sağlıyor - Veri,
U28kaydırma yazmacına girerek bit bit ilerliyor - RAM'den kaydırma yazmacına giden bit sırasının yanlış bağlandığı bir donanım hatası olduğundan, yazılımda bitleri karıştırarak bunun etrafından dolaşmak gerekti
MOSIveSCK, iyi bir 10BASE-T sinyali üretmek için tam olarak senkronize olmalıU11AveU8Bbu senkronizasyonu gerçekleştiriyortx_cnt0, bit sayacının bit 0'ı; 20 MHz'i 2'ye bölmüş sinyal olarak saat için kullanılıyorU11Abu sinyale göre çıkışını değiştiriyorU8B,U11A'nın oluşturduğu gecikmeye uyum sağlamak için saati geciktiriyor- D latch, basit AND kapısına göre daha karmaşık ve yaklaşık 5 ns daha fazla gecikmeye sahip olduğundan daha hızlı 74LV74A kullanılıyor
- 74LV74A bu karttaki hızlı aileden tek çip
- RAM
CPU arayüzü ve bellek eşleme
- Programcı açısından Ethernet adaptörü bellek eşlemeli bir arayüz gibi görünüyor
- İki çerçeve arabelleği
0xF000adresine eşleniyor - İki salt okunur yazmaç var
0xFB00adresindeki 8 bitlik durum yazmacındaRX_FULLveTX_BUSYbayrakları bulunuyorRX_FULL, çerçeve alımının tamamlandığı durumu gösteriyorTX_BUSY, çerçeve gönderiminin sürdüğü durumu gösteriyor0xFB02adresindeki 16 bitlik yazmaç alınan veri uzunluğunu içeriyor
- Yazma işlemleri kontrol komutu olarak kullanılıyor
0xFB00adresine herhangi bir değer yazmak alıcıyı yeniden etkinleştiriyor0xFB01adresine herhangi bir değer yazmak gönderimi başlatıyor
- CPU kesmeleri desteklemediği için kesme yok
- İlgili adreslerin tamamı üst 4 biti 1 olan
File başlıyor; bu koşuluU2Akontrol ediyor - Arabellek adreslerinde bit 11'in 0 olması gerekiyor;
U1D,D2,R2,U1Ebunu kontrol ediyor - Yazmaç adreslerinde ikinci onaltılık basamağın
B, yani1011olması gerekiyor;U1BveU2Bbunu doğruluyor U4A,U4Bkod çözücüleri ayrı işlevlerin seçimi için kullanılıyor- İki LED, arabellek veya yazmaç erişimini gösteriyor
Programlama ve performans
- Ağ desteği istense de TCP/IP yığınını baştan yazmak istenmediğinden ve assembly programlama da zahmetli olduğundan bir C derleyicisi geliştirildi
- Bu derleyici, küçük bir TCP/IP kitaplığı olan uIP 1.0'ı derleyebilecek kadar olgun
- CPU'nun kod yoğunluğu çok düşük olsa da uIP RAM'e sığıyor ve gerçek uygulamalar için de yer kalıyor
- Ağ performansı düşük, ancak bu ticari CPU veya özel çip olmadan elde edilmiş bir sonuç
- Ping gidiş-dönüş ortalaması: 85 ms
- HTTP sunucusu indirme hızı: 2,6 kB/s
- HTTP sunucusu SD karttaki statik dosyaları sunuyor
- Model, devre şeması dosyaları ve PCB çizimleri GitHub deposunda bulunuyor
1 yorum
Hacker News yorumları
Paylaştığın için teşekkürler, harika bir iş. Özellikle akıl yürütme sürecinin stack trace’i çok hoşuma gitti; birçok şeyi ilk ilkelerden çözmesi ya da yeni başlayan bakış açısıyla açıklamaya çalışması eğitim açısından çok değerli.
Gerçek ağ kullanımı için pratik olmasa da bunun basit bir oyuncaktan ibaret olmadığını düşünüyorum. Aşırı karmaşık ağ çiplerinde backdoor’ların bulunduğu bir çağda, ileride daha ciddi bir okur kitlesi ya da proje motivasyonu da oluşabilir.
Bu tamamen özel yapım bir bilgisayar için olduğundan, başlı başına çok daha etkileyici; “bu yüzden bir C derleyicisi yaptım” kısmını söylemeye bile gerek yok. Yine de “sıradan” bir PC için Ethernet kartının asgari uygulaması ne kadar olurdu diye merak ediyorum.
Büyük kısmı benzer olur gibi; checksum işlemi PC CPU’suna yaptırılabilir. Bağlantı ham seri hat olabilir ya da daha pratik olarak USB gerekir; sonuçta ya “gerçek” bir sürücü kullanmak ya da işi kullanıcı alanına devredip orada işlemek gerekecek gibi.
Benzer şeylere bakarken, cihaz https://en.wikipedia.org/wiki/USB_communications_device_clas... uygularsa kendi sürücüsü olmadan “öylece çalıştırmak” mümkün olmaz mı diye düşünmüştüm; ama tüm checksum’ları host tarafında işlemekle pek uyuşmayacak gibi.
Ararken https://en.wikipedia.org/wiki/Ethernet_over_USB sayfasını da buldum; bu, sadece fiziksel bağlantıyı USB’ye çeviren bir adaptör yapıp gerisini bilgisayarın halletmesini sağlamak mümkün olabilir anlamına mı geliyor, emin değilim.
FTDI tarzı bir USB cihazını 10base2 Ethernet’i bit-bang etmeye ikna etmek belki mümkün olabilir. Hat trafiğini temiz bir bit akışına dönüştüren ve frame başlangıcını hizalayan “PHY” tarafını uygulayıp, geri kalan her şeyi PC’nin yazılımla işlemesini sağlamak gibi.
USB tarafında CDC-NCM’nin kendisini herhangi bir MCU’da uygulamak zor değil; ama USB HS PHY uygulaması pratikte ASIC donanım gerektiriyor.
0,30 dolarlık bir USB HS ULPI PHY kullanılırsa, FPGA’da USB CDC-NCM’yi epey kolay uygulamak mümkün olurdu.
Son kısımda bu proje için yapılan C derleyicisinin bağlantısı var: https://github.com/imihajlow/ccpu-cc
Görünüşe göre linker ve libc de var. Donanım tasarımının ne kadar karmaşık olduğunu tam bilmiyorum ama C derleyicisini hafifçe yapıp eklemiş olması müthiş.
Gerçekten etkileyici. Böyle bir projeyi ben de denemek isterdim; sistemi anlayıp ardından onu yapmaya harcanan tutkuyu ve sayısız saati takdir etmemek elde değil.
Emekliliği özellikle istemiyorum ama belki o zamanlar böyle donanım-yazılım projelerine zaman ayırırım.
Peki bu Etherlink 3c501’den daha mı iyi, yoksa daha mı kötü? :-D
https://mirror.math.princeton.edu/pub/oldlinux/Linux.old/net...
Yanlış hatırlamıyorsam, CPU’nun okumaya çalıştığı buffer’ın ağdan gelen yeni paket tarafından üzerine yazılması gibi bir durum vardı. Bir süre Linux’ta kullandım; performansı gerçekten berbattı.
Sürücü ve firmware güncellemelerinin ne kadar çok şeyi gözden sakladığı şaşırtıcı.
Benimkinde iki buffer var, o yüzden daha iyi :) Yine de yalnızca tek bir alınan frame saklanıyor.
“Frame uzunluğunu sabitlemek üst protokolleri etkilemez. Çünkü üst protokoller paket boyutunu header’da kodlar ve gerçek Ethernet frame uzunluğuna dayanmaz” kısmı ilginç.
Yakın zamanda bir paket decoder’ı yaptım; her katmanda alt katman uzunluğunun uyup uymadığını açıkça doğruladım. IP için benim decoder’ımda IP datagram uzunluğunun Ethernet frame uzunluğu ve link katmanı header uzunluğuyla tam olarak eşleşmesi gerekiyor.
Bunu titiz olmak için değil, kısa frame’leri tespit etmek için yapmıştım; daha sonra uzun frame’leri de hata saymaya karar verdim. Yazar uIP kullanıyor ama Linux’un ya da başka modern OS’lerin bunu nasıl ele aldığını merak ediyorum. Birlikte çalışabilirlik testi yapıp yapmadığını da merak ettim.
Uygulama L2 verisini görmüyorsa Linux IP stack’i bunu sadece yok sayıyor.
DEC’in ilk SSI Ethernet kart setinden fiziksel olarak çok daha küçük: https://i.ebayimg.com/images/g/NEYAAOSw-mZlg0lZ/s-l1600.jpg
DEC DEUNA kartları 1 feet’ten daha uzun ama işlevleri de çok daha fazla. DEUNA “gerçek” bir NIC; gönderme/alma kuyrukları var, bunları otonom biçimde işliyor ve DMA da yapıyor. Tabii kartın üzerinde bunları çalıştıran kendi PDP-11’i de var.
Gerçekten harika. Ne kadar sürdüğünü merak ediyorum.
Ağ portuna bağlı bir çipin içine backdoor yerleştirmenin ne kadar kolay olduğunu gösteriyor.
Communication Systems Engineering dersinde Ethernet sinyal işlemeyi uygulamıştık; ardından ARP ve switching dahil TCP/IP stack’ini Motorola 68k QUIC assembly ile uyguladık.
Hayatımın en uzun 18 ayıydı.