Cómo hice una tarjeta de red de lógica discreta
Este artículo es parte de una serie sobre el proceso de construir un sistema de cómputo completo usando circuitos de lógica discreta. Hasta ahora, se ha construido una computadora capaz de ejecutar aplicaciones de red como un servidor HTTP o juegos LAN.
Resumen
- El año pasado se fabricó un adaptador de capa física que convierte señales Ethernet 10BASE-T a SPI y viceversa. En ese momento se probó su funcionamiento usando un microcontrolador STM32, y ahora se está implementando un módulo de capa MAC para conectarlo a una computadora hecha a mano.
- Ambos adaptadores son full-duplex y tienen secciones independientes de transmisión y recepción.
Receptor
Resumen del funcionamiento del receptor:
- Los datos seriales SPI se convierten en datos paralelos por bytes, y se extrae el reloj de byte.
- Los primeros 6 bytes se comparan con una referencia de dirección MAC de destino, y se descartan las tramas que no coinciden.
- Los bytes se escriben en un búfer de RAM estática.
- Cuando termina la trama, el receptor se desactiva, y se rechazan tramas adicionales hasta que el usuario reinicie el receptor. El contador de bytes se detiene y su valor se pone a disposición del usuario.
Captura de datos
- Es necesario convertir los datos seriales SPI en un flujo de bytes.
- Los datos seriales se desplazan al registro de corrimiento (
U32).U30yU31cuentan los bits y los bytes, respectivamente. - La señal de escritura en RAM estática
recv_buf_wese forma usando el flip-flop DU29B. Esta señal baja brevemente después de cada uno de los 8 bits de los datos de entrada. - Los bytes recibidos se escriben en un búfer de RAM estática 6116 (
U20) de 2 kB. U13,U16yU18forman un multiplexor de direcciones que selecciona ya sea el contador de bytes o el bus de direcciones del sistema como entrada de direcciones del SRAM (U20).- El búfer triestado
U21envía los bytes recibidos a la RAM.
Filtrado de direcciones MAC
- Al analizar tráfico Ethernet, se observó que las tramas suelen llegar en grupos pequeños (3-4 tramas separadas por una latencia corta). Las tramas dentro de un grupo normalmente tienen diferentes direcciones MAC de destino.
- Esto llevó a pensar que la computadora no podría filtrar las tramas recibidas por MAC y reiniciar el receptor lo suficientemente rápido como para capturar las tramas dirigidas a sí misma. Se necesitaba filtrado de direcciones MAC por hardware.
- Guardar una dirección MAC personalizada en algún lugar y luego compararla con los primeros 6 bytes recibidos era demasiado complejo. También se podía hacer como repetición de un solo byte (por ejemplo, FE:FE:FE:FE:FE:FE), pero sería aburrido.
- Para darle una pequeña variación a la MAC, se hizo como una función del índice del byte:
- El bit 0 se fija en 0
- El bit 1 se fija en 1
- Los bits 2-4 son la inversión del índice del byte
- Los bits 5-7 se fijan en 1
- Con esta regla, la dirección MAC resulta ser
FE:FA:F6:F2:EE:EA. Además, para que funcione con ARP, también debe aceptarse la MAC de broadcastFF:FF:FF:FF:FF:FF.
Transmisor
- Igual que en el receptor, el transmisor no implementa la generación de FCS y eso se hace en software.
- Para simplificar aún más el transmisor, se decidió soportar solo tramas de longitud fija. Esto evita la necesidad de un comparador digital complejo, y la lógica de transmisión de tramas depende solo de un único bit del contador de bytes.
- La longitud de la trama se eligió en 1024 bytes, lo cual está cerca del MTU típico de 1500 bytes.
- El preámbulo de trama requerido por 10BASE-T (una secuencia de
0x55seguida de0xD5) también está incluido dentro de esos 1024 bytes y debe cargarse desde software.
Contadores
- Igual que en el receptor, se usan dos contadores para contar bits (
U12) y bytes (U14). - El primer contador recibe el reloj de 20 MHz de un oscilador integrado.
- Los 20 MHz no se usan directamente, sino que primero se dividen al menos entre 2. Así, el ciclo de trabajo del oscilador no afecta la señal de salida.
Flujo de datos
- Para seleccionar la entrada de direcciones de la RAM (
U22), se usan los mismos tres multiplexores 74HC157 que en el receptor (no mostrados aquí). U23se usa para cargar datos en la RAM.U24sirve como almacenamiento intermedio para el byte que se está transmitiendo en ese momento. La idea aquí es similar a la de la tubería VGA del autor.- El contador de bytes 74HC4040 es un contador ripple y tarda tiempo en estabilizarse, por lo que
U24proporciona una salida estable mientras la salida de la RAM todavía no es válida. - Estos datos se alimentan al registro de corrimiento
U28y se desplazan bit a bit.
Interfaz de CPU
Desde el punto de vista del programador, la interfaz del adaptador Ethernet es la siguiente:
- Ambos búferes de tramas están mapeados en
0xF000. - Hay dos registros de solo lectura:
- El registro de estado de 8 bits en
0xFB00tiene dos banderas:RX_FULL- se recibió una tramaTX_BUSY- una trama está en transmisión
- El registro de 16 bits de longitud de datos recibidos en
0xFB02
- El registro de estado de 8 bits en
- Escribir cualquier valor en
0xFB00reinicia el receptor. - Escribir cualquier valor en
0xFB01inicia la transmisión. - No hay interrupciones porque esta CPU no las soporta.
Programación
Se quería tener soporte de red, pero no se quería implementar una pila TCP/IP completa desde cero. Además, como el primer compilador era terrible y programar en ensamblador era una molestia, se quería un compilador de C decente. Así que se hizo un compilador de C. Ya está lo suficientemente maduro como para compilar uIP 1.0 (una biblioteca TCP/IP pequeña). A pesar de que la densidad de código de esta CPU es muy baja, uIP es lo bastante pequeño para caber en la RAM y todavía dejar espacio para aplicaciones reales.
El rendimiento de red es muy bajo, pero considerando que no se usó ninguna CPU comercial ni chips especializados, el resultado sigue siendo muy satisfactorio:
- Tiempo promedio de ida y vuelta de ping: 85 ms
- Velocidad de descarga del servidor HTTP: 2.6 kB/s (sirviendo archivos estáticos desde una tarjeta SD)
Repositorio del proyecto
Los modelos, archivos de esquemáticos y diseños de PCB están en GitHub.
Opinión de GN⁺
- Este proyecto muestra la profunda comprensión y pasión del desarrollador por el hardware. El esfuerzo por implementar todo manualmente es muy impresionante, aunque desde el punto de vista práctico deja algunas dudas.
- Los sistemas de cómputo modernos son muy complejos y especializados, así que implementar todo desde cero es muy ineficiente. Especialmente en áreas bien establecidas y optimizadas, como la pila de protocolos de red, es más sensato aprovechar implementaciones existentes.
- Aun así, este tipo de proyectos tiene un valor educativo muy alto, porque permite experimentar directamente cómo interactúan el hardware y el software de bajo nivel, y cómo se implementan los protocolos.
- Además, en un momento en que entre muchos desarrolladores está disminuyendo la comprensión del hardware, este tipo de proyecto puede ser un ejemplo valioso que recuerde los fundamentos de los sistemas de cómputo.
- Lo desafortunado es que el rendimiento es muy bajo. Para aumentar su utilidad práctica, parecería necesaria una implementación más optimizada. Pero ese no parece ser el objetivo principal del proyecto.
1 comentarios
Comentarios de Hacker News
libc, etc.