• 已绑定课时
  • 工程师可点评

实验报告 · 本节笔记 课程:中级 | FPGA工程师实战精进课程(送板卡+证书) · 第一部分 进阶接口设计篇 发布自课程云笔记 · FPGA 实验证据骨架 【本节要点】 ARP RX接收端代码 ARP 顶层 【疑问/坑点】 【可复用的代码/思路】 ARP_RX接口 `timescale 1ns / 1ps module ARP_RX( input wire rst_n , input wire…

旭晨
6 0

实验报告 · 本节笔记

课程:中级 | FPGA工程师实战精进课程(送板卡+证书) · 第一部分 进阶接口设计篇

发布自课程云笔记 · FPGA 实验证据骨架

ARP RX接收端代码

ARP 顶层

ARP_RX接口

`timescale 1ns / 1ps

module ARP_RX(
input   wire            rst_n       ,
input   wire            arp_rxc     ,
input   wire            arp_rxv     ,
input   wire    [7:0]   arp_rxd     ,
output  reg     [47:0]  pc_mac      ,
output  reg     [31:0]  pc_ip       ,
output  wire            arp_rx_op   ,
output  wire            arp_rx_done
);

parameter FPGA_MAC = 48'h00_11_22_33_44_55  ;
parameter FPGA_IP  = 32'hC0_A8_00_03        ;

localparam  IDLE        =   1   ,//空闲
PREAMBL     =   2   ,//前导码 6字节         0~6
SFD         =   3   ,//帧起始界定符 1字节    6~7
ETH_MAC0    =   4   ,//目的PC MAC 6字节     8~13
ETH_MAC_S   =   5   ,//源FPGA MAC 6字节     14~19
ARP_START0  =   6   ,//长度|类型 2字节       20~21
ARP_START1  =   7   ,//硬件类型 2字节        22~23
ARP_START2  =   8   ,//协议类型 2字节        24~25
ARP_START3  =   9   ,//硬件地址长度6 1字节   26
ARP_START4  =   10  ,//协议地址长度6 1字节   27
OP          =   11  ,//arp协议类型 2字节     28~29
ETH_MAC_S1  =   12  ,//源FPGA MAC 6字节      30~35
ETH_IP_S1   =   13  ,//源FPGA IP 4字节       36~39
ETH_MAC1    =   14  ,//目的MAC PC 6字节      40~45
ETH_IP1     =   15  ,//目的IP PC 4字节       46~49
ARP_START5  =   16  ,//18字节00占位 18字节    50~67
CRC         =   17  ;//CRC32校验 4字节       68~71

reg [4:0]   cur_s       ;//现态
reg [4:0]   nex_s       ;//次态

reg [6:0]   cnt_byte    ;//字节计数
reg         error       ;//错误信号
reg [15:0]  op          ;
reg [47:0]  eth_mac     ;//目的mac
reg [31:0]  eth_ip      ;//目的ip
reg [47:0]  eth_mac_s   ;//源mac
reg [31:0]  eth_ip_s    ;//源ip

always @(posedge arp_rxc)
begin
if(!rst_n)
cur_s <= IDLE   ;
else
cur_s <= nex_s  ;
end

always @(*)
begin
case (cur_s)
IDLE        :
begin
if(arp_rxv && arp_rxd == 8'h55)
nex_s = PREAMBL ;
else
nex_s = cur_s   ;
end
PREAMBL     :
begin
if(error)
nex_s = IDLE ;
else if(cnt_byte == 5)
nex_s = SFD ;
else
nex_s = cur_s ;
end
SFD         :
begin//nex_s = ETH_MAC0 ; //只有一个字节也可以直接跳变到下个状态
if(error)
nex_s = IDLE ;
else if(cnt_byte == 6)
nex_s = ETH_MAC0 ;
else
nex_s = cur_s ;
end
ETH_MAC0    :
begin
if(error)
nex_s = IDLE ;
else if(cnt_byte == 12)//8~13
nex_s = ETH_MAC_S ;
else
nex_s = cur_s ;
end
ETH_MAC_S   :
begin
if(error)
nex_s = IDLE ;
else if(cnt_byte == 18)//14~19
nex_s = ARP_START0 ;
else
nex_s = cur_s ;
end
ARP_START0  :
begin
if(error)
nex_s = IDLE ;
else if(cnt_byte == 20)//20~21
nex_s = ARP_START1 ;
else
nex_s = cur_s ;
end
ARP_START1  :
begin
if(error)
nex_s = IDLE ;
else if(cnt_byte == 22)//22~23
nex_s = ARP_START2 ;
else
nex_s = cur_s ;
end
ARP_START2  :
begin
if(error)
nex_s = IDLE ;
else if(cnt_byte == 24)//24~25
nex_s = ARP_START3 ;
else
nex_s = cur_s ;
end
ARP_START3  :
begin//nex_s = ARP_START4 ;//只有一个字节也可以直接跳变到下个状态
if(error)
nex_s = IDLE ;
else if(cnt_byte == 25)
nex_s = ARP_START4 ;
else
nex_s = cur_s ;
end
ARP_START4  :
begin//nex_s = OP ;//只有一个字节也可以直接跳变到下个状态
if(error)
nex_s = IDLE ;
else if(cnt_byte == 26)
nex_s = OP ;
else
nex_s = cur_s ;
end
OP          :
begin
if(error)
nex_s = IDLE ;
else if(cnt_byte == 28)//28~29
nex_s = ETH_MAC_S1 ;
else
nex_s = cur_s ;
end
ETH_MAC_S1  :
begin
if(error)
nex_s = IDLE ;
else if(cnt_byte == 34)//30~35
nex_s = ETH_IP_S1 ;
else
nex_s = cur_s ;
end
ETH_IP_S1   :
begin
if(error)
nex_s = IDLE ;
else if(cnt_byte == 38)//36~39
nex_s = ETH_MAC1 ;
else
nex_s = cur_s ;
end
ETH_MAC1    :
begin
if(error)
nex_s = IDLE ;
else if(cnt_byte == 44)//40~45
nex_s = ETH_IP1 ;
else
nex_s = cur_s ;
end
ETH_IP1     :
begin
if(error)
nex_s = IDLE ;
else if(cnt_byte == 48)//46~49
nex_s = ARP_START5 ;
else
nex_s = cur_s ;
end
ARP_START5  :
begin
if(error)
nex_s = IDLE ;
else if(cnt_byte == 66)//50~67
nex_s = CRC ;
else
nex_s = cur_s ;
end
CRC         :
begin
if(error)
nex_s = IDLE ;
else if(cnt_byte == 70)//68~71
nex_s = IDLE ;
else
nex_s = cur_s ;
end
default     :   nex_s = IDLE ;
endcase
end

//字节计数器
always @(posedge arp_rxc)
begin
if(!rst_n)
cnt_byte <= 0 ;
else if(cur_s == IDLE)
cnt_byte <= 0 ;
else
cnt_byte <= cnt_byte + 1 ;
end

//error
always @(posedge arp_rxc)
begin
if(!rst_n)
error <= 0 ;
else
case (cur_s)
IDLE        : error <= 0 ;
PREAMBL     :
begin
if(cnt_byte < 6 && arp_rxd != 8'h55)
error <= 1 ;
else
error <= 0 ;
end
SFD         :begin
if(cnt_byte == 6 && arp_rxd != 8'h55)
error <= 1 ;
else
error <= 0 ;
end
ETH_MAC0    :error <= 0 ;
ETH_MAC_S   :error <= 0 ;
ARP_START0  :begin
if((cnt_byte == 19 && arp_rxd != 8'h08)||(cnt_byte == 20 && arp_rxd != 8'h06))
error <= 1 ;
else
error <= 0 ;
end
ARP_START1  :begin
if((cnt_byte == 21 && arp_rxd != 8'h00)||(cnt_byte == 22 && arp_rxd != 8'h01))
error <= 1 ;
else
error <= 0 ;
end
ARP_START2  :begin
if((cnt_byte == 23 && arp_rxd != 8'h08)||(cnt_byte == 24 && arp_rxd != 8'h00))
error <= 1 ;
else
error <= 0 ;
end
ARP_START3  :begin
if(cnt_byte == 25 && arp_rxd != 8'h06)
error <= 1 ;
else
error <= 0 ;
end
ARP_START4  :begin
if(cnt_byte == 26 && arp_rxd != 8'h04)
error <= 1 ;
else
error <= 0 ;
end
OP          :begin
if((cnt_byte == 27 && arp_rxd != 8'h00)||(cnt_byte == 28 && arp_rxd != 8'h01 && arp_rxd != 8'h02))
error <= 1 ;
else
error <= 0 ;
end
ETH_MAC_S1  :error <= 0;
ETH_IP_S1   :error <= 0;
ETH_MAC1    :begin
if(cnt_byte == 44 && op == 16'h0002 && eth_mac != FPGA_MAC)
error <= 1 ;
else
error <= 0 ;
end
ETH_IP1     :error <= 0 ;
ARP_START5  :begin
if(cnt_byte == 49 && eth_ip != FPGA_IP)
error <= 1 ;
else
error <= 0 ;
end
CRC         :error <= 0 ;
default     :error <= 0 ;
endcase
end

//op
always @(posedge arp_rxc)
begin
if(!rst_n)
op <= 0 ;
else if(cur_s == OP)
op <= {op[7:0],arp_rxd} ;
end

//eth_mac
always @(posedge arp_rxc)
begin
if(!rst_n)
eth_mac <= 0 ;
else if(cur_s == ETH_MAC0)
eth_mac <= {eth_mac[39:0],arp_rxd} ;
end

//eth_ip
always @(posedge arp_rxc)
begin
if(!rst_n)
eth_ip <= 0 ;
else if(cur_s == ETH_IP1)
eth_ip <= {eth_ip[23:0],arp_rxd} ;
end

//eth_mac_s
always @(posedge arp_rxc)
begin
if(!rst_n)
eth_mac_s <= 0 ;
else if(cur_s == ETH_MAC_S1)
eth_mac_s <= {eth_mac_s[39:0],arp_rxd} ;
end

//eth_ip_s
always @(posedge arp_rxc)
begin
if(!rst_n)
eth_ip_s <= 0 ;
else if(cur_s == ETH_IP_S1)
eth_ip_s <= {eth_ip_s[23:0],arp_rxd} ;
end

//pc_mac
always @(posedge arp_rxc)
begin
if(!rst_n)
pc_mac <= 0 ;
else if(op == 16'h0002 && CRC)
pc_mac <= eth_mac_s ;
end

//pc_ip
always @(posedge arp_rxc)
begin
if(!rst_n)
pc_ip <= 0 ;
else if(op == 16'h0002 && CRC)
pc_ip <= eth_ip_s ;
end

assign arp_rx_op   = op[0] ;//01,02:1:请求包、0:应答包
assign arp_rx_done = (cur_s == CRC && cnt_byte == 70)?1:0 ;

endmodule
`timescale 1ns / 1ps

module ARP(
input   wire            rst_n       ,//复位
//TX
input   wire            arp_txc     ,//时钟
output  wire    [7:0]   arp_txd     ,//数据
output  wire            arp_txv     ,//有效信号
//RX
input   wire            arp_rxc     ,
input   wire            arp_rxv     ,
input   wire    [7:0]   arp_rxd     ,
//控制
input   wire            arp_tx_en   ,//arp发送使能信号
input   wire            arp_tx_op   ,//arp发送数据包的类型:请求|应答
//目的
output  wire    [47:0]  pc_mac      ,
output  wire    [31:0]  pc_ip       ,
output  wire            arp_rx_op   ,
output  wire            arp_rx_done
);

//tx
wire            crc_e       ;
wire            crc_init    ;
wire            arp_tx_done ;
//CRC
wire    [31:0]  crc_data    ;
wire    [31:0]  crc_next    ;

ARP_TX ARP_TX_u(
.arp_txc     (arp_txc    ),//时钟
.rst_n       (rst_n      ),//复位
.arp_tx_en   (arp_tx_en  ),//arp发送使能信号
.arp_tx_op   (arp_tx_op  ),//arp发送数据包的类型:请求|应答
.des_mac     (pc_mac     ),//接收到请求包(源mac),发送应答包(目的mac)
.des_ip      (pc_ip      ),//接收到请求包
.arp_txd     (arp_txd    ),//数据
.arp_txv     (arp_txv    ),//有效信号
.arp_tx_done (arp_tx_done),//结束信号
.crc_d       (crc_d      ),//crc32校验数据
.crc_e       (crc_e      ),//开始校验的使能
.crc_init    (crc_init   ) //初始化信号
);

ARP_RX ARP_RX_u(
.rst_n       (rst_n      ),
.arp_rxc     (arp_rxc    ),
.arp_rxv     (arp_rxv    ),
.arp_rxd     (arp_rxd    ),
.pc_mac      (pc_mac     ),
.pc_ip       (pc_ip      ),
.arp_rx_op   (arp_rx_op  ),
.arp_rx_done (arp_rx_done)
);

crc32_data crc32_data_u(
.clk        (arp_txc ),
.rst_n      (rst_n   ),
.data       (arp_txd ),
.crc_en     (crc_en  ),
.crc_clr    (crc_init),
.crc_data   (crc_data),
.crc_next   (crc_next)
);

endmodule

本节要验证什么?预期现象是什么?

用工具栏插入波形图、仿真界面或示波器照片

粘贴关键仿真输出或报错原文

板卡现象、按键/数码管/接口实测结果

结论、坑点与下一步修改

学习上下文

产出状态

工程师已阅6 位工程师