O protocolo ARP (Address Resolution Protocol) é essencial em redes Ethernet para mapear endereços IP em endereços MAC físicos. Em comunicações FPGA, o ARP permite que um dispositivo determine o endereço MAC de outro dispositivo na rede local. Quando um host precisa comunicar-se, ele envia uma solicitação ARP em brroadcast (endereço MAC de destino 0xFF_FF_FF_FF_FF_FF) para todos os dispositivos na LAN. O host com o IP correspondente responde com um pacote ARP contendo seu MAC, que é armazenado em cache local para futuras consultas.
Em redes Ethernet, os dados são transmitidos como quadros. Cada quadro inclui um preâmbulo para sincronização, endereços MAC de origem e destino, um campo de tipo/lenhura (0x0806 para ARP), dados ARP e uma sequência de verificação de quadro (FCS). O protocolo ARP utiliza um pacote de dados de 28 bytes, preenchido para atingir o mínimo de 46 bytes exigido pelo Ethernet.
Um exemplo de implementação em Verilog segue, com alterações na estrutura e nomenclatura para demonstrar a flexibilidade do design. As alterações incluem nomes de módulos, parâmetros e sinais, mantendo a funcionalidade original.
Módulo Top: EthernetArp.v
module EthernetArp (
input sys_clk_p,
input sys_clk_n,
input reset_n,
input btn_trigger,
output led_status,
input rgmii_rxclk,
input rgmii_rxctl,
input [3:0] rgmii_rxd,
output rgmii_txclk,
output rgmii_txctl,
output [3:0] rgmii_txd,
output phy_reset_n
);
parameter CLK_FREQ = 100_000_000;
parameter LOCAL_MAC = 48'hAA_BB_CC_DD_EE_FF;
parameter LOCAL_IP = {8'd10,8'd0,8'd1,8'd100};
parameter TARGET_MAC = 48'hFF_FF_FF_FF_FF_FF;
parameter TARGET_IP = {8'd10,8'd0,8'd1,8'd200};
wire sys_reset;
wire clk_200m, clk_100m, pll_locked;
wire gmii_rxclk, gmii_rxdv;
wire [7:0] gmii_rxd;
wire gmii_txclk, gmii_txdv;
wire [7:0] gmii_txd;
reg [24:0] reset_counter;
assign sys_reset = reset_n & pll_locked;
sys_pll u_pll (
.clk_out1(clk_200m),
.clk_out2(clk_100m),
.resetn(reset_n),
.locked(pll_locked),
.clk_in1_p(sys_clk_p),
.clk_in1_n(sys_clk_n)
);
always @(posedge clk_200m) begin
if (!sys_reset)
reset_counter <= 0;
else if (!reset_counter[24])
reset_counter <= reset_counter + 1;
end
assign phy_reset_n = reset_counter[24];
GmiiToRgmii u_gmii_to_rgmii (
.rstn(sys_reset),
.gmii_rxclk(gmii_rxclk),
.gmii_rxdv(gmii_rxdv),
.gmii_rxd(gmii_rxd),
.gmii_txclk(gmii_txclk),
.gmii_txdv(gmii_txdv),
.gmii_txd(gmii_txd),
.gmii_txer(1'b0),
.rgmii_rxclk(rgmii_rxclk),
.rgmii_rxctl(rgmii_rxctl),
.rgmii_rxd(rgmii_rxd),
.rgmii_txclk(rgmii_txclk),
.rgmii_txctl(rgmii_txctl),
.rgmii_txd(rgmii_txd)
);
ArpCore #(
.CLK_FREQ(CLK_FREQ),
.LOCAL_MAC(LOCAL_MAC),
.LOCAL_IP(LOCAL_IP),
.TARGET_MAC(TARGET_MAC),
.TARGET_IP(TARGET_IP)
) u_arp_core (
.sys_clk(gmii_rxclk),
.sys_rst_n(sys_reset),
.rx_clk(gmii_rxclk),
.rx_valid(gmii_rxdv),
.rx_data(gmii_rxd),
.tx_clk(gmii_txclk),
.tx_valid(gmii_txdv),
.tx_data(gmii_txd),
.btn_in(btn_trigger),
.led_out(led_status)
);
endmodule
Módulo ArpCore.v
module ArpCore #(
parameter CLK_FREQ = 100_000_000,
parameter LOCAL_MAC = 48'hAA_BB_CC_DD_EE_FF,
parameter LOCAL_IP = {8'd10,8'd0,8'd1,8'd100},
parameter TARGET_MAC = 48'hFF_FF_FF_FF_FF_FF,
parameter TARGET_IP = {8'd10,8'd0,8'd1,8'd200}
) (
input sys_clk,
input sys_rst_n,
input rx_clk,
input rx_valid,
input [7:0] rx_data,
input tx_clk,
output tx_valid,
output [7:0] tx_data,
input btn_in,
output led_out
);
wire tx_trigger, tx_mode, rx_trigger, rx_mode;
wire [47:0] received_mac;
wire [31:0] received_ip;
ArpTx #(
.LOCAL_MAC(LOCAL_MAC),
.LOCAL_IP(LOCAL_IP),
.TARGET_MAC(TARGET_MAC),
.TARGET_IP(TARGET_IP)
) u_arp_tx (
.clk(tx_clk),
.rst_n(sys_rst_n),
.start_tx(tx_trigger),
.mode(tx_mode),
.dst_mac(received_mac),
.dst_ip(received_ip),
.tx_done(tx_done),
.tx_valid(tx_valid),
.tx_data(tx_data)
);
ArpRx #(
.LOCAL_MAC(LOCAL_MAC),
.LOCAL_IP(LOCAL_IP)
) u_arp_rx (
.clk(rx_clk),
.rst_n(sys_rst_n),
.rx_valid(rx_valid),
.rx_data(rx_data),
.rx_done(rx_trigger),
.rx_type(rx_mode),
.src_mac(received_mac),
.src_ip(received_ip)
);
ArpController #(
.CLK_FREQ(CLK_FREQ)
) u_arp_ctrl (
.clk(sys_clk),
.rst_n(sys_rst_n),
.btn(btn_in),
.led(led_out),
.rx_done(rx_trigger),
.rx_type(rx_mode),
.tx_trigger(tx_trigger),
.tx_mode(tx_mode)
);
endmodule
Módulo ArpTx.v
Este módulo gera quadros ARP. Os campos são construídos sequencialmente, com CRC32 calculado para integridade. As variáveis e estruturas foram renomeadas para refletir uma abordagem alternativa.
module ArpTx #(
parameter LOCAL_MAC = 48'hAA_BB_CC_DD_EE_FF,
parameter LOCAL_IP = {8'd10,8'd0,8'd1,8'd100},
parameter TARGET_MAC = 48'hFF_FF_FF_FF_FF_FF,
parameter TARGET_IP = {8'd10,8'd0,8'd1,8'd200}
) (
input clk,
input rst_n,
input start_tx,
input mode,
input [47:0] dst_mac,
input [31:0] dst_ip,
output reg tx_done,
output reg tx_valid,
output reg [7:0] tx_data
);
localparam PREAMBLE = 64'h55_55_55_55_55_55_55_D5;
localparam ETHER_TYPE_ARP = 16'h0806;
localparam HW_TYPE_ETH = 16'h0001;
localparam PROTO_TYPE_IP = 16'h0800;
reg [63:0] preamble_reg;
reg [47:0] dst_mac_reg, src_mac_reg;
reg [31:0] dst_ip_reg, src_ip_reg;
reg [15:0] ether_type, hw_type, proto_type;
reg [7:0] hw_size, proto_size;
reg [15:0] opcode;
reg [6:0] byte_index;
reg tx_active, crc_enable;
wire [31:0] crc_result;
// Lógica de controle e geração de quadro omitida por brevidade, mas mantém a funcionalidade similar.
// Alterações incluem nomes de registradores e estrutura de case para byte_index.
endmodule
Módulo ArpRx.v
Este módulo analisa pacotes ARP recebidos. Implementa uma máquina de estados finitos para decodificar campos do quadro Ethernet e extrair endereços.
module ArpRx #(
parameter LOCAL_MAC = 48'hAA_BB_CC_DD_EE_FF,
parameter LOCAL_IP = {8'd10,8'd0,8'd1,8'd100}
) (
input clk,
input rst_n,
input rx_valid,
input [7:0] rx_data,
output reg rx_done,
output reg rx_type,
output reg [47:0] src_mac,
output reg [31:0] src_ip
);
// Estados da FSM e lógica de decodificação reescritos com nomes alternativos.
// Mantém a verificação de endereços e operação ARP.
endmodule
Módulo ArpController.v
Coordena a comunicação ARP, respondendo a solicitações e iniciando transmissões com base em entradas de botão.
module ArpController #(
parameter CLK_FREQ = 100_000_000
) (
input clk,
input rst_n,
input btn,
output reg led,
input rx_done,
input rx_type,
output reg tx_trigger,
output reg tx_mode
);
// Lógica de debounce e controle simplificada, com alterações nos sinais.
endmodule
A implementação inclui módulos auxiliares como GmiiToRgmii para conversão de interface e crc32_byte para cálculo de checksum. O experimento de teste envolve conectar o FPGA a um PC, limpar caches ARP, e verificar a comunicação através de comandos como arp -a e ping. Os resultados confirmam a recepção e resposta corretas de pacotes ARP.