3 คะแนน โดย GN⁺ 2024-04-10 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

บันทึกการสร้างการ์ดเครือข่ายลอจิกแบบดิสครีต

บทความนี้เป็นส่วนหนึ่งของชุดบทความที่ว่าด้วยกระบวนการสร้างระบบคอมพิวเตอร์ที่สมบูรณ์โดยใช้วงจรลอจิกแบบดิสครีต จนถึงตอนนี้ได้สร้างคอมพิวเตอร์ที่สามารถรันแอปพลิเคชันเครือข่ายอย่าง HTTP server หรือเกมผ่าน LAN ได้แล้ว

ภาพรวม

  • เมื่อปีที่แล้วได้สร้างอะแดปเตอร์ชั้นกายภาพที่แปลงสัญญาณอีเธอร์เน็ต 10BASE-T ไปเป็น SPI และแปลงกลับได้ด้วย ตอนนั้นทดสอบการทำงานด้วยไมโครคอนโทรลเลอร์ STM32 และตอนนี้กำลังพัฒนาโมดูลชั้น MAC เพื่อเชื่อมต่อเข้ากับคอมพิวเตอร์ที่สร้างขึ้นเอง
  • อะแดปเตอร์ทั้งสองเป็นแบบฟูลดูเพล็กซ์และมีส่วนส่งกับส่วนรับที่แยกจากกันอย่างอิสระ

ตัวรับ

สรุปการทำงานของตัวรับ:

  • ข้อมูลอนุกรม SPI ถูกแปลงเป็นข้อมูลขนานระดับไบต์ และดึงสัญญาณนาฬิกาไบต์ออกมา
  • 6 ไบต์แรกจะถูกนำไปเทียบกับค่าอ้างอิงของที่อยู่ MAC ปลายทาง และเฟรมที่ไม่ตรงกันจะถูกปฏิเสธ
  • ไบต์จะถูกเขียนลงในบัฟเฟอร์ static RAM
  • เมื่อเฟรมสิ้นสุด ตัวรับจะถูกปิดการทำงาน และจะปฏิเสธเฟรมเพิ่มเติมจนกว่าผู้ใช้จะสตาร์ตตัวรับใหม่ ตัวนับไบต์จะหยุดและค่าดังกล่าวจะถูกส่งให้ผู้ใช้

การเก็บข้อมูล

  • ต้องแปลงข้อมูล SPI แบบอนุกรมให้เป็นสตรีมข้อมูลระดับไบต์
  • ข้อมูลอนุกรมจะถูกเลื่อนเข้า shift register (U32) U30 และ U31 ใช้นับบิตและไบต์ตามลำดับ
  • สัญญาณเขียน static RAM recv_buf_we ถูกสร้างโดยใช้ D flip-flop U29B สัญญาณนี้จะลดลงเป็นช่วงสั้น ๆ หลังจากข้อมูลอินพุตแต่ละชุดครบ 8 บิต
  • ไบต์ที่รับมาได้จะถูกเขียนลงในบัฟเฟอร์ static RAM ขนาด 2kB ของ 6116 (U20)
  • U13, U16, U18 สร้าง address multiplexer เพื่อเลือกให้ใช้อย่างใดอย่างหนึ่งระหว่างตัวนับไบต์หรือบัสที่อยู่ของระบบเป็นอินพุตที่อยู่ของ SRAM (U20)
  • tri-state buffer U21 ใช้ส่งไบต์ที่รับมาเข้า RAM

การกรองที่อยู่ MAC

  • ระหว่างการวิเคราะห์ทราฟฟิกอีเธอร์เน็ต พบว่าเฟรมมักจะมาเป็นกลุ่มเล็ก ๆ (3-4 เฟรมที่คั่นกันด้วยดีเลย์สั้น ๆ) โดยเฟรมในกลุ่มเดียวกันมักมีที่อยู่ 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 ได้ ยังต้องยอมรับ broadcast MAC FF:FF:FF:FF:FF:FF ด้วย

ตัวส่ง

  • เช่นเดียวกับตัวรับ ตัวส่งไม่ได้สร้าง FCS ในฮาร์ดแวร์ แต่ทำในซอฟต์แวร์
  • เพื่อให้ตัวส่งง่ายขึ้น จึงตัดสินใจรองรับเฉพาะเฟรมความยาวคงที่ วิธีนี้ทำให้ไม่ต้องใช้ digital comparator ที่ซับซ้อน และลอจิกการส่งเฟรมจะอาศัยเพียงบิตเดียวของตัวนับไบต์
  • เลือกความยาวเฟรมเป็น 1024 ไบต์ ซึ่งใกล้เคียงกับ MTU ทั่วไปที่ 1500 ไบต์
  • preamble ของเฟรมที่ 10BASE-T ต้องใช้ (ลำดับของ 0x55 ตามด้วย 0xD5) ก็รวมอยู่ใน 1024 ไบต์นี้ และต้องโหลดมาจากซอฟต์แวร์ด้วย

ตัวนับ

  • เช่นเดียวกับตัวรับ ใช้ตัวนับสองตัวในการนับบิต (U12) และไบต์ (U14)
  • ตัวนับตัวแรกป้อนด้วยสัญญาณนาฬิกา 20MHz จาก oscillator ในตัว
  • ไม่ได้ใช้ 20MHz โดยตรง แต่หารอย่างน้อย 2 ก่อน เพื่อไม่ให้ duty cycle ของ oscillator ส่งผลต่อสัญญาณเอาต์พุต

การไหลของข้อมูล

  • ใช้ 74HC157 multiplexer สามตัวชุดเดียวกับฝั่งตัวรับ (ไม่ได้แสดงไว้ที่นี่) เพื่อเลือกอินพุตที่อยู่ของ RAM (U22)
  • U23 ใช้สำหรับโหลดข้อมูลเข้า RAM
  • U24 ทำหน้าที่เป็นที่เก็บชั่วคราวสำหรับไบต์ที่กำลังส่งอยู่ แนวคิดนี้คล้ายกับ VGA pipeline ของผู้เขียน
  • ตัวนับไบต์ 74HC4040 เป็น ripple counter และต้องใช้เวลาสักพักกว่าจะนิ่ง โดย U24 จะให้เอาต์พุตที่คงที่ในระหว่างที่เอาต์พุตของ RAM ยังไม่ valid
  • จากนั้นข้อมูลนี้จะถูกป้อนไปยัง shift register U28 และเลื่อนออกทีละบิต

อินเทอร์เฟซกับ CPU

จากมุมมองของโปรแกรมเมอร์ อินเทอร์เฟซของอะแดปเตอร์อีเธอร์เน็ตนี้เป็นดังนี้:

  • frame buffer ทั้งสองถูกแมปไว้ที่ 0xF000
  • มีรีจิสเตอร์แบบอ่านอย่างเดียวสองตัว:
    • รีจิสเตอร์สถานะ 8 บิตที่ 0xFB00 มีแฟล็กสองตัว:
      • RX_FULL - ได้รับเฟรมแล้ว
      • TX_BUSY - กำลังส่งเฟรมอยู่
    • รีจิสเตอร์ความยาวข้อมูลที่รับมาแบบ 16 บิตที่ 0xFB02
  • การเขียนค่าใด ๆ ไปที่ 0xFB00 จะเป็นการรีสตาร์ตตัวรับ
  • การเขียนค่าใด ๆ ไปที่ 0xFB01 จะเริ่มการส่ง
  • ไม่มี interrupt เพราะ CPU ของผู้เขียนไม่รองรับ interrupt

การเขียนโปรแกรม

ต้องการการรองรับเครือข่าย แต่ไม่อยากลงมือเขียน TCP/IP stack เอง อีกทั้งคอมไพเลอร์ตัวแรกก็แย่มาก และการเขียนโปรแกรมด้วยแอสเซมบลีก็น่ารำคาญ จึงอยากได้ C compiler ที่ดีพอ เลยสร้าง C compiler ขึ้นมาเอง ตอนนี้มันพัฒนาไปมากพอที่จะคอมไพล์ uIP 1.0 (ไลบรารี TCP/IP ขนาดเล็ก) ได้ แม้ว่าความหนาแน่นของโค้ดบน CPU นี้จะต่ำมาก แต่ uIP ก็ยังเล็กพอที่จะใส่ลงใน RAM ได้ และยังเหลือพื้นที่สำหรับแอปพลิเคชันจริง

ประสิทธิภาพเครือข่ายนั้นต่ำมาก แต่เมื่อคำนึงว่าไม่ได้ใช้ทั้ง CPU เชิงพาณิชย์หรือชิปเฉพาะทาง ก็ยังน่าพอใจมาก:

  • ping แบบไปกลับเฉลี่ย 85ms
  • ความเร็วดาวน์โหลดจาก HTTP server 2.6kB/s (ให้บริการไฟล์สถิตจาก SD card)

ที่เก็บโครงการ

โมเดล ไฟล์ schematic และแบบ PCB อยู่บน GitHub

ความเห็นของ GN⁺

  • โครงการนี้แสดงให้เห็นถึงความเข้าใจด้านฮาร์ดแวร์อย่างลึกซึ้งและความหลงใหลของผู้พัฒนา ความพยายามที่จะสร้างทุกอย่างขึ้นมาเองนั้นน่าประทับใจอย่างมาก แต่ในแง่ความใช้งานจริงก็ยังชวนให้ตั้งคำถาม
  • ระบบคอมพิวเตอร์สมัยใหม่มีความซับซ้อนและเฉพาะทางสูงมาก การสร้างทุกอย่างตั้งแต่ศูนย์จึงไม่มีประสิทธิภาพอย่างยิ่ง โดยเฉพาะในส่วนที่มีการวางรากฐานและปรับแต่งมาอย่างดีแล้ว เช่น network protocol stack การใช้ implementation ที่มีอยู่จึงเป็นทางเลือกที่ฉลาดกว่า
  • ถึงอย่างนั้น โครงการแบบนี้ก็มีคุณค่าทางการศึกษาอย่างมาก เพราะทำให้ได้สัมผัสโดยตรงว่าฮาร์ดแวร์ระดับล่างและซอฟต์แวร์ทำงานร่วมกันอย่างไร และโปรโตคอลต่าง ๆ ถูกนำไปสร้างจริงอย่างไร
  • อีกทั้งในช่วงที่นักพัฒนายุคนี้มีความเข้าใจเรื่องฮาร์ดแวร์ลดลง โครงการแบบนี้ก็อาจเป็นตัวอย่างอันมีค่าที่ช่วยย้ำเตือนถึงรากฐานของระบบคอมพิวเตอร์
  • จุดที่น่าเสียดายคือประสิทธิภาพยังต่ำมาก หากต้องการให้นำไปใช้งานได้จริงมากขึ้นก็น่าจะต้องมีการปรับแต่งเพิ่มเติม แต่ดูเหมือนว่านั่นไม่ใช่เป้าหมายหลักของโครงการนี้

1 ความคิดเห็น

 
GN⁺ 2024-04-10
ความคิดเห็นจาก Hacker News
  • โปรเจ็กต์นี้สร้างการ์ดอีเธอร์เน็ตสำหรับคอมพิวเตอร์แบบกำหนดเองที่มีการทำ hardware MAC address filtering และลำดับการไล่เหตุผลระหว่างกระบวนการทำงานก็ให้ความรู้และยอดเยี่ยมมาก
  • การทำ implementation ขั้นต่ำของการ์ดอีเธอร์เน็ตสำหรับพีซีทั่วไปก็น่าจะคล้ายกัน แต่คงต้องให้ CPU ของพีซีคำนวณ checksum และเชื่อมต่อผ่าน USB หรืออย่างอื่น
  • น่าประทับใจที่สำหรับโปรเจ็กต์นี้ ผู้สร้างทำทั้ง C compiler, linker และ libc ขึ้นมาเอง
  • รู้สึกทึ่งกับความหลงใหลและความพยายามที่ใส่ลงไปในโปรเจ็กต์แบบนี้ และอยากลองทำโปรเจ็กต์ฮาร์ดแวร์/ซอฟต์แวร์แบบนี้หลังเกษียณ
  • ในอดีต การ์ดอีเธอร์เน็ต Etherlink 3c501 มีประสิทธิภาพไม่ดีนัก
  • ดูเหมือนว่านี่คือการสร้างการ์ดเครือข่ายด้วยวงจรลอจิกแบบดิสครีต (ไม่ใช่การ์ดเครือข่ายลอจิกแบบดิสครีต)
  • การ์ดเครือข่ายทุกใบไม่ได้สร้างจากชิ้นส่วนลอจิกแบบดิสครีตทั้งหมดใช่ไหม (คำถามแบบใสซื่อ)
  • ความเป็นโมดูลาร์ของชุดคอมพิวเตอร์นี้ยอดเยี่ยมมาก
  • น่าประทับใจที่อธิบายได้เรียบง่ายและมีประสิทธิภาพ และสมควรได้รับกำลังใจอย่างมาก