Este repositorio implementa una colección de componentes relacionados con Ethernet en Bluespec SystemVerilog (BSV) para el procesamiento de paquetes de alto rendimiento en FPGA. Específicamente, este repositorio proporciona módulos para generar y analizar paquetes UDP/IP/Ethernet. También se proporciona una unidad de procesamiento ARP con caché sin bloqueo que almacena información de direcciones para manejar la resolución de direcciones MAC automáticamente. Además de construir una pila UDP/IP/Ethernet estándar, blue-ethernet agrega soporte para RoCE (RDMA sobre Ethernet convergente): 1) integra la generación y verificación de ICRC (redundancia cíclica invariante) en el procesamiento de paquetes UDP/IP; 2) proporcionar módulos para manejar PFC (Control de flujo prioritario) para realizar la transmisión de red sin pérdidas. Y, finalmente, también se proporcionan módulos de conversión de interfaz para que el generador y analizador de paquetes interactúen con el subsistema Ethernet 100G (CMAC) de Xilinx.
Algunos directorios clave de este repositorio se muestran a continuación:
├── lib # external libraries/repos
│ ├── blue-crc # high-performance CRC hardware implementation
│ └── blue-wrapper # BSV wrappers for generating ready-to-use Verilog interface
├── scripts # scripts used to build project
├── src # design source files
│ └── includes # files containing some commonly-used BSV types and modules
├── syn # scripts for vivado synthesis and implementation
└── test # source files for verification
├── bluesim # testbenches based on bluesim
├── cocotb # python testbenches based on cocotb
└── vivado # co-simulation with cmac using vivado
Aquí hay una lista de algunos archivos fuente críticos:
./src
├── ArpCache.bsv # Cache implementation storing MAC addresses got from ARP
├── ArpProcessor.bsv # processing unit handling ARP requests and responses
├── includes
│ ├── CompletionBuf.bsv
│ ├── ContentAddressMem.bsv
│ ├── EthernetTypes.bsv # numeric and struct types about protocol definition
│ ├── PortConversion.bsv # interface conversion modules used to generate ready-to-use Verilog
│ ├── Ports.bsv # numeric and struct types about in/output ports of modules
│ ├── RFile.bsv
│ ├── StreamHandler.bsv # modules implemented for manipulating data stream
│ └── EthUtils.bsv # utility functions and modules
├── MacLayer.bsv # generator and parser for Ethernet packet
├── PfcUdpIpArpEthRxTx.bsv # generator and parser for UDP/IP/Ethernet packet with PFC
├── PriorityFlowControl.bsv # modules handling PFC
├── UdpIpArpEthRxTx.bsv # generator and parser for UDP/IP/Ethernet packet
├── UdpIpEthRx.bsv # parser for UDP/IP/Ethernet packet
├── UdpIpEthTx.bsv # generator for UDP/IP/Ethernet packet
├── UdpIpLayer.bsv # parser and generator for UDP/IP packet
├── UdpIpLayerForRdma.bsv # parser and generator for UDP/IP packet with support for RoCE
└── XilinxCmacRxTxWrapper.bsv # bridge modules between parser/generator and Xilinx CMAC
Esta sección proporciona descripciones detalladas de algunos componentes importantes implementados en blue-ethernet, incluida su funcionalidad, interfaz y arquitectura de hardware.
Lo que hacen los componentes de hardware relacionados con Ethernet es básicamente una serie de manipulaciones de flujo. El generador de paquetes es responsable de insertar el flujo de encabezado en el encabezado del flujo de carga útil para generar un flujo de paquetes completo. Por el contrario, lo que hace el analizador es extraer el flujo de encabezado y el flujo de carga útil del flujo de paquetes. En cuanto a agregar la suma de verificación de un paquete, el flujo de paquetes se pasa a la calculadora CRC y luego el valor CRC de salida se agrega al final del flujo de paquetes.
La entidad de hardware correspondiente al flujo que mencionamos aquí es en realidad un grupo de señales de datos custodiadas por el par de señales de control válidas y listas. La señal válida indica que el componente fuente quiere transferir datos. Y listo indica que el receptor está listo para recibir datos de la fuente. Una transferencia entre el origen y el sumidero solo se produce correctamente cuando tanto la validez como la preparación son altas. Si el tamaño de los datos a transmitir es mayor que el tamaño de una transferencia, los datos deben fragmentarse y transmitirse en una serie de transferencias.
La parte más complicada y propensa a errores del procesamiento de transmisiones es cómo manejar las señales de control listas para ser válidas de diferentes transmisiones. En BSV, la manipulación de las señales de control la implementa el compilador y es invisible en el nivel gramatical, lo que ayuda a los diseñadores a centrarse en la lógica del procesamiento del flujo.
Las señales de datos utilizadas para transferir flujos de paquetes entre diferentes componentes se encapsulan en la estructura DataStream , que incluye una señal de datos de 256 bits, una señal de habilitación de bytes de 32 bits y dos señales booleanas que representan si esta transferencia es la última o la primera de un flujo de paquetes.
typedef 256 DATA_BUS_WIDTH ;
typedef TDiv # ( DATA_BUS_WIDTH , 8 ) DATA_BUS_BYTE_WIDTH ;
typedef Bit # ( DATA_BUS_WIDTH ) Data ;
typedef Bit # ( DATA_BUS_BYTE_WIDTH ) ByteEn ;
typedef struct {
Data data ;
ByteEn byteEn ;
Bool isFirst ;
Bool isLast ;
} DataStream deriving ( Bits , Bounded , Eq , FShow ) ;
module mkAppendDataStreamHead # (
IsSwapEndian swapDataStream ,
IsSwapEndian swapAppendData ,
FifoOut # ( DataStream ) dataStreamIn ,
FifoOut # ( dType ) appendDataIn
)( FifoOut # ( DataStream )) ;
module mkAppendDataStreamTail # (
IsSwapEndian swapDataStream ,
IsSwapEndian swapAppendData ,
FifoOut # ( DataStream ) dataStreamIn ,
FifoOut # ( dType ) appendDataIn ,
FifoOut # ( Bit # ( streamLenWidth )) streamLengthIn
)( FifoOut # ( DataStream )) ;
interface ExtractDataStream # ( type dType ) ;
interface FifoOut # ( dType ) extractDataOut ;
interface FifoOut # ( DataStream ) dataStreamOut ;
endinterface
module mkExtractDataStreamHead # (
FifoOut # ( DataStream ) dataStreamIn
)( ExtractDataStream # ( dType )) ;
Los módulos del paquete UdpIpLayer se implementan para generar y analizar paquetes UDP/IP.
El generador de paquetes toma UdpIpMetaData que contiene información de encabezado UDP/IP y el flujo de carga útil y genera un flujo de paquetes UDP/IP completo. El analizador de paquetes funciona de manera opuesta: extrae UdpIpMetaData y el flujo de carga útil del flujo de paquetes UDP/IP.
typedef struct {
UdpLength dataLen ; # The Length of payload data
IpAddr ipAddr ; # Desitnation IP address
IpDscp ipDscp ; # DSCP field used for PFC
IpEcn ipEcn ; # ECN field
UdpPort dstPort ; # Destination port number
UdpPort srcPort ; # Source port number
} UdpIpMetaData ;
Las señales encapsuladas en la estructura UdpIpMetaData no cubren todos los campos definidos en el encabezado UDP/IP. Algunos campos del encabezado están fijos para un dispositivo de red específico, que están encapsulados en la estructura UdpConfig y deben configurarse antes de transmitir o recibir cualquier paquete. Y algunos otros campos son constantes y están codificados en los componentes de hardware.
typedef struct {
EthMacAddr macAddr ; # Source MAC address
IpAddr ipAddr ; # Source IP address
IpNetMask netMask ; # IP netmask
IpGateWay gateWay ; # IP gateway
} UdpConfig ;
module mkUdpIpStream # (
UdpConfig udpConfig ,
FifoOut # ( DataStream ) dataStreamIn ,
FifoOut # ( UdpIpMetaData ) udpIpMetaDataIn ,
function UdpIpHeader genHeader ( UdpIpMetaData meta , UdpConfig udpConfig , IpID ipId )
)( FifoOut # ( DataStream )) ;
interface UdpIpMetaDataAndDataStream ;
interface FifoOut # ( UdpIpMetaData ) udpIpMetaDataOut ;
interface FifoOut # ( DataStream ) dataStreamOut ;
endinterface
module mkUdpIpMetaDataAndDataStream # (
UdpConfig udpConfig ,
FifoOut # ( DataStream ) udpIpStreamIn ,
function UdpIpMetaData extractMetaData ( UdpIpHeader hdr )
)( UdpIpMetaDataAndDataStream ) ;
Los módulos del paquete UdpIpLayerForRdma se implementan en función de UdpIpLayer con soporte para RoCE (RDMA sobre Ethernet convergente). La funcionalidad adicional agregada para admitir RoCE es la generación y verificación de ICRC (CRC invariante) requerida para los paquetes RoCE. El formato del paquete RoCE se define a continuación:
Los módulos del paquete MacLayer se implementan para generar y analizar paquetes Ethernet. El generador inserta un encabezado Ethernet en el encabezado del flujo de paquetes UDP/IP para generar un flujo de paquetes Ethernet. El analizador extrae el encabezado Ethernet y el flujo de paquetes UDP/IP del flujo de paquetes Ethernet.
La información del encabezado utilizada para generar el paquete Ethernet se define en la estructura MacMetaData .
typedef struct {
EthMacAddr macAddr ; # Destination MAC address
EthType ethType ; # Type of Ethernet frame
} MacMetaData deriving ( Bits , Eq , FShow ) ;
Cabe señalar que el paquete Ethernet manejado en MacLayer solo cubre los campos delineados en el rectángulo rojo en la siguiente figura. Otros campos quedan para que Xilinx CMAC IP los procese.
module mkMacStream # (
FifoOut # ( DataStream ) udpIpStreamIn ,
FifoOut # ( MacMetaData ) macMetaDataIn ,
UdpConfig udpConfig
)( FifoOut # ( DataStream )) ;
interface MacMetaDataAndUdpIpStream ;
interface FifoOut # ( MacMetaData ) macMetaDataOut ;
interface FifoOut # ( DataStream ) udpIpStreamOut ;
endinterface
module mkMacMetaDataAndUdpIpStream # (
FifoOut # ( DataStream ) macStreamIn ,
UdpConfig udpConfig
)( MacMetaDataAndUdpIpStream ) ;
El Protocolo de resolución de direcciones (ARP) se utiliza para descubrir la dirección MAC asociada con una dirección IP determinada. En blue-ethernet, se implementa el módulo mkArpProcessor para el procesamiento ARP, que integra el generador de paquetes ARP, el analizador y el módulo mkArpCache que almacena direcciones MAC.
Para el caché utilizado en el procesamiento ARP, la dirección IP de 32 bits corresponde a la dirección del caché y la dirección MAC de 48 bits corresponde a los datos del caché. La disposición predeterminada de la matriz de memoria para la caché ARP se muestra a continuación, que es una estructura asociativa de 4 vías, cada vía contiene 64 líneas y cada línea incluye 1 bit válido, etiqueta de 26 bits y datos de 48 bits. El tamaño total de esta configuración de matriz predeterminada es de aproximadamente 1,2 KB. Se admite cambiar el tamaño de la matriz de memoria configurando el número de líneas y formas. Basado en esta matriz de memoria, el caché está diseñado para no bloquear, admitir solicitudes pendientes (múltiples solicitudes en vuelo) y utilizar un algoritmo pseudo-LRU para el reemplazo de la línea de caché.
La definición de la interfaz y el diagrama de estructura simplificado del módulo mkArpCache se muestran a continuación. ArpCache tiene dos subinterfaces: cacheServer maneja las interacciones con los componentes del servicio de resolución de direcciones MAC; y arpClient maneja las interacciones con mkArpProcessor para iniciar la solicitud ARP y obtener la dirección MAC de la respuesta ARP. El flujo de trabajo básico del módulo mkArpCache es el siguiente:
Cuando el caché recibe una solicitud de lectura, primero busca en la matriz de memoria para obtener todas las etiquetas y datos correspondientes a la dirección IP dada. Luego verifica las etiquetas para ver si los datos que necesitamos están almacenados en el caché. Si el caché llega, los datos recuperados se envían a hitBuf . O la dirección IP se envía a arpReqBuf para iniciar una solicitud ARP. Y cuando regresa la respuesta ARP, los datos y la información de dirección que contiene se escriben en cacheWrBuf y missHitBuf para actualizar la matriz de memoria y devolver la respuesta de lectura de caché.
interface ArpCache ;
interface Server # ( CacheAddr , CacheData ) cacheServer ;
interface Client # ( CacheAddr , ArpResp ) arpClient ;
endinterface
La parte más difícil de la implementación de la caché es admitir la característica sobresaliente, es decir, admitir múltiples solicitudes de lectura en vuelo. El problema inducido por el estado pendiente es que el tiempo de respuesta es diferente para cada solicitud ARP en vuelo, lo que significa que una solicitud tardía puede recibir su respuesta primero. Por lo tanto, se necesita un mecanismo de reordenamiento para garantizar la correspondencia entre la dirección de solicitud y los datos de respuesta cuando ocurre una pérdida de caché. Para lograr una respuesta en orden, el búfer de finalización respCBuf y la memoria de contenido direccionable missReqTab están integrados en el flujo de datos. El búfer de finalización funciona como FIFO con soporte adicional para la funcionalidad de reserva. Antes de la operación de puesta en cola real, primero podemos reservar un pedido en el búfer de finalización. Y la operación de puesta en cola sigue el orden reservado sin importar el orden secuencial real de las operaciones de puesta en cola. Para cada solicitud de lectura, se invierte un orden de retirada de la cola en respCBuf una vez que se recibe. Y debido a que la solicitud ARP no puede transportar la información del pedido, se implementa missReqTab para almacenarla.
El módulo puede comportarse como cliente y servidor ARP. Como servidor, el procesador necesita generar una solicitud ARP si se desconoce la dirección MAC de la IP de destino y luego espera la respuesta ARP del dispositivo de destino. Como cliente, el procesador ARP recibe solicitudes ARP de otros dispositivos y envía una respuesta ARP con su propia dirección MAC.
interface ArpProcessor ;
interface FifoOut # ( DataStream ) arpStreamOut ;
interface FifoOut # ( MacMetaData ) macMetaDataOut ;
interface Put # ( UdpConfig ) udpConfig ;
endinterface
module mkArpProcessor # (
FifoOut # ( DataStream ) arpStreamIn ,
FifoOut # ( UdpIpMetaData ) udpIpMetaDataIn
)( ArpProcessor ) ;
Los módulos del paquete UdpIpEthRx se implementan para recibir y analizar paquetes UDP/IP/Ethernet.
interface UdpIpEthRx ;
interface Put # ( UdpConfig ) udpConfig ;
interface Put # ( AxiStream512 ) axiStreamIn ;
interface FifoOut # ( MacMetaData ) macMetaDataOut ;
interface FifoOut # ( UdpIpMetaData ) udpIpMetaDataOut ;
interface FifoOut # ( DataStream ) dataStreamOut ;
endinterface
module mkGenericUdpIpEthRx # ( Bool isSupportRdma )( UdpIpEthRx )
Los módulos del paquete UdpIpEthTx se implementan para generar y transmitir paquetes UDP/IP/Ethernet.
interface UdpIpEthTx ;
interface Put # ( UdpConfig ) udpConfig ;
interface Put # ( UdpIpMetaData ) udpIpMetaDataIn ;
interface Put # ( MacMetaData ) macMetaDataIn ;
interface Put # ( DataStream ) dataStreamIn ;
interface AxiStream512FifoOut axiStreamOut ;
endinterface
module mkGenericUdpIpEthTx # ( Bool isSupportRdma )( UdpIpEthTx ) ;
Los módulos proporcionados en el paquete UdpIpArpEthRxTx están diseñados para recibir y transmitir paquetes UDP/IP/Ethernet y manejar solicitudes y respuestas ARP al mismo tiempo.
El módulo se puede dividir en dos rutas opuestas de flujos, incluida la ruta de transmisión y la ruta de recepción:
Para la ruta de transmisión, toma dataStreamInTx que transporta el flujo de carga útil y udpIpMetaDataIn que transporta el flujo de información del encabezado y genera axiStreamOutTx que transporta el flujo de paquetes UDP/IP/Ethernet. No es necesario proporcionar MacMetaData que contenga información del encabezado Ethernet como módulo mkUdpIpEthTx , porque mkArpProcessor es responsable de manejar la resolución de direcciones MAC y generar información del encabezado Ethernet.
Para la ruta de recepción, funciona de manera opuesta extrayendo dataStreamOutRx que transporta el flujo de carga útil y udpIpMetaDataOutRx que transporta el flujo de información del encabezado de axiStreamInRx que transporta el flujo de paquetes UDP/IP/Ethernet.
El generador y el analizador de paquetes Ethernet son compartidos tanto por el paquete UDP/IP como por el paquete ARP, por lo que se necesitan Mux y Demux adicionales en la ruta de transmisión y recepción para el arbitraje y distribución del flujo. El parámetro del módulo isSupportRdma especifica si admite o no el procesamiento de paquetes RoCE. Si el soporte para RDMA está deshabilitado, solo necesitamos mkUdpIpStream y mkUdpIpMetaAndDataStream en la ruta de transmisión y recepción respectivamente.
interface UdpIpArpEthRxTx ;
interface Put # ( UdpConfig ) udpConfig ;
// Tx
interface Put # ( UdpIpMetaData ) udpIpMetaDataInTx ;
interface Put # ( DataStream ) dataStreamInTx ;
interface AxiStream512FifoOut axiStreamOutTx ;
// Rx
interface Put # ( AxiStream512 ) axiStreamInRx ;
interface FifoOut # ( UdpIpMetaData ) udpIpMetaDataOutRx ;
interface FifoOut # ( DataStream ) dataStreamOutRx ;
endinterface
module mkGenericUdpIpArpEthRxTx # ( Bool isSupportRdma )( UdpIpArpEthRxTx ) ;
El módulo envuelve mkGenericUdpIpArpEthRxTx utilizando los módulos proporcionados en blue-wrapper para que genere una interfaz Verilog lista para usar.
El módulo integra el módulo mkGenericUdpIpArpEthRxTx y el módulo mkXilinxCmacTxWrapper . Está diseñado para interactuar con Xilinx CMAC IP para transmitir y recibir paquetes UDP/IP/Ethernet hacia y desde un medio físico.
Los módulos del paquete PriorityFlowControl se implementan para implementar un mecanismo de control de flujo prioritario para garantizar una transmisión de red sin pérdidas.
interface PriorityFlowControlTx ;
interface Get # ( UdpIpMetaData ) udpIpMetaDataOut ;
interface Get # ( DataStream ) dataStreamOut ;
endinterface
module mkPriorityFlowControlTx # (
FifoOut # ( FlowControlReqVec ) flowControlReqVecIn ,
Vector # ( VIRTUAL_CHANNEL_NUM , DataStreamFifoOut ) dataStreamInVec ,
Vector # ( VIRTUAL_CHANNEL_NUM , UdpIpMetaDataFifoOut ) udpIpMetaDataInVec
)( PriorityFlowControlTx ) ;
interface PriorityFlowControlRx # (
numeric type bufPacketNum ,
numeric type maxPacketFrameNum ,
numeric type pfcThreshold
) ;
interface FifoOut # ( FlowControlReqVec ) flowControlReqVecOut ;
interface Vector # ( VIRTUAL_CHANNEL_NUM , Get # ( DataStream )) dataStreamOutVec ;
interface Vector # ( VIRTUAL_CHANNEL_NUM , Get # ( UdpIpMetaData )) udpIpMetaDataOutVec ;
endinterface
module mkPriorityFlowControlRx # (
DataStreamFifoOut dataStreamIn ,
UdpIpMetaDataFifoOut udpIpMetaDataIn
)( PriorityFlowControlRx # ( bufPacketNum , maxPacketFrameNum , pfcThreshold )) ;
mkGenericPfcUdpIpArpEthRxTx integra mkPriorityFlowControlRx/Tx y mkGenericUdpIpArpEthRxTx para proporcionar la funcionalidad de generar y analizar paquetes UDP/IP/Ethernet al tiempo que admite el control de flujo prioritario. Para la transmisión de paquetes, se necesitan ocho canales de flujo de carga útil e información de encabezado UDP/IP, y genera un flujo de paquetes UDP/IP/Ethernet. Para la recepción de paquetes, toma un flujo de paquetes UDP/IP/Ethernet y enruta el encabezado UDP/IP extraído y el flujo de carga útil a uno de los ocho canales de salida.
mkPfcUdpIpArpEthCmacRxTx integra el módulo mkGenericPfcUdpIpArpEthRxTx y el módulo mkXilinxCmacTxWrapper . Está diseñado para interactuar con Xilinx CMAC IP para transmitir y recibir paquetes UDP/IP/Ethernet hacia y desde un medio físico.
La síntesis e implementación del módulo principal mkGenericUdpIpArpEthRxTx se realizan en base al dispositivo Xilinx xcvu9p usando Vivado. Y los resultados muestran que el circuito puede alcanzar la frecuencia de trabajo de 500 MHz y proporcionar un rendimiento máximo de 128 Gbps. El uso de recursos de hardware se enumera a continuación:
CLB Logic
+----------------------------+-------+-------+------------+-----------+-------+
| Site Type | Used | Fixed | Prohibited | Available | Util % |
+----------------------------+-------+-------+------------+-----------+-------+
| CLB LUTs | 63886 | 0 | 0 | 1182240 | 5.40 |
| LUT as Logic | 41242 | 0 | 0 | 1182240 | 3.49 |
| LUT as Memory | 22644 | 0 | 0 | 591840 | 3.83 |
| LUT as Distributed RAM | 22644 | 0 | | | |
| LUT as Shift Register | 0 | 0 | | | |
| CLB Registers | 44099 | 0 | 0 | 2364480 | 1.87 |
| Register as Flip Flop | 44099 | 0 | 0 | 2364480 | 1.87 |
| Register as Latch | 0 | 0 | 0 | 2364480 | 0.00 |
| CARRY8 | 73 | 0 | 0 | 147780 | 0.05 |
| F7 Muxes | 194 | 0 | 0 | 591120 | 0.03 |
| F8 Muxes | 28 | 0 | 0 | 295560 | < 0.01 |
| F9 Muxes | 0 | 0 | 0 | 147780 | 0.00 |
+----------------------------+-------+-------+------------+-----------+-------+
BLOCKRAM
+-------------------+------+-------+------------+-----------+-------+
| Site Type | Used | Fixed | Prohibited | Available | Util % |
+-------------------+------+-------+------------+-----------+-------+
| Block RAM Tile | 4.5 | 0 | 0 | 2160 | 0.21 |
| RAMB36 / FIFO * | 4 | 0 | 0 | 2160 | 0.19 |
| RAMB36E2 only | 4 | | | | |
| RAMB18 | 1 | 0 | 0 | 4320 | 0.02 |
| RAMB18E2 only | 1 | | | | |
| URAM | 0 | 0 | 0 | 960 | 0.00 |
+-------------------+------+-------+------------+-----------+-------+
Esta sección presenta cómo comenzar con este proyecto. Antes de realizar cualquier otro paso, primero debe configurar el entorno de desarrollo consultando el script setup.sh. Aquí hay una lista de dependencias:
Después de configurar el entorno, clone este repositorio en un directorio específico. Aquí nos referimos a este directorio como BLUE_ETH:
git clone --recursive https://github.com/wengwz/blue-ethernet.git $( BLUE_ETH )
Hay tres niveles diferentes de bancos de pruebas proporcionados en blue-ethernet:
# Specify TARGET to the name of target component
cd $( BLUE_ETH ) /test/bluesim
make TARGET=ArpCache
# Run tests of UdpIpEthRx/Tx
# Enable/Disable support for RDMA by setting SUPPORT_RDAM to True/False
cd $( BLUE_ETH ) /test/cocotb
make cocotb TARGET=UdpIpEthTx SUPPORT_RDMA=TRUE
# Run simulation on virtual network
# Change NET_IFC in run_docker_net_test.sh to the name of your network card
cd $( BLUE_ETH ) /test/cocotb
docker build -f ./build_docker/Dockerfile -t ethernet-test ./build_docker
./run_docker_net_test.sh
# Available TARGET includes UdpIpArpEthCmacRxTx/PfcUdpIpArpEthCmacRxTx
# Enable/Disable support for RDMA by setting SUPPORT_RDAM to True/False
cd $( BLUE_ETH ) /test/vivado
make sim TARGET=UdpIpArpEthCmacRxTx SUPPORT_RDMA=False
Los scripts utilizados para ejecutar la síntesis y la implementación de diseños se proporcionan en el directorio $(BLUE_ETH)/syn.
# TARGET specifies the top module to be synthsized or implemented
# SUPPORT_RDMA specifies whether modules supports RoCE packet processing
# ONLYSYNTH decides whether or not run implemetation after synthesis
cd $( BLUE_ETH ) /syn
make vivado TARGET=UdpIpArpEthRxTx SUPPORT_RDMA=False ONLYSYNTH=0
# TARGET specifies the name of top module to be generated
# Specify SUPPORT_RDMA if needed
cd $( BLUE_ETH ) /test/cocotb
make verilog TARGET=UdpIpEthTx SUPPORT_RDMA=TRUE
bsc -p +: $( BLUE_ETH ) /src: $( BLUE_ETH ) /src/includes ...
La implementación de blue-ethernet implica el uso de las siguientes bibliotecas externas: