赞
踩
前面完成了(四)ARP的处理,但是似乎少了点东西,既然说了ARP处理,不顺手再实现一个ARP表不就白来了吗。
如果主机A对FPGA发送IP协议的数据,就需要先发送ARP得到FPGA端的MAC地址,而FPGA对其解析后再做相应处理,比如需要再发送IP协议到主机A端,那么是不是得一直保存主机A的MAC地址或者FPGA发送ARP请求帧去请求主机A的MAC地址?
那可不可以主机A先发送的ARP请求帧时,就将其MAC/IP地址的映射存入到RAM当中,当FPGA要发送IP协议的数据时(比如ICMP或者UDP),就直接在RAM中查询主机A的MAC地址,然后再封帧进行发送,这样就省得再发ARP问询了。好,到这个时候,ARP表的功能就出了。
作为一个MAC/IP地址的映射表,首先就需要确定存入什么样的数据,然后是怎么样将数据存入,最后是怎样取出数据,本文设计采用以下方式:
获取ARP报文的各字段信息前文已经说过,本文不再说明。
当Opcode字段为16'h0001或者16'h0002时,则开始更新ARP表:
assign update_arptable_en = ((arp_opcode == 16'h0001) || (arp_opcode == 16'h0002))
对于采用何种算法完成HASH计算确实是个问题,但是前面在检验一文中提到使用CRC算法,还提了一个在线生成源码的工具,所以本文就直接使用该工具,生成32bit数据位宽的CRC计算模块来实现HASH计算,如下所示,其中nextCRC8_D32即在线生成的function。
- wire [7:0] new_crc;
- assign new_crc = nextCRC8_D32(calc_data_i,8'hff);
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- crc32_o <= 8'h0;
- end
- else if(calc_en_i) begin
- crc32_o <= new_crc;
- end
- end
-
- always@(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- crc32_valid_o <= 1'h0;
- end
- else begin
- crc32_valid_o <= calc_en_i;
- end
- end
- // polynomial: x^8 + x^2 + x^1 + 1
- // data width: 32
- // convention: the first serial bit is D[31]
- function [7:0] nextCRC8_D32;
- input [31:0] Data;
- input [7:0] crc;
- reg [31:0] d;
- reg [7:0] c;
- reg [7:0] newcrc;
- begin
- d = Data;
- c = crc;
- newcrc[0] = d[31] ^ d[30] ^ d[28] ^ d[23] ^ d[21] ^ d[19] ^ d[18] ^ d[16] ^ d[14] ^ d[12] ^ d[8] ^ d[7] ^ d[6] ^ d[0] ^ c[4] ^ c[6] ^ c[7];
- newcrc[1] = d[30] ^ d[29] ^ d[28] ^ d[24] ^ d[23] ^ d[22] ^ d[21] ^ d[20] ^ d[18] ^ d[17] ^ d[16] ^ d[15] ^ d[14] ^ d[13] ^ d[12] ^ d[9] ^ d[6] ^ d[1] ^ d[0] ^ c[0] ^ c[4] ^ c[5] ^ c[6];
- newcrc[2] = d[29] ^ d[28] ^ d[25] ^ d[24] ^ d[22] ^ d[17] ^ d[15] ^ d[13] ^ d[12] ^ d[10] ^ d[8] ^ d[6] ^ d[2] ^ d[1] ^ d[0] ^ c[0] ^ c[1] ^ c[4] ^ c[5];
- newcrc[3] = d[30] ^ d[29] ^ d[26] ^ d[25] ^ d[23] ^ d[18] ^ d[16] ^ d[14] ^ d[13] ^ d[11] ^ d[9] ^ d[7] ^ d[3] ^ d[2] ^ d[1] ^ c[1] ^ c[2] ^ c[5] ^ c[6];
- newcrc[4] = d[31] ^ d[30] ^ d[27] ^ d[26] ^ d[24] ^ d[19] ^ d[17] ^ d[15] ^ d[14] ^ d[12] ^ d[10] ^ d[8] ^ d[4] ^ d[3] ^ d[2] ^ c[0] ^ c[2] ^ c[3] ^ c[6] ^ c[7];
- newcrc[5] = d[31] ^ d[28] ^ d[27] ^ d[25] ^ d[20] ^ d[18] ^ d[16] ^ d[15] ^ d[13] ^ d[11] ^ d[9] ^ d[5] ^ d[4] ^ d[3] ^ c[1] ^ c[3] ^ c[4] ^ c[7];
- newcrc[6] = d[29] ^ d[28] ^ d[26] ^ d[21] ^ d[19] ^ d[17] ^ d[16] ^ d[14] ^ d[12] ^ d[10] ^ d[6] ^ d[5] ^ d[4] ^ c[2] ^ c[4] ^ c[5];
- newcrc[7] = d[30] ^ d[29] ^ d[27] ^ d[22] ^ d[20] ^ d[18] ^ d[17] ^ d[15] ^ d[13] ^ d[11] ^ d[7] ^ d[6] ^ d[5] ^ c[3] ^ c[5] ^ c[6];
- nextCRC8_D32 = newcrc;
- end
- endfunction
对待更新的MAC/IP地址中的IP地址进行HASH计算,得到的8bit的计算结果取低位作为ARP表(RAM)的地址,并将MAC/IP地址信息存入到RAM中,如下所示,使用了一个数据位宽为80bit,深度为2^4=16的双端口RAM作为了ARP表,其中RAM的a端作为更新端,b端作为查询端。
- assign arp_table_mem_wea = crc_calc_result_valid;
- assign arp_table_mem_addra = crc_calc_result[ARP_TB_W-1:0];
- assign arp_table_mem_dina = {arp_sender_ip,arp_sender_mac};
-
- dual_ram#(
- .RAM_DW (80), //ram data width
- .RAM_DP (ARP_TB_W) //ARP_TB_W取4, ram depth 2^4 = 16
- ) U_arp_table_mem(
- .rst_n (rst_n),
-
- .clka (clk),
- .wea (arp_table_mem_wea),
- .addra (arp_table_mem_addra),
- .dina (arp_table_mem_dina),
- .douta (arp_table_mem_douta),
-
- .clkb (clk),
- .web (arp_table_mem_web),
- .addrb (arp_table_mem_addrb),
- .dinb (arp_table_mem_dinb),
- .doutb (arp_table_mem_doutb)
- );
当外部逻辑需要通过IP地址查询MAC地址时,即同样对待查询的IP地址进行HASH计算,将其计算结果的低位作为ARP表(RAM)的b端读取地址,得到的MAC/IP信息后,再与待查询的IP地址进行比较输出,如下所示。
- //request IP&MAC mapping
- CRC8_D32 U1_CRC8_D32(
- .clk (clk),
- .rst_n (rst_n),
-
- .calc_data_i (req_ip_i),
- .calc_en_i (mac_ip_req_i),
-
- .crc32_o (req_crc_result),
- .crc32_valid_o (req_crc_result_valid)
- );
-
- assign arp_table_mem_web = 1'b0;
- assign arp_table_mem_addrb = req_crc_result[ARP_TB_W-1:0];
- assign arp_table_mem_dinb = 80'h0;
-
- dual_ram#(
- .RAM_DW (80), //ram data width
- .RAM_DP (ARP_TB_W) //ARP_TB_W取4, ram depth 2^4 = 16
- ) U_arp_table_mem(
- .rst_n (rst_n),
-
- .clka (clk),
- .wea (arp_table_mem_wea),
- .addra (arp_table_mem_addra),
- .dina (arp_table_mem_dina),
- .douta (arp_table_mem_douta),
-
- .clkb (clk),
- .web (arp_table_mem_web),
- .addrb (arp_table_mem_addrb),
- .dinb (arp_table_mem_dinb),
- .doutb (arp_table_mem_doutb)
- );
-
- //output result
- always @ (posedge clk or negedge rst_n) begin
- if(!rst_n) begin
- req_crc_result_valid_r <= 1'b0;
- mac_ip_ack_o <= 1'b0;
- ack_mac_o <= 48'h0;
- end
- else begin
- req_crc_result_valid_r <= req_crc_result_valid;
- mac_ip_ack_o <= req_crc_result_valid_r;
- ack_mac_o <= (arp_table_mem_doutb[79:48] == req_ip_i)?arp_table_mem_doutb[47:0]:48'h0;
- end
- end
以及即完成了ARP表的设计,不过设计中存在的HASH冲突问题并未解决,同时采用CRC8进行HASH计算资源消耗较大,换成简单一点的HASH算法可能更优,有兴趣的可以加以改进。
如有错误之处还望批评指正!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。