Este repositório implementa uma coleção de componentes relacionados à Ethernet no Bluespec SystemVerilog (BSV) para processamento de pacotes de alto desempenho em FPGA. Especificamente, este repositório fornece módulos para gerar e analisar pacotes UDP/IP/Ethernet. Uma unidade de processamento ARP com cache sem bloqueio que armazena informações de endereço também é fornecida para lidar automaticamente com a resolução de endereços MAC. Além de construir uma pilha UDP/IP/Ethernet padrão, a blue-ethernet adiciona suporte para RoCE (RDMA over Converged Ethernet): 1) integra a geração e verificação de ICRC (Redundância Cíclica Invariante) no processamento de pacotes UDP/IP; 2) fornecer módulos para lidar com PFC (Controle de Fluxo Prioritário) para realizar a transmissão de rede sem perdas. E, finalmente, módulos de conversão de interface também são fornecidos para o gerador e analisador de pacotes interagirem com o Xilinx 100G Ethernet Subsystem (CMAC).
Alguns diretórios principais deste repositório são mostrados abaixo:
├── 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
Aqui está uma lista de alguns arquivos de origem 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 seção fornece descrições detalhadas de alguns componentes importantes implementados em blue-ethernet, incluindo sua funcionalidade, interface e arquitetura de hardware.
O que os componentes de hardware relacionados à Ethernet fazem é basicamente uma série de manipulações de fluxo. O gerador de pacotes é responsável por inserir o fluxo de cabeçalho no fluxo de carga útil para gerar o fluxo de pacotes completo. Pelo contrário, o que o analisador faz é extrair o fluxo de cabeçalho e o fluxo de carga útil do fluxo de pacotes. Quanto à adição da soma de verificação de um pacote, o fluxo de pacotes é passado para a calculadora CRC e, em seguida, o valor CRC de saída é anexado à parte final do fluxo de pacotes.
A entidade de hardware correspondente ao fluxo mencionado aqui é na verdade um grupo de sinais de dados protegidos pelo par de sinais de controle válidos e prontos. O sinal válido indica que o componente de origem deseja transferir dados. E o ready indica que o sink está pronto para receber dados da fonte. Uma transferência entre a origem e o coletor só acontece com sucesso quando válido e pronto são altos. Se o tamanho dos dados a serem transmitidos for maior que o tamanho de uma transferência, os dados precisarão ser fragmentados e transmitidos em uma série de transferências.
A parte mais complicada e propensa a erros do processamento de fluxo é como lidar com os sinais de controle válidos e prontos de diferentes fluxos. No BSV, a manipulação dos sinais de controle é implementada pelo compilador e invisível no nível gramatical, o que ajuda os projetistas a se concentrarem na lógica do processamento do fluxo.
Os sinais de dados usados para transferir fluxo de pacotes entre diferentes componentes são encapsulados na estrutura DataStream , que inclui sinal de dados de 256 bits, sinal de habilitação de byte de 32 bits, dois sinais booleanos representam se esta transferência é a última ou a primeira de um fluxo de pacotes.
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 )) ;
Módulos no pacote UdpIpLayer são implementados para gerar e analisar pacotes UDP/IP.
O gerador de pacotes recebe UdpIpMetaData que contém informações do cabeçalho UDP/IP e o fluxo de carga útil e gera um fluxo de pacotes UDP/IP completo. O analisador de pacotes funciona de maneira oposta, extraindo UdpIpMetaData e fluxo de carga útil do fluxo de pacotes 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 ;
Os sinais encapsulados na estrutura UdpIpMetaData não cobrem todos os campos definidos no cabeçalho UDP/IP. Alguns campos do cabeçalho são fixos para um dispositivo de rede específico, que são encapsulados na estrutura UdpConfig e precisam ser configurados antes de transmitir ou receber qualquer pacote. E alguns outros campos são constantes e codificados em 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 ) ;
Os módulos no pacote UdpIpLayerForRdma são implementados com base em UdpIpLayer com suporte para RoCE (RDMA over Converged Ethernet). A funcionalidade adicional adicionada para suportar RoCE é a geração e verificação de ICRC (CRC Invariável) necessária para pacotes RoCE. O formato do pacote RoCE é definido conforme abaixo:
Módulos no pacote MacLayer são implementados para gerar e analisar pacotes Ethernet. O gerador insere o cabeçalho Ethernet no cabeçalho do fluxo de pacotes UDP/IP para gerar o fluxo de pacotes Ethernet. O analisador extrai o cabeçalho Ethernet e o fluxo de pacotes UDP/IP do fluxo de pacotes Ethernet.
As informações do cabeçalho usadas para gerar pacotes Ethernet são definidas na estrutura MacMetaData .
typedef struct {
EthMacAddr macAddr ; # Destination MAC address
EthType ethType ; # Type of Ethernet frame
} MacMetaData deriving ( Bits , Eq , FShow ) ;
Deve ser observado que o pacote Ethernet tratado no MacLayer cobre apenas os campos destacados no retângulo vermelho na figura abaixo. Outros campos são deixados para serem processados pelo Xilinx CMAC IP.
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 ) ;
O Address Resolution Protocol (ARP) é usado para descobrir o endereço MAC associado a um determinado endereço IP. No blue-ethernet, o módulo mkArpProcessor é implementado para processamento ARP, que integra gerador de pacotes ARP, analisador e módulo mkArpCache que armazena endereços MAC.
Para o cache usado no processamento ARP, o endereço IP de 32 bits corresponde ao endereço do cache e o endereço MAC de 48 bits corresponde aos dados do cache. O arranjo padrão da matriz de memória para cache ARP é mostrado abaixo, que é uma estrutura associativa de conjunto de 4 vias, cada via contém 64 linhas e cada linha inclui dados válidos de 1 bit, tag de 26 bits e dados de 48 bits. O tamanho total desta configuração de matriz padrão é de cerca de 1,2 KB. É possível alterar o tamanho do array de memória definindo o número de linhas e caminhos. Com base nesta matriz de memória, o cache é projetado para não bloquear, suportar solicitações pendentes (múltiplas solicitações em voo) e usar o algoritmo pseudo-LRU para substituição de linha de cache.
A definição da interface e o diagrama de estrutura simplificado do módulo mkArpCache são mostrados abaixo. O ArpCache possui duas subinterfaces: cacheServer lida com interações com componentes que atendem a resolução de endereços MAC; e arpClient lida com interações com mkArpProcessor para iniciar a solicitação ARP e obter o endereço MAC da resposta ARP. O fluxo de trabalho básico do módulo mkArpCache é o seguinte:
Quando o cache recebe uma solicitação de leitura, ele primeiro pesquisa na matriz de memória para obter todas as tags e dados correspondentes ao endereço IP fornecido. Em seguida, ele verifica as tags para ver se os dados necessários estão armazenados no cache. Se o cache for atingido, os dados buscados serão enviados para hitBuf . Ou o endereço IP é enviado ao arpReqBuf para iniciar uma solicitação ARP. E quando a resposta ARP retorna, os dados e as informações de endereço que ela carrega são gravados em cacheWrBuf e missHitBuf para atualizar a matriz de memória e retornar a resposta de leitura do cache.
interface ArpCache ;
interface Server # ( CacheAddr , CacheData ) cacheServer ;
interface Client # ( CacheAddr , ArpResp ) arpClient ;
endinterface
A parte mais difícil da implementação do cache é suportar o recurso pendente, que suporta múltiplas solicitações de leitura em andamento. O problema induzido pela pendente é que o tempo de resposta é diferente para cada solicitação ARP em andamento, o que significa que uma solicitação atrasada pode receber sua resposta primeiro. Portanto, o mecanismo de reordenação é necessário para garantir a correspondência entre o endereço da solicitação e os dados de resposta quando ocorre uma falha no cache. Para obter uma resposta em ordem, o buffer de conclusão respCBuf e a memória endereçável de conteúdo missReqTab são integrados no fluxo de dados. O buffer de conclusão funciona como FIFO com suporte adicional para a funcionalidade de reserva. Antes da operação real de enfileiramento, podemos primeiro reservar um pedido no buffer de conclusão. E a operação de desenfileiramento segue a ordem reservada, independentemente da ordem sequencial real das operações de enfileiramento. Para cada solicitação de leitura, uma ordem de desenfileiramento é revertida em respCBuf assim que recebida. E como a solicitação ARP não pode transportar as informações do pedido, missReqTab é implementado para armazená-las.
O módulo pode se comportar como cliente e servidor ARP. Como servidor, o processador precisa gerar uma solicitação ARP se o endereço MAC do IP alvo for desconhecido e então aguardar a resposta ARP do dispositivo alvo. Como cliente, o processador ARP recebe solicitações ARP de outros dispositivos e envia de volta uma resposta ARP carregando seu próprio endereço 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 ) ;
Módulos no pacote UdpIpEthRx são implementados para receber e analisar pacotes 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 )
Os módulos do pacote UdpIpEthTx são implementados para gerar e transmitir pacotes 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 ) ;
Os módulos fornecidos no pacote UdpIpArpEthRxTx são projetados para receber e transmitir pacotes UDP/IP/Ethernet e lidar com solicitações e respostas ARP ao mesmo tempo.
O módulo pode ser dividido em dois caminhos opostos de fluxos, incluindo caminho de transmissão e caminho de recepção:
Para o caminho de transmissão, ele recebe o fluxo de carga útil dataStreamInTx e o fluxo de informações do cabeçalho udpIpMetaDataIn e gera o fluxo de pacotes UDP/IP/Ethernet axiStreamOutTx . Não há necessidade de fornecer MacMetaData que contém informações de cabeçalho Ethernet como módulo mkUdpIpEthTx , porque mkArpProcessor é responsável por lidar com a resolução de endereços MAC e gerar informações de cabeçalho Ethernet.
Para o caminho de recepção, ele funciona de maneira oposta, extraindo dataStreamOutRx transportando fluxo de carga útil e udpIpMetaDataOutRx transportando fluxo de informações de cabeçalho de axiStreamInRx transportando fluxo de pacotes UDP/IP/Ethernet.
O gerador e o analisador de pacotes Ethernet são compartilhados tanto pelo pacote UDP/IP quanto pelo pacote ARP, portanto, Mux e Demux adicionais são necessários no caminho de transmissão e recepção para arbitragem e distribuição de fluxo. O parâmetro do módulo isSupportRdma especifica se ele suporta ou não o processamento de pacotes RoCE. Se o suporte para RDMA estiver desabilitado, precisaremos apenas de mkUdpIpStream e mkUdpIpMetaAndDataStream no caminho de transmissão e recepção, 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 ) ;
O módulo envolve mkGenericUdpIpArpEthRxTx usando módulos fornecidos em blue-wrapper para gerar uma interface Verilog pronta para uso.
O módulo integra o módulo mkGenericUdpIpArpEthRxTx e o módulo mkXilinxCmacTxWrapper . Ele foi projetado para interagir com Xilinx CMAC IP para transmitir e receber pacotes UDP/IP/Ethernet de e para meio físico.
Os módulos no pacote PriorityFlowControl são implementados para realizar o mecanismo de controle de fluxo prioritário para garantir a transmissão de rede sem perdas.
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 e mkGenericUdpIpArpEthRxTx para fornecer a funcionalidade de geração e análise de pacotes UDP/IP/Ethernet enquanto oferece suporte ao controle de fluxo de prioridade. Para transmissão de pacotes, são necessários oito canais de fluxo de carga útil e informações de cabeçalho UDP/IP e gera um fluxo de pacotes UDP/IP/Ethernet. Para recepção de pacotes, ele recebe um fluxo de pacotes UDP/IP/Ethernet e roteia o cabeçalho UDP/IP extraído e o fluxo de carga útil para um dos oito canais de saída.
mkPfcUdpIpArpEthCmacRxTx integra o módulo mkGenericPfcUdpIpArpEthRxTx e o módulo mkXilinxCmacTxWrapper . Ele foi projetado para interagir com Xilinx CMAC IP para transmitir e receber pacotes UDP/IP/Ethernet de e para meio físico.
A síntese e implementação do módulo principal mkGenericUdpIpArpEthRxTx são realizadas com base no dispositivo Xilinx xcvu9p usando Vivado. E os resultados mostram que o circuito pode atingir a frequência de trabalho de 500 MHz e fornecer pico de transferência de 128 Gbps. O uso de recursos de hardware é listado a seguir:
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 seção apresenta como começar este projeto. Antes de qualquer outra etapa, primeiro você precisa configurar o ambiente de desenvolvimento referindo-se ao script setup.sh. Aqui está uma lista de dependências:
Após configurar o ambiente, clone este repositório em um diretório específico. Aqui nos referimos a este diretório como BLUE_ETH:
git clone --recursive https://github.com/wengwz/blue-ethernet.git $( BLUE_ETH )
Existem três níveis diferentes de testbenches fornecidos em 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
Os scripts usados para executar a síntese e implementação de projetos são fornecidos no diretório $(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 ...
A implementação do blue-ethernet envolve o uso das seguintes bibliotecas externas: