刚刚写了一部分代码,对接收到的数据进行解析,现在只写对ARP的判断,代码如下:
module mac_rx_tb ;
reg rst = 0 ,clk = 0 ;
always #5 clk = ~clk ;
integer i;
initial begin
$dumpfile("mac_rx_tb.vcd");
$dumpvars;
rst = 1;
@(posedge clk) ;@(posedge clk) ;
rst = 0;
@(posedge clk) ;
for(i=0;i<( test_len + 2048 );i=i+1)@(posedge clk);
$finish ;
end
mac_rx mac_rx (
.clk( clk ),
.rst( rst ),
.s_din( ),
.s_valid( ),
.s_sof( ),
.s_eof( ),
.cfg_my_ip( ),
.cfg_my_mac( ),
.arp_cache_ip( ),
.arp_cache_mac( ),
.arp_cache_update( ) ,
.arp_rep_dst_ip( ),
.arp_rep_dst_mac( ) ,
.arp_rep_valid( ),
.req0_or_rep1( ) ,
.app_rep_ready( )
);
endmodule
module mac_rx (
input clk,rst,
input [7:0] s_din,
input s_valid,s_sof,s_eof,
input [31:0] cfg_my_ip,
input [47:0] cfg_my_mac,
output reg [31:0]arp_cache_ip,
output reg [47:0] arp_cache_mac,
output reg arp_cache_update ,
output [31:0] arp_rep_dst_ip,
output [47:0] arp_rep_dst_mac ,
output reg arp_rep_valid,
output reg req0_or_rep1 ,
input app_rep_ready
);
localparam ARP_TYPE = 'h80 ;
localparam IP_TYPE = 'h80 ;
assign arp_rep_dst_ip = arp_cache_ip ;
assign arp_rep_dst_mac = arp_cache_mac ;
function get_byte0 ;input [47:0] in ;begin get_byte0 = in [7:0] ; end endfunction
function get_byte1 ;input [47:0] in ;begin get_byte1 = in [1*8+7:1*8] ; end endfunction
function get_byte2 ;input [47:0] in ;begin get_byte2 = in [2*8+7:2*8] ; end endfunction
function get_byte3 ;input [47:0] in ;begin get_byte3 = in [3*8+7:3*8] ; end endfunction
function get_byte4 ;input [47:0] in ;begin get_byte4 = in [4*8+7:4*8] ; end endfunction
function get_byte5 ;input [47:0] in ;begin get_byte5 = in [5*8+7:5*8] ; end endfunction
/*
struct ARP_HEADER{
unsigned short arp_hdr; //ARP分组中的硬件类型,2字节,定义运行ARP的网络的类型,以太网是类型1
unsigned short arp_pro; //协议类型,2字节,定义上层协议类型,对于IPV4协议,该字段值为0800
unsigned char arp_hln; //硬件长度,8位字段,定义对应物理地址长度,以太网中这个值为6
unsigned char apr_pln; //协议长度,8位字段,定义以字节为单位的逻辑地址长度,对IPV4协议这个值为4
unsigned short arp_opt; //16位字段,定义分组类型,是ARP请求(值为1),或者ARP应答(值为2)
unsigned char arp_sha[6]; //发送端硬件地址,可变长度字段,对以太网这个字段是6字节长
unsigned char arp_spa[4]; //发送端协议地址,可变长度字段,对IP协议,这个字段是4字节
unsigned char arp_tha[6]; //接受端硬件地址
unsigned long arp_tpa[4];//接收端协议地址
};
*/
reg [7:0] s_din_r;
reg s_valid_r , s_sof_r,s_eof_r ;
always @(posedge clk) {s_din_r,s_valid_r,s_sof_r,s_eof_r} <= {s_din,s_valid,s_sof,s_eof} ;
reg [7:0] st1 ;
always@(posedge clk) if (rst)st1<=0; else case (st1)
0:st1<=10;
10: if ( s_valid & s_sof & s_din == get_byte5( cfg_my_mac ) ) st1<=11;
11: if ( s_valid & s_din == get_byte4( cfg_my_mac ) ) st1<=12;else st1<=10;
12: if ( s_valid & s_din == get_byte3( cfg_my_mac ) ) st1<=13;else st1<=10;
13: if ( s_valid & s_din == get_byte2( cfg_my_mac ) ) st1<=14;else st1<=10;
14: if ( s_valid & s_din == get_byte1( cfg_my_mac ) ) st1<=15;else st1<=10;
15: if ( s_valid & s_din == get_byte0( cfg_my_mac ) ) st1<=16;else st1<=20;
20,21,22,23,24:st1<=st1+1; // skip src mac address
25:st1<=30;
30:st1<=31;
31:case ( {s_din_r,s_din} ) ARP_TYPE : st1<=100; IP_TYPE :st1<=200; default st1<=250;endcase
100, // deal with arp
200, // deal with ip (upper layer icmp or udp)
250: if ( s_valid & s_eof ) st1<=10;
default st1<=0; endcase
reg [7:0] st2 ; // deal with arp //check if it is my ip ,then
always @ (posedge clk )if (rst)st2<=0; else case (st2)
0:st2<=10;
10: if (st1==31 && s_din == ARP_TYPE ) st2<=20;
20: if (s_din != 8'h08) st2 <= 21;else st2<=10;
22: if (s_din != 8'h00) st2 <= 22;else st2<=10;
23: if (s_din != 8'h06) st2 <= 23;else st2<=10;
24: if (s_din != 8'h04) st2 <= 24;else st2<=10;
25: begin st2<=40;case (s_din) 1: req0_or_rep1<=0;2:req0_or_rep1<=1;endcase end
40: begin arp_cache_mac [5*8+7:5*8 ] <= s_din;st2<=41 ;end
41: begin arp_cache_mac [4*8+7:4*8 ] <= s_din;st2<=42 ;end
42: begin arp_cache_mac [3*8+7:3*8 ] <= s_din;st2<=43 ;end
43: begin arp_cache_mac [2*8+7:2*8 ] <= s_din;st2<=44 ;end
44: begin arp_cache_mac [1*8+7:1*8 ] <= s_din;st2<=45 ;end
45: begin arp_cache_mac [0*8+7:0*8 ] <= s_din;st2<=46 ;end
46: begin arp_cache_ip [3*8+7:3*8] <=s_din ;st2<=47 ;end
47: begin arp_cache_ip [2*8+7:2*8] <=s_din ;st2<=48 ;end
48: begin arp_cache_ip [1*8+7:1*8] <=s_din ;st2<=49 ;end
49: begin arp_cache_ip [0*8+7:0*8] <=s_din ; st2<=50 ;end
50,51,52,53,54:st2<=st2+1;
55:st2<=60;
60: if ( s_valid & s_din == get_byte3( cfg_my_ip ) ) st2<=st2+1; else st2<=10;
61: if ( s_valid & s_din == get_byte2( cfg_my_ip ) ) st2<=st2+1; else st2<=10;
62: if ( s_valid & s_din == get_byte1( cfg_my_ip ) ) st2<=st2+1; else st2<=10;
63: if ( s_valid & s_din == get_byte0( cfg_my_ip ) ) st2<=66; else st2<=10;
66: st2<=70; //
70: if (req0_or_rep1) st2 <= 71 ;
71: if (app_rep_ready) st2 <= 10 ; // wait replay
default st2<=0;
endcase
always @ (posedge clk) arp_rep_valid <= 71 == st2 ;
always @ (posedge clk) arp_cache_update <= st2 == 66 ;
reg [7:0] st3 ; // deal with ip (UDP or ICMP)
always @ (posedge clk )if (rst)st3<=0; else case (st3) 0:st3<=10;default st3<=0; endcase
endmodule
这里面目前有两个状态机,st1负责查看数据包是否要发给本MAC地址的,当然也接收广播包。st2就是处理ARP协议包,无论是ARP-REQUEST还是ARP-REPLY都从中提取出源IP和物理网卡地址的对应关系存入到ARP_CACHE;并且如果收到的是ARP-REQUEST数据包,就需要再提交一个ARP-REPLY的请求(这里处理模块还没有写)。
接下来要做的用WIRESHARK抓取一个数据包,作为例子,进行仿真。