diff --git a/libraries/base/common/src/vhdl/common_network_total_header_pkg.vhd b/libraries/base/common/src/vhdl/common_network_total_header_pkg.vhd index 544b97ac9341718f62e4c32865e4e1452f31be6e..deaf4c35acacc09743dd0d71088acb01b9f1e3ec 100644 --- a/libraries/base/common/src/vhdl/common_network_total_header_pkg.vhd +++ b/libraries/base/common/src/vhdl/common_network_total_header_pkg.vhd @@ -222,6 +222,18 @@ PACKAGE common_network_total_header_pkg IS FUNCTION func_network_total_header_extract_icmp(hdr_arr : t_network_total_header_64b_arr) RETURN t_network_icmp_header; FUNCTION func_network_total_header_extract_udp( hdr_arr : t_network_total_header_32b_arr) RETURN t_network_udp_header; FUNCTION func_network_total_header_extract_udp( hdr_arr : t_network_total_header_64b_arr) RETURN t_network_udp_header; + + -- Combinatorial map just as above but for network packets without word align field. + FUNCTION func_network_total_header_no_align_extract_eth( hdr_arr : t_network_total_header_32b_arr) RETURN t_network_eth_header; + FUNCTION func_network_total_header_no_align_extract_eth( hdr_arr : t_network_total_header_64b_arr) RETURN t_network_eth_header; + FUNCTION func_network_total_header_no_align_extract_ip( hdr_arr : t_network_total_header_32b_arr) RETURN t_network_ip_header; + FUNCTION func_network_total_header_no_align_extract_ip( hdr_arr : t_network_total_header_64b_arr) RETURN t_network_ip_header; + FUNCTION func_network_total_header_no_align_extract_arp( hdr_arr : t_network_total_header_32b_arr) RETURN t_network_arp_packet; + FUNCTION func_network_total_header_no_align_extract_arp( hdr_arr : t_network_total_header_64b_arr) RETURN t_network_arp_packet; + FUNCTION func_network_total_header_no_align_extract_icmp(hdr_arr : t_network_total_header_32b_arr) RETURN t_network_icmp_header; + FUNCTION func_network_total_header_no_align_extract_icmp(hdr_arr : t_network_total_header_64b_arr) RETURN t_network_icmp_header; + FUNCTION func_network_total_header_no_align_extract_udp( hdr_arr : t_network_total_header_32b_arr) RETURN t_network_udp_header; + FUNCTION func_network_total_header_no_align_extract_udp( hdr_arr : t_network_total_header_64b_arr) RETURN t_network_udp_header; -- Construct the total header array from the individual header records FUNCTION func_network_total_header_construct_eth( eth : t_network_eth_header) RETURN t_network_total_header_32b_arr; -- sets unused words to zero @@ -250,6 +262,25 @@ PACKAGE common_network_total_header_pkg IS FUNCTION func_network_total_header_response_icmp(icmp_arr : t_network_total_header_64b_arr; mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_64b_arr; FUNCTION func_network_total_header_response_udp( udp_arr : t_network_total_header_32b_arr; mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_32b_arr; FUNCTION func_network_total_header_response_udp( udp_arr : t_network_total_header_64b_arr; mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_64b_arr; + + -- Construct the response total header array for a total header array without alignment bytes + FUNCTION func_network_total_header_no_align_response_eth( eth_arr : t_network_total_header_32b_arr; mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_32b_arr; + FUNCTION func_network_total_header_no_align_response_eth( eth_arr : t_network_total_header_64b_arr; mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_64b_arr; + FUNCTION func_network_total_header_no_align_response_arp( arp_arr : t_network_total_header_32b_arr; mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0); + ip_addr : STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0)) + RETURN t_network_total_header_32b_arr; + FUNCTION func_network_total_header_no_align_response_arp( arp_arr : t_network_total_header_64b_arr; mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0); + ip_addr : STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0)) + RETURN t_network_total_header_64b_arr; + FUNCTION func_network_total_header_no_align_response_ip( ip_arr : t_network_total_header_32b_arr; mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_32b_arr; + FUNCTION func_network_total_header_no_align_response_ip( ip_arr : t_network_total_header_64b_arr; mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_64b_arr; + FUNCTION func_network_total_header_no_align_response_icmp(icmp_arr : t_network_total_header_32b_arr; mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_32b_arr; + FUNCTION func_network_total_header_no_align_response_icmp(icmp_arr : t_network_total_header_64b_arr; mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_64b_arr; + FUNCTION func_network_total_header_no_align_response_udp( udp_arr : t_network_total_header_32b_arr; mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_32b_arr; + FUNCTION func_network_total_header_no_align_response_udp( udp_arr : t_network_total_header_64b_arr; mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_64b_arr; + + + END common_network_total_header_pkg; @@ -396,6 +427,146 @@ PACKAGE BODY common_network_total_header_pkg IS v_hdr.checksum := hdr_arr(5)(15 DOWNTO 0); RETURN v_hdr; END; + + -- Assume the total header has NOT been padded with the word align field + -- Map the 11 32b words or 6 64b longwords from the total header to the header field records + + FUNCTION func_network_total_header_no_align_extract_eth(hdr_arr : t_network_total_header_32b_arr) RETURN t_network_eth_header IS + VARIABLE v_hdr : t_network_eth_header; + BEGIN + v_hdr.dst_mac(47 DOWNTO 16) := hdr_arr(0); + v_hdr.dst_mac(15 DOWNTO 0) := hdr_arr(1)(31 DOWNTO 16); + v_hdr.src_mac(47 DOWNTO 32) := hdr_arr(1)(15 DOWNTO 0); + v_hdr.src_mac(31 DOWNTO 0) := hdr_arr(2); + v_hdr.eth_type := hdr_arr(3)(31 DOWNTO 16); + RETURN v_hdr; + END; + + FUNCTION func_network_total_header_no_align_extract_eth(hdr_arr : t_network_total_header_64b_arr) RETURN t_network_eth_header IS + VARIABLE v_hdr : t_network_eth_header; + BEGIN + v_hdr.dst_mac := hdr_arr(0)(63 DOWNTO 16); + v_hdr.src_mac(47 DOWNTO 32) := hdr_arr(0)(15 DOWNTO 0); + v_hdr.src_mac(31 DOWNTO 0) := hdr_arr(1)(63 DOWNTO 32); + v_hdr.eth_type := hdr_arr(1)(31 DOWNTO 16); + RETURN v_hdr; + END; + + FUNCTION func_network_total_header_no_align_extract_ip(hdr_arr : t_network_total_header_32b_arr) RETURN t_network_ip_header IS + VARIABLE v_hdr : t_network_ip_header; + BEGIN + v_hdr.version := hdr_arr(3)(15 DOWNTO 12); + v_hdr.header_length := hdr_arr(3)(11 DOWNTO 8); + v_hdr.services := hdr_arr(3)( 7 DOWNTO 0); + v_hdr.total_length := hdr_arr(4)(31 DOWNTO 16); + v_hdr.identification := hdr_arr(4)(15 DOWNTO 0); + v_hdr.flags := hdr_arr(5)(31 DOWNTO 29); + v_hdr.fragment_offset := hdr_arr(5)(28 DOWNTO 16); + v_hdr.time_to_live := hdr_arr(5)(15 DOWNTO 8); + v_hdr.protocol := hdr_arr(5)( 7 DOWNTO 0); + v_hdr.header_checksum := hdr_arr(6)(31 DOWNTO 16); + v_hdr.src_ip_addr(31 DOWNTO 16) := hdr_arr(6)(15 DOWNTO 0); + v_hdr.src_ip_addr(15 DOWNTO 0) := hdr_arr(7)(31 DOWNTO 16); + v_hdr.dst_ip_addr(31 DOWNTO 16) := hdr_arr(7)(15 DOWNTO 0); + v_hdr.dst_ip_addr(15 DOWNTO 0) := hdr_arr(8)(31 DOWNTO 16); + RETURN v_hdr; + END; + + FUNCTION func_network_total_header_no_align_extract_ip(hdr_arr : t_network_total_header_64b_arr) RETURN t_network_ip_header IS + VARIABLE v_hdr : t_network_ip_header; + BEGIN + v_hdr.version := hdr_arr(1)(15 DOWNTO 12); + v_hdr.header_length := hdr_arr(1)(11 DOWNTO 8); + v_hdr.services := hdr_arr(1)( 7 DOWNTO 0); + v_hdr.total_length := hdr_arr(2)(63 DOWNTO 48); + v_hdr.identification := hdr_arr(2)(47 DOWNTO 32); + v_hdr.flags := hdr_arr(2)(31 DOWNTO 29); + v_hdr.fragment_offset := hdr_arr(2)(28 DOWNTO 16); + v_hdr.time_to_live := hdr_arr(2)(15 DOWNTO 8); + v_hdr.protocol := hdr_arr(2)( 7 DOWNTO 0); + v_hdr.header_checksum := hdr_arr(3)(63 DOWNTO 48); + v_hdr.src_ip_addr := hdr_arr(3)(47 DOWNTO 16); + v_hdr.dst_ip_addr(31 DOWNTO 16) := hdr_arr(3)(15 DOWNTO 0); + v_hdr.dst_ip_addr(15 DOWNTO 0) := hdr_arr(4)(63 DOWNTO 48); + RETURN v_hdr; + END; + + FUNCTION func_network_total_header_no_align_extract_arp(hdr_arr : t_network_total_header_32b_arr) RETURN t_network_arp_packet IS + VARIABLE v_arp : t_network_arp_packet; + BEGIN + v_arp.htype := hdr_arr(3)(15 DOWNTO 0); + v_arp.ptype := hdr_arr(4)(31 DOWNTO 16); + v_arp.hlen := hdr_arr(4)(15 DOWNTO 8); + v_arp.plen := hdr_arr(4)( 7 DOWNTO 0); + v_arp.oper := hdr_arr(5)(31 DOWNTO 16); + v_arp.sha(47 DOWNTO 32) := hdr_arr(5)(15 DOWNTO 0); + v_arp.sha(31 DOWNTO 0) := hdr_arr(6); + v_arp.spa := hdr_arr(7); + v_arp.tha(47 DOWNTO 16) := hdr_arr(8); + v_arp.tha(15 DOWNTO 0) := hdr_arr(9)(31 DOWNTO 16); + v_arp.tpa(31 DOWNTO 16) := hdr_arr(9)(15 DOWNTO 0); + v_arp.tpa(15 DOWNTO 0) := hdr_arr(9)(31 DOWNTO 16); + RETURN v_arp; + END; + + FUNCTION func_network_total_header_no_align_extract_arp(hdr_arr : t_network_total_header_64b_arr) RETURN t_network_arp_packet IS + VARIABLE v_arp : t_network_arp_packet; + BEGIN + v_arp.htype := hdr_arr(1)(15 DOWNTO 0); + v_arp.ptype := hdr_arr(2)(63 DOWNTO 48); + v_arp.hlen := hdr_arr(2)(47 DOWNTO 40); + v_arp.plen := hdr_arr(2)(39 DOWNTO 32); + v_arp.oper := hdr_arr(2)(31 DOWNTO 16); + v_arp.sha(47 DOWNTO 32) := hdr_arr(2)(15 DOWNTO 0); + v_arp.sha(31 DOWNTO 0) := hdr_arr(3)(63 DOWNTO 32); + v_arp.spa := hdr_arr(3)(31 DOWNTO 0); + v_arp.tha := hdr_arr(4)(63 DOWNTO 16); + v_arp.tpa(31 DOWNTO 16) := hdr_arr(4)(15 DOWNTO 0); + v_arp.tpa(15 DOWNTO 0) := hdr_arr(5)(63 DOWNTO 48); + RETURN v_arp; + END; + + FUNCTION func_network_total_header_no_align_extract_icmp(hdr_arr : t_network_total_header_32b_arr) RETURN t_network_icmp_header IS + VARIABLE v_hdr : t_network_icmp_header; + BEGIN + v_hdr.msg_type := hdr_arr(8)(15 DOWNTO 8); + v_hdr.code := hdr_arr(8)( 7 DOWNTO 0); + v_hdr.checksum := hdr_arr(9)(31 DOWNTO 16); + v_hdr.id := hdr_arr(9)(15 DOWNTO 0); + v_hdr.sequence := hdr_arr(10)(31 DOWNTO 16); + RETURN v_hdr; + END; + + FUNCTION func_network_total_header_no_align_extract_icmp(hdr_arr : t_network_total_header_64b_arr) RETURN t_network_icmp_header IS + VARIABLE v_hdr : t_network_icmp_header; + BEGIN + v_hdr.msg_type := hdr_arr(4)(47 DOWNTO 40); + v_hdr.code := hdr_arr(4)(39 DOWNTO 32); + v_hdr.checksum := hdr_arr(4)(31 DOWNTO 16); + v_hdr.id := hdr_arr(4)(15 DOWNTO 0); + v_hdr.sequence := hdr_arr(5)(63 DOWNTO 48); + RETURN v_hdr; + END; + + FUNCTION func_network_total_header_no_align_extract_udp(hdr_arr : t_network_total_header_32b_arr) RETURN t_network_udp_header IS + VARIABLE v_hdr : t_network_udp_header; + BEGIN + v_hdr.src_port := hdr_arr(8)(15 DOWNTO 0); + v_hdr.dst_port := hdr_arr(9)(31 DOWNTO 16); + v_hdr.total_length := hdr_arr(9)(15 DOWNTO 0); + v_hdr.checksum := hdr_arr(10)(31 DOWNTO 16); + RETURN v_hdr; + END; + + FUNCTION func_network_total_header_no_align_extract_udp(hdr_arr : t_network_total_header_64b_arr) RETURN t_network_udp_header IS + VARIABLE v_hdr : t_network_udp_header; + BEGIN + v_hdr.src_port := hdr_arr(4)(47 DOWNTO 32); + v_hdr.dst_port := hdr_arr(4)(31 DOWNTO 16); + v_hdr.total_length := hdr_arr(4)(15 DOWNTO 0); + v_hdr.checksum := hdr_arr(5)(63 DOWNTO 48); + RETURN v_hdr; + END; -- Construct the total header array from the individual header records FUNCTION func_network_total_header_construct_eth( eth : t_network_eth_header) RETURN t_network_total_header_32b_arr IS @@ -712,5 +883,174 @@ PACKAGE BODY common_network_total_header_pkg IS v_response(5)(15 DOWNTO 0) := TO_UVEC(0, 16); RETURN v_response; END; + + + + -- Construct the response headers for headers without word align padding + FUNCTION func_network_total_header_no_align_response_eth(eth_arr : t_network_total_header_32b_arr; + mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_32b_arr IS + VARIABLE v_response : t_network_total_header_32b_arr; + BEGIN + -- Default + v_response := eth_arr; + -- ETH + -- . use input src mac for dst mac + v_response(0) := eth_arr(1)(15 DOWNTO 0) & eth_arr(2)(31 DOWNTO 16); + v_response(1)(31 DOWNTO 16) := eth_arr(2)(15 DOWNTO 0); + -- . force eth src mac to this node mac address (because the input dst_mac can be via eth broadcast mac) + v_response(1)(15 DOWNTO 0) := mac_addr(47 DOWNTO 32); + v_response(2) := mac_addr(31 DOWNTO 0); + RETURN v_response; + END; + + FUNCTION func_network_total_header_no_align_response_eth(eth_arr : t_network_total_header_64b_arr; + mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_64b_arr IS + VARIABLE v_response : t_network_total_header_64b_arr; + BEGIN + -- Default + v_response := eth_arr; + -- ETH + -- . use input src mac for dst mac + v_response(0)(63 DOWNTO 16) := eth_arr(0)(15 DOWNTO 0) & eth_arr(1)(63 DOWNTO 32); + -- . force eth src mac to this node mac address (because the input dst_mac can be via eth broadcast mac) + v_response(0)(15 DOWNTO 0) := mac_addr(47 DOWNTO 32); + v_response(1)(63 DOWNTO 32) := mac_addr(31 DOWNTO 0); + RETURN v_response; + END; + + FUNCTION func_network_total_header_no_align_response_arp(arp_arr : t_network_total_header_32b_arr; + mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0); + ip_addr : STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_32b_arr IS + VARIABLE v_response : t_network_total_header_32b_arr; + BEGIN + -- ETH + v_response := func_network_total_header_no_align_response_eth(arp_arr, mac_addr); + -- ARP + -- . force operation arp reply + v_response(5)(15 DOWNTO 0) := TO_UVEC(c_network_arp_oper_reply, 16); + -- . force sha to this node mac address + v_response(6) := mac_addr(47 DOWNTO 16); + v_response(7)(31 DOWNTO 16) := mac_addr(15 DOWNTO 0); + -- . force spa to this node ip address + v_response(7)(15 DOWNTO 0) := ip_addr(31 DOWNTO 16); + v_response(8)(31 DOWNTO 16) := ip_addr(15 DOWNTO 0); + -- . use input sha for tha + v_response(8)(15 DOWNTO 0) := arp_arr(6)(31 DOWNTO 16); + v_response(9) := arp_arr(6)(15 DOWNTO 0) & arp_arr(7)(31 DOWNTO 16); + -- . use input spa for tpa + v_response(10) := arp_arr(7)(15 DOWNTO 0) & arp_arr(8)(31 DOWNTO 16); + RETURN v_response; + END; + + FUNCTION func_network_total_header_no_align_response_arp(arp_arr : t_network_total_header_64b_arr; + mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0); + ip_addr : STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_64b_arr IS + VARIABLE v_response : t_network_total_header_64b_arr; + BEGIN + -- ETH + v_response := func_network_total_header_no_align_response_eth(arp_arr, mac_addr); + -- ARP + -- . force operation arp reply + v_response(3)(47 DOWNTO 32) := TO_UVEC(c_network_arp_oper_reply, 16); + -- . force sha to this node mac address + v_response(3)(31 DOWNTO 0) := mac_addr(47 DOWNTO 16); + v_response(4)(63 DOWNTO 48) := mac_addr(15 DOWNTO 0); + -- . force spa to this node ip address + v_response(4)(47 DOWNTO 16) := ip_addr(31 DOWNTO 0); + -- . use input sha for tha + v_response(4)(15 DOWNTO 0) := arp_arr(3)(31 DOWNTO 16); + v_response(5)(63 DOWNTO 32) := arp_arr(3)(15 DOWNTO 0) & arp_arr(4)(63 DOWNTO 48); + -- . use input spa for tpa + v_response(5)(31 DOWNTO 0) := arp_arr(4)(47 DOWNTO 16); + RETURN v_response; + END; + + FUNCTION func_network_total_header_no_align_response_ip(ip_arr : t_network_total_header_32b_arr; + mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_32b_arr IS + VARIABLE v_response : t_network_total_header_32b_arr; + BEGIN + -- ETH + v_response := func_network_total_header_no_align_response_eth(ip_arr, mac_addr); + -- IP + -- . force ip header checksum to 0 + v_response(6)(31 DOWNTO 16) := TO_UVEC(0, 16); + -- . swap ip dst_addr and ip src_addr + v_response(6)(15 DOWNTO 0) := ip_arr(7)(15 DOWNTO 0); + v_response(7)(31 DOWNTO 16) := ip_arr(8)(31 DOWNTO 16); + v_response(7)(15 DOWNTO 0) := ip_arr(6)(15 DOWNTO 0); + v_response(8)(31 DOWNTO 16) := ip_arr(7)(31 DOWNTO 16); + RETURN v_response; + END; + + FUNCTION func_network_total_header_no_align_response_ip(ip_arr : t_network_total_header_64b_arr; + mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_64b_arr IS + VARIABLE v_response : t_network_total_header_64b_arr; + BEGIN + -- ETH + v_response := func_network_total_header_no_align_response_eth(ip_arr, mac_addr); + -- IP + -- . force ip header checksum to 0 + v_response(3)(63 DOWNTO 48) := TO_UVEC(0, 16); + -- . swap ip dst_addr and ip src_addr + v_response(3)(47 DOWNTO 16) := ip_arr(3)(15 DOWNTO 0) & ip_arr(4)(63 DOWNTO 48); + v_response(3)(15 DOWNTO 0) := ip_arr(3)(47 DOWNTO 32); + v_response(4)(63 DOWNTO 48) := ip_arr(3)(31 DOWNTO 16); + RETURN v_response; + END; + + FUNCTION func_network_total_header_no_align_response_icmp(icmp_arr : t_network_total_header_32b_arr; + mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_32b_arr IS + VARIABLE v_response : t_network_total_header_32b_arr; + BEGIN + -- ETH, IP + v_response := func_network_total_header_no_align_response_ip(icmp_arr, mac_addr); + -- ICMP : force type to icmp reply + v_response(8)(15 DOWNTO 8) := TO_UVEC(c_network_icmp_msg_type_reply, 8); + -- ICMP : force icmp checksum to 0 + v_response(9)(31 DOWNTO 16) := TO_UVEC(0, 16); + RETURN v_response; + END; + + FUNCTION func_network_total_header_no_align_response_icmp(icmp_arr : t_network_total_header_64b_arr; + mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_64b_arr IS + VARIABLE v_response : t_network_total_header_64b_arr; + BEGIN + -- ETH, IP + v_response := func_network_total_header_no_align_response_ip(icmp_arr, mac_addr); + -- ICMP : force type to icmp reply + v_response(4)(47 DOWNTO 40) := TO_UVEC(c_network_icmp_msg_type_reply, 8); + -- ICMP : force icmp checksum to 0 + v_response(4)(31 DOWNTO 16) := TO_UVEC(0, 16); + RETURN v_response; + END; + + FUNCTION func_network_total_header_no_align_response_udp(udp_arr : t_network_total_header_32b_arr; + mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_32b_arr IS + VARIABLE v_response : t_network_total_header_32b_arr; + BEGIN + -- ETH, IP + v_response := func_network_total_header_no_align_response_ip(udp_arr, mac_addr); + -- UDP : swap udp dst port and udp src port + v_response(9) := udp_arr(9)(15 DOWNTO 0) & udp_arr(9)(31 DOWNTO 16); + -- UDP : force udp checksum to 0 + v_response(10)(15 DOWNTO 0) := TO_UVEC(0, 16); + RETURN v_response; + END; + + FUNCTION func_network_total_header_no_align_response_udp(udp_arr : t_network_total_header_64b_arr; + mac_addr : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0)) RETURN t_network_total_header_64b_arr IS + VARIABLE v_response : t_network_total_header_64b_arr; + BEGIN + -- ETH, IP + v_response := func_network_total_header_no_align_response_ip(udp_arr, mac_addr); + -- UDP : swap udp dst port and udp src port + v_response(5)(63 DOWNTO 32) := udp_arr(5)(47 DOWNTO 32) & udp_arr(5)(63 DOWNTO 48); + -- UDP : force udp checksum to 0 + v_response(5)(15 DOWNTO 0) := TO_UVEC(0, 16); + RETURN v_response; + END; + + + END common_network_total_header_pkg; diff --git a/libraries/base/dp/hdllib.cfg b/libraries/base/dp/hdllib.cfg index 864bb29d1acdfba549ed7fafb99a0c5a7b027f47..49811810201ec2f9fdc82d583e57fe3355bda0ec 100644 --- a/libraries/base/dp/hdllib.cfg +++ b/libraries/base/dp/hdllib.cfg @@ -128,6 +128,7 @@ synth_files = src/vhdl/dp_field_blk.vhd src/vhdl/dp_concat_field_blk.vhd src/vhdl/dp_offload_tx.vhd + src/vhdl/dp_offload_tx_v3.vhd src/vhdl/dp_offload_rx_filter.vhd src/vhdl/dp_offload_rx_filter_mm.vhd src/vhdl/dp_offload_rx.vhd @@ -289,6 +290,7 @@ test_bench_files = tb/vhdl/tb_tb_dp_xonoff.vhd tb/vhdl/tb_tb_tb_dp_backpressure.vhd + tb/vhdl/tb_dp_offload_tx_v3.vhd tb/vhdl/tb_dp_offload_rx_filter.vhd regression_test_vhdl = diff --git a/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd b/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd index c8e3d4e667ff1a49202863cf048f982bb954f2f3..47427a6d14f68477f41b1c7e7407a1183427be71 100644 --- a/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd +++ b/libraries/base/dp/src/vhdl/dp_fifo_fill_eop.vhd @@ -1,36 +1,38 @@ --------------------------------------------------------------------------------- +------------------------------------------------------------------------------- -- --- Copyright (C) 2019 +-- Copyright 2020 -- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> -- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. -- --- This program is free software: you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation, either version 3 of the License, or --- (at your option) any later version. --- --- This program is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- GNU General Public License for more details. --- --- You should have received a copy of the GNU General Public License --- along with this program. If not, see <http://www.gnu.org/licenses/>. --- --------------------------------------------------------------------------------- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Author: R. van der Walle -- Purpose: -- The FIFO starts outputting data when the output is ready and it has been -- filled with more than g_fifo_fill words or an eop signal has been received. --- Given a fixed frame length, this is useful when the in_val is throttled while --- the out_val should not be inactive valid between out_sop to out_eop. --- This is necessary for frame transport over a PHY link without separate data --- valid signal. +-- This is useful when the in_val is throttled while the out_val should not be +-- inactive valid between out_sop to out_eop. This is necessary for frame +-- transport over a PHY link without separate data valid signal. -- Description: -- Modified version of dp_fifo_fill_core. In addition to a frame being available -- after the fifo has been filled sufficiently, a frame is also available when -- the in_eop has been received earlier than the specified g_fifo_fill. For -- more details, please consult the description of dp_fill_fifo_core. +------------------------------------------------------------------------------- LIBRARY IEEE, common_lib, technology_lib; USE IEEE.std_logic_1164.ALL; @@ -82,7 +84,6 @@ ENTITY dp_fifo_fill_eop IS ); END dp_fifo_fill_eop; - ARCHITECTURE rtl OF dp_fifo_fill_eop IS CONSTANT c_fifo_rl : NATURAL := sel_a_b(g_fifo_fill=0, 1, g_fifo_rl); @@ -99,6 +100,8 @@ ARCHITECTURE rtl OF dp_fifo_fill_eop IS CONSTANT s_fill : STD_LOGIC_VECTOR(1 DOWNTO 0) := "01"; CONSTANT s_output : STD_LOGIC_VECTOR(1 DOWNTO 0) := "10"; CONSTANT s_xoff : STD_LOGIC_VECTOR(1 DOWNTO 0) := "11"; + + CONSTANT c_nof_spulse : NATURAL := 3; SIGNAL state : STD_LOGIC_VECTOR(1 DOWNTO 0); -- t_state SIGNAL nxt_state : STD_LOGIC_VECTOR(1 DOWNTO 0); -- t_state @@ -121,7 +124,12 @@ ARCHITECTURE rtl OF dp_fifo_fill_eop IS SIGNAL pend_src_out : t_dp_sosi; SIGNAL received_eop : BOOLEAN := FALSE; - SIGNAL nxt_received_eop : BOOLEAN := FALSE; + SIGNAL nxt_received_eop : BOOLEAN := FALSE; + SIGNAL expecting_eop : BOOLEAN := FALSE; + SIGNAL nxt_expecting_eop : BOOLEAN := FALSE; + SIGNAL common_spulse_clken : STD_LOGIC_VECTOR(c_nof_spulse DOWNTO 0) := (OTHERS => '1'); + SIGNAL common_spulse_out_pulse : STD_LOGIC_VECTOR(c_nof_spulse-1 DOWNTO 0); + SIGNAL common_spulse_busy : STD_LOGIC_VECTOR(c_nof_spulse-1 DOWNTO 0); SIGNAL crossed_domain_snk_in_eop : STD_LOGIC := '0'; BEGIN @@ -136,7 +144,7 @@ BEGIN rd_fill_ctrl <= rd_fill_32b(c_fifo_size_w-1 DOWNTO 0); gen_dp_fifo_sc : IF g_use_dual_clock=FALSE GENERATE - crossed_domain_snk_in_eop <= snk_in.eop; + crossed_domain_snk_in_eop <= snk_in.eop; -- No need to transfer eop across clock domains u_dp_fifo_sc : ENTITY work.dp_fifo_sc GENERIC MAP ( g_technology => g_technology, @@ -175,15 +183,22 @@ BEGIN END GENERATE; gen_dp_fifo_dc : IF g_use_dual_clock=TRUE GENERATE - u_common_spulse : ENTITY common_lib.common_spulse - PORT MAP ( - in_rst => wr_rst, - in_clk => wr_clk, - in_pulse => snk_in.eop, - out_rst => rd_rst, - out_clk => rd_clk, - out_pulse => crossed_domain_snk_in_eop - ); + -- Transfer eop across clock domain + crossed_domain_snk_in_eop <= vector_or(common_spulse_out_pulse); + gen_spulse : FOR I IN 0 TO c_nof_spulse-1 GENERATE + common_spulse_clken(I+1) <= vector_and(common_spulse_busy(I DOWNTO 0)); + u_common_spulse : ENTITY common_lib.common_spulse + PORT MAP ( + in_rst => wr_rst, + in_clk => wr_clk, + in_clken => common_spulse_clken(I), + in_pulse => snk_in.eop, + in_busy => common_spulse_busy(I), + out_rst => rd_rst, + out_clk => rd_clk, + out_pulse => common_spulse_out_pulse(I) + ); + END GENERATE; u_dp_fifo_dc : ENTITY work.dp_fifo_dc GENERIC MAP ( @@ -239,13 +254,19 @@ BEGIN state <= s_idle; i_src_out <= c_dp_sosi_rst; received_eop <= FALSE; + expecting_eop <= FALSE; ELSIF rising_edge(rd_clk) THEN xon_reg <= nxt_xon_reg; state <= nxt_state; i_src_out <= nxt_src_out; IF crossed_domain_snk_in_eop = '1' THEN - received_eop <= TRUE; + IF expecting_eop THEN + expecting_eop <= FALSE; + ELSE + received_eop <= TRUE; + END IF; ELSE + expecting_eop <= nxt_expecting_eop; received_eop <= nxt_received_eop; END IF; END IF; @@ -254,10 +275,11 @@ BEGIN nxt_xon_reg <= src_in.xon; -- register xon to easy timing closure gen_rl_0 : IF g_fifo_rl=0 GENERATE - p_state : PROCESS(state, rd_sosi, src_in, xon_reg, rd_fifo_usedw, rd_fill_ctrl, received_eop) + p_state : PROCESS(state, rd_sosi, src_in, xon_reg, rd_fifo_usedw, rd_fill_ctrl, received_eop, expecting_eop) BEGIN nxt_state <= state; nxt_received_eop <= received_eop; + nxt_expecting_eop <= expecting_eop; rd_siso <= src_in; -- default acknowledge (RL=1) this input when output is ready -- The output register stage increase RL=0 to 1, so it matches RL = 1 for src_in.ready @@ -291,8 +313,12 @@ BEGIN -- if the output is ready, then start outputting the frame IF src_in.ready='1' THEN nxt_src_out <= rd_sosi; -- output sop that is still at FIFO output (RL=0) - nxt_received_eop <= FALSE; nxt_state <= s_output; + IF received_eop THEN + nxt_received_eop <= FALSE; + ELSE + nxt_expecting_eop <= TRUE; + END IF; END IF; END IF; END IF; @@ -335,10 +361,11 @@ BEGIN src_out_reg => i_src_out ); - p_state : PROCESS(state, src_in, xon_reg, pend_src_out, rd_fifo_usedw, rd_fill_ctrl, received_eop) + p_state : PROCESS(state, src_in, xon_reg, pend_src_out, rd_fifo_usedw, rd_fill_ctrl, received_eop, expecting_eop) BEGIN nxt_state <= state; nxt_received_eop <= received_eop; + nxt_expecting_eop <= expecting_eop; hold_src_in <= src_in; -- default request (RL=1) new input when output is ready @@ -373,8 +400,12 @@ BEGIN -- if the output is ready, then start outputting the input frame IF src_in.ready='1' THEN nxt_src_out <= pend_src_out; -- output sop that is still pending in dp_hold_input - nxt_received_eop <= FALSE; nxt_state <= s_output; + IF received_eop THEN + nxt_received_eop <= FALSE; + ELSE + nxt_expecting_eop <= TRUE; + END IF; END IF; END IF; END IF; diff --git a/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd b/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd new file mode 100644 index 0000000000000000000000000000000000000000..e841015d5418e980fad3d84ca0c347f4df7170f8 --- /dev/null +++ b/libraries/base/dp/src/vhdl/dp_offload_tx_v3.vhd @@ -0,0 +1,232 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2017 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +-- Purpose: +-- . Concatenate a user-defined header to a DP frame e.g. to create an Ethernet frame +-- Description: +-- . The header contents can be controlled dynamically by data path or MM control (selected by g_hdr_field_sel) +-- . The header and data can be concatened at symbol level. The g_symbol_w defines the +-- resolution of the empty field. The g_data_w must be an integer multiple of the +-- g_symbol_w. If the empty field is not used or if the empty field is always 0 then +-- set g_symbol_w = g_data_w. +-- . For example to concat header and data for an Ethernet frame use: +-- - g_data_w = 32 (1GbE) or 64 (10GbE) +-- - g_symbol_w = c_byte_w = 8 if either the header or the data can have an +-- non-zero empty field, so when they are not a multiple of 4 bytes +-- (= 32b) or 8 bytes (= 64b). +-- g_symbol_w = g_data_w if the empty field is always 0, so the number of bits in +-- the header and data are an integer number of g_data_w. + + +LIBRARY IEEE, common_lib, technology_lib, mm_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE work.dp_stream_pkg.ALL; +USE common_lib.common_field_pkg.ALL; +USE technology_lib.technology_select_pkg.ALL; + +ENTITY dp_offload_tx_v3 IS + GENERIC ( + g_nof_streams : NATURAL; + g_data_w : NATURAL; + g_symbol_w : NATURAL; + g_hdr_field_arr : t_common_field_arr; -- User defined header fields + g_hdr_field_sel : STD_LOGIC_VECTOR; -- For each header field, select the source: 0=data path, 1=MM controlled + g_pipeline_ready : BOOLEAN := FALSE + ); + PORT ( + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + + dp_rst : IN STD_LOGIC; + dp_clk : IN STD_LOGIC; + + reg_hdr_dat_mosi : IN t_mem_mosi := c_mem_mosi_rst; + reg_hdr_dat_miso : OUT t_mem_miso; + + snk_in_arr : IN t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + snk_out_arr : OUT t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); + + src_out_arr : OUT t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + src_in_arr : IN t_dp_siso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy); + + hdr_fields_in_arr : IN t_slv_1024_arr(g_nof_streams-1 DOWNTO 0); -- hdr_fields_in_arr(i) is considered valid @ snk_in_arr(i).sop + hdr_fields_out_arr : OUT t_slv_1024_arr(g_nof_streams-1 DOWNTO 0) + ); +END dp_offload_tx_v3; + + +ARCHITECTURE str OF dp_offload_tx_v3 IS + + CONSTANT c_dp_field_blk_snk_data_w : NATURAL := field_slv_out_len(field_arr_set_mode(g_hdr_field_arr , "RW")); + CONSTANT c_dp_field_blk_src_data_w : NATURAL := g_data_w; + + SIGNAL dbg_c_dp_field_blk_snk_data_w : NATURAL := c_dp_field_blk_snk_data_w; + SIGNAL dbg_c_dp_field_blk_src_data_w : NATURAL := c_dp_field_blk_src_data_w; + + SIGNAL dp_field_blk_snk_in_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL dp_field_blk_snk_out_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); + + SIGNAL dp_field_blk_src_out_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL dp_field_blk_src_in_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); + + SIGNAL dp_concat_snk_in_2arr : t_dp_sosi_2arr_2(g_nof_streams-1 DOWNTO 0); + SIGNAL dp_concat_snk_out_2arr : t_dp_siso_2arr_2(g_nof_streams-1 DOWNTO 0); + + SIGNAL reg_hdr_dat_mosi_arr : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL reg_hdr_dat_miso_arr : t_mem_miso_arr(g_nof_streams-1 DOWNTO 0); + + SIGNAL mm_fields_slv_out_arr : t_slv_1024_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL field_override_arr : STD_LOGIC_VECTOR(g_hdr_field_arr'RANGE) := g_hdr_field_sel; --1 override bit per field + + +BEGIN + + ASSERT c_dp_field_blk_snk_data_w <= c_dp_stream_data_w REPORT "Number of header bits must fit in t_dp_sosi data field." SEVERITY FAILURE; + --------------------------------------------------------------------------------------- + -- Create header block & concatenate header to offload stream. + --------------------------------------------------------------------------------------- + p_wire_valid : PROCESS(snk_in_arr, hdr_fields_in_arr) + BEGIN + FOR i IN 0 TO g_nof_streams-1 LOOP + -- default pass on the other snk_in_arr fields as well, especially the sync, bsn and channel can + -- be useful to preserve for the packetized output, even though only the sosi.data of the + -- packetized output will get transmitted. + dp_field_blk_snk_in_arr(i) <= snk_in_arr(i); + -- Prepare packet header as a data block with only one data word, so valid = sop = eop. If + -- c_dp_field_blk_snk_data_w > c_dp_field_blk_src_data_w then dp_repack_data in dp_field_blk will + -- repack this data word into a multi word header block, else dp_field_blk will pass on the + -- dp_field_blk_snk_in_arr as a single word header block. + dp_field_blk_snk_in_arr(i).data <= RESIZE_DP_DATA(hdr_fields_in_arr(i)(field_slv_len(g_hdr_field_arr)-1 DOWNTO 0)); + dp_field_blk_snk_in_arr(i).valid <= snk_in_arr(i).sop; + dp_field_blk_snk_in_arr(i).sop <= snk_in_arr(i).sop; -- necessary for single word header block + dp_field_blk_snk_in_arr(i).eop <= snk_in_arr(i).sop; -- necessary for single word header block + END LOOP; + END PROCESS; + + gen_dp_field_blk : FOR i IN 0 TO g_nof_streams-1 GENERATE + + -- Both dp_concat inputs must be ready. One of the inputs toggles ready via dp_field_blk. + snk_out_arr(i).ready <= dp_field_blk_snk_out_arr(i).ready AND dp_concat_snk_out_2arr(i)(0).ready; + snk_out_arr(i).xon <= src_in_arr(i).xon; + + -- Wire hdr_fields_out_arr + -- MM override bits determine source for each field + gen_field_wires: FOR j IN g_hdr_field_arr'RANGE GENERATE + hdr_fields_out_arr(i)(field_hi(g_hdr_field_arr, j) DOWNTO field_lo(g_hdr_field_arr, j)) <= mm_fields_slv_out_arr(i)(field_hi(g_hdr_field_arr, j) DOWNTO field_lo(g_hdr_field_arr, j)) + WHEN field_override_arr(j) = '1' ELSE + hdr_fields_in_arr(i)(field_hi(g_hdr_field_arr, j) DOWNTO field_lo(g_hdr_field_arr, j)); + END GENERATE; + + --------------------------------------------------------------------------------------- + -- mm_fields for MM access to each field + --------------------------------------------------------------------------------------- + u_mm_fields_slv: ENTITY mm_lib.mm_fields + GENERIC MAP( + g_field_arr => field_arr_set_mode(g_hdr_field_arr , "RW") + ) + PORT MAP ( + mm_clk => mm_clk, + mm_rst => mm_rst, + + mm_mosi => reg_hdr_dat_mosi_arr(i), + mm_miso => OPEN, -- Not used + + slv_clk => dp_clk, + slv_rst => dp_rst, + + slv_out => mm_fields_slv_out_arr(i)(field_slv_len(g_hdr_field_arr)-1 DOWNTO 0) + ); + + + -- Create multi-cycle header block from single-cycle wide header SLV + u_dp_field_blk : ENTITY work.dp_field_blk + GENERIC MAP ( + g_field_arr => field_arr_set_mode(g_hdr_field_arr , "RW"), + g_field_sel => g_hdr_field_sel, + g_snk_data_w => c_dp_field_blk_snk_data_w, + g_src_data_w => c_dp_field_blk_src_data_w, + g_in_symbol_w => g_symbol_w, + g_out_symbol_w => g_symbol_w, + g_pipeline_ready => g_pipeline_ready + ) + PORT MAP ( + dp_clk => dp_clk, + dp_rst => dp_rst, + + mm_clk => mm_clk, + mm_rst => mm_rst, + + snk_in => dp_field_blk_snk_in_arr(i), + snk_out => dp_field_blk_snk_out_arr(i), + + src_out => dp_field_blk_src_out_arr(i), + src_in => dp_field_blk_src_in_arr(i), + + reg_slv_mosi => reg_hdr_dat_mosi_arr(i), + reg_slv_miso => reg_hdr_dat_miso_arr(i) + ); + + dp_field_blk_src_in_arr(i) <= dp_concat_snk_out_2arr(i)(1); + + END GENERATE; + + -- Prepend the header block to the input block + gen_dp_concat : FOR i IN 0 TO g_nof_streams-1 GENERATE + + dp_concat_snk_in_2arr(i)(0) <= snk_in_arr(i); + dp_concat_snk_in_2arr(i)(1) <= dp_field_blk_src_out_arr(i); + + u_dp_concat : ENTITY work.dp_concat + GENERIC MAP ( + g_data_w => g_data_w, + g_symbol_w => g_symbol_w + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + + snk_out_arr => dp_concat_snk_out_2arr(i), + snk_in_arr => dp_concat_snk_in_2arr(i), + + src_in => src_in_arr(i), + src_out => src_out_arr(i) + ); + END GENERATE; + + --------------------------------------------------------------------------------------- + -- MM control & monitoring + --------------------------------------------------------------------------------------- + u_common_mem_mux_hdr_dat : ENTITY common_lib.common_mem_mux + GENERIC MAP ( + g_nof_mosi => g_nof_streams, + g_mult_addr_w => ceil_log2(field_nof_words(g_hdr_field_arr, c_word_w)) + ) + PORT MAP ( + mosi => reg_hdr_dat_mosi, + miso => reg_hdr_dat_miso, + mosi_arr => reg_hdr_dat_mosi_arr, + miso_arr => reg_hdr_dat_miso_arr + ); + +END str; diff --git a/libraries/base/dp/tb/vhdl/tb_dp_fifo_fill_eop.vhd b/libraries/base/dp/tb/vhdl/tb_dp_fifo_fill_eop.vhd index a6dc8a1a3f9ecb805bd27cf984084b74ac31b1ab..b13ef2a3a54f8fb66878f9347c5d32a808c71717 100644 --- a/libraries/base/dp/tb/vhdl/tb_dp_fifo_fill_eop.vhd +++ b/libraries/base/dp/tb/vhdl/tb_dp_fifo_fill_eop.vhd @@ -1,25 +1,26 @@ ------------------------------------------------------------------------------- -- --- Copyright (C) 2010 +-- Copyright 2020 -- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> --- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> -- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands --- --- This program is free software: you can redistribute it and/or modify --- it under the terms of the GNU General Public License as published by --- the Free Software Foundation, either version 3 of the License, or --- (at your option) any later version. --- --- This program is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --- GNU General Public License for more details. --- --- You should have received a copy of the GNU General Public License --- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. -- ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +-- Author: R. van der Walle + -- Purpose: -- Test bench for dp_fifo_fill_eop -- Description: @@ -33,7 +34,8 @@ -- > run -all -- . signal tb_end will stop the simulation by stopping the clk -- . the tb is self checking --- +------------------------------------------------------------------------------- + LIBRARY IEEE, common_lib; USE IEEE.std_logic_1164.ALL; USE IEEE.numeric_std.ALL; diff --git a/libraries/base/dp/tb/vhdl/tb_dp_offload_tx_v3.vhd b/libraries/base/dp/tb/vhdl/tb_dp_offload_tx_v3.vhd new file mode 100644 index 0000000000000000000000000000000000000000..08566621228bb4e41e719517306f6497d1c6e96e --- /dev/null +++ b/libraries/base/dp/tb/vhdl/tb_dp_offload_tx_v3.vhd @@ -0,0 +1,436 @@ +------------------------------------------------------------------------------- +-- +-- Copyright (C) 2015 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +-- Purpose: +-- . Test bench for dp_offload_tx_v3 and dp_offload_rx +-- Description: +-- u_tx u_rx +-- ___________________ ___________________ +-- |dp_offload_tx_v3| |dp_offload_rx | +-- stimuli_src -->| |--->| |--> verify_snk +-- | in out | | | in out | +-- |___________________| | |___________________| +-- | +-- link_offload_sosi +-- Usage: +-- > as 10 +-- > run -all +-- + +LIBRARY IEEE, common_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_lfsr_sequences_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_field_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE work.dp_stream_pkg.ALL; +USE work.tb_dp_pkg.ALL; + + +ENTITY tb_dp_offload_tx_v3 IS + GENERIC ( + -- general + g_flow_control_stimuli : t_dp_flow_control_enum := e_pulse; -- always e_active, e_random or e_pulse flow control + g_flow_control_verify : t_dp_flow_control_enum := e_active; -- always e_active, e_random or e_pulse flow control + -- specific + g_data_w : NATURAL := 64; + g_nof_repeat : NATURAL := 100; + g_pkt_len : NATURAL := 240; + g_pkt_gap : NATURAL := 16 + ); +END tb_dp_offload_tx_v3; + + +ARCHITECTURE tb OF tb_dp_offload_tx_v3 IS + + CONSTANT c_mm_clk_period : TIME := 1 ns; + CONSTANT c_dp_clk_period : TIME := 5 ns; + + -- dp_stream_stimuli + CONSTANT c_stimuli_pulse_active : NATURAL := 3; + CONSTANT c_stimuli_pulse_period : NATURAL := 4; + + -- dp_stream_verify + CONSTANT c_verify_pulse_active : NATURAL := 1; + CONSTANT c_verify_pulse_period : NATURAL := 5; + + CONSTANT c_data_max : UNSIGNED(g_data_w-1 DOWNTO 0) := (OTHERS=>'1'); + CONSTANT c_dsp_max : UNSIGNED(g_data_w-1 DOWNTO 0) := (OTHERS=>'1'); + + --CONSTANT c_verify_snk_in_cnt_max : t_dp_sosi_unsigned := c_dp_sosi_unsigned_rst; -- default 0 is no wrap + CONSTANT c_verify_snk_in_cnt_max : t_dp_sosi_unsigned := TO_DP_SOSI_UNSIGNED('0', '0', '0', '0', c_data_max, c_dsp_max, c_dsp_max, c_unsigned_0, c_unsigned_0, c_unsigned_0, c_unsigned_0); + CONSTANT c_verify_snk_in_cnt_gap : t_dp_sosi_unsigned := c_dp_sosi_unsigned_ones; -- default only accept increment +1 + + CONSTANT c_expected_pkt_len : NATURAL := g_pkt_len; + CONSTANT c_sync_period : NATURAL := 5; + CONSTANT c_sync_offset : NATURAL := 2; + + CONSTANT c_hdr_len : NATURAL := 7; + CONSTANT c_wait_last_evt : NATURAL := 100 + g_nof_repeat * c_hdr_len; + + ----------------------------------------------------------------------------- + -- Tx offload + ----------------------------------------------------------------------------- + -- From apertif_udp_offload_pkg.vhd: + CONSTANT c_udp_offload_nof_hdr_fields : NATURAL := 3+12+4+3; -- 448b; 7 64b words + -- Notes: + -- . pre-calculated ip_header_checksum is valid only for UNB0, FN0 targeting IP 10.10.10.10 + -- . udp_total_length = 176 beamlets * 64b / 8b = 1408B + 14 DP bytes + 8 UDP bytes = 1430B + CONSTANT c_udp_offload_hdr_field_arr : t_common_field_arr(c_udp_offload_nof_hdr_fields-1 DOWNTO 0) := ( + ( field_name_pad("eth_dst_mac" ), "RW", 48, field_default(x"001B214368AC") ), + ( field_name_pad("eth_src_mac" ), "RW", 48, field_default(0) ), + ( field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), + ( field_name_pad("ip_version" ), "RW", 4, field_default(4) ), + ( field_name_pad("ip_header_length" ), "RW", 4, field_default(5) ), + ( field_name_pad("ip_services" ), "RW", 8, field_default(0) ), + ( field_name_pad("ip_total_length" ), "RW", 16, field_default(1450) ), + ( field_name_pad("ip_identification" ), "RW", 16, field_default(0) ), + ( field_name_pad("ip_flags" ), "RW", 3, field_default(2) ), + ( field_name_pad("ip_fragment_offset" ), "RW", 13, field_default(0) ), + ( field_name_pad("ip_time_to_live" ), "RW", 8, field_default(127) ), + ( field_name_pad("ip_protocol" ), "RW", 8, field_default(17) ), + ( field_name_pad("ip_header_checksum" ), "RW", 16, field_default(29928) ), + ( field_name_pad("ip_src_addr" ), "RW", 32, field_default(x"C0A80009") ), + ( field_name_pad("ip_dst_addr" ), "RW", 32, field_default(x"C0A80001") ), + ( field_name_pad("udp_src_port" ), "RW", 16, field_default(0) ), + ( field_name_pad("udp_dst_port" ), "RW", 16, field_default(0) ), + ( field_name_pad("udp_total_length" ), "RW", 16, field_default(1430) ), + ( field_name_pad("udp_checksum" ), "RW", 16, field_default(0) ), + ( field_name_pad("dp_reserved" ), "RW", 47, field_default(0) ), + ( field_name_pad("dp_sync" ), "RW", 1, field_default(0) ), + ( field_name_pad("dp_bsn" ), "RW", 64, field_default(0) ) ); + + -- From apertif_unb1_fn_beamformer_udp_offload.vhd: + -- Override ('1') only the Ethernet fields so we can use MM defaults there. + CONSTANT c_hdr_field_ovr_init : STD_LOGIC_VECTOR(c_udp_offload_nof_hdr_fields-1 DOWNTO 0) := "101"&"111111111111"&"1111"&"100"; + + CONSTANT c_NODE_ID : STD_LOGIC_VECTOR(7 DOWNTO 0) := TO_UVEC(0, 8); + + SIGNAL id_backplane : STD_LOGIC_VECTOR(c_byte_w-1 DOWNTO 0); + SIGNAL id_chip : STD_LOGIC_VECTOR(c_byte_w-1 DOWNTO 0); + + SIGNAL dp_fifo_sc_src_in : t_dp_siso := c_dp_siso_rdy; + SIGNAL dp_fifo_sc_src_out : t_dp_sosi; + + SIGNAL dp_offload_tx_snk_in_arr : t_dp_sosi_arr(0 DOWNTO 0); + SIGNAL dp_offload_tx_snk_out_arr : t_dp_siso_arr(0 DOWNTO 0); + + SIGNAL tx_hdr_fields_in_arr : t_slv_1024_arr(0 DOWNTO 0); + SIGNAL tx_hdr_fields_out_arr : t_slv_1024_arr(0 DOWNTO 0); + + SIGNAL reg_dp_offload_tx_hdr_dat_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL reg_dp_offload_tx_hdr_dat_miso : t_mem_miso; + + ----------------------------------------------------------------------------- + -- Link + ----------------------------------------------------------------------------- + + SIGNAL tx_offload_sosi_arr : t_dp_sosi_arr(0 DOWNTO 0); + SIGNAL tx_offload_siso_arr : t_dp_siso_arr(0 DOWNTO 0); + + SIGNAL link_offload_sosi_arr : t_dp_sosi_arr(0 DOWNTO 0); + SIGNAL link_offload_siso_arr : t_dp_siso_arr(0 DOWNTO 0); + + ----------------------------------------------------------------------------- + -- Rx offload + ----------------------------------------------------------------------------- + SIGNAL dp_offload_rx_src_out_arr : t_dp_sosi_arr(0 DOWNTO 0); + SIGNAL dp_offload_rx_src_in_arr : t_dp_siso_arr(0 DOWNTO 0); + + SIGNAL rx_hdr_fields_out_arr : t_slv_1024_arr(0 DOWNTO 0); + SIGNAL rx_hdr_fields_raw_arr : t_slv_1024_arr(0 DOWNTO 0); + + SIGNAL reg_dp_offload_rx_hdr_dat_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL reg_dp_offload_rx_hdr_dat_miso : t_mem_miso; + + ----------------------------------------------------------------------------- + -- Test + ----------------------------------------------------------------------------- + SIGNAL mm_clk : STD_LOGIC := '1'; + SIGNAL mm_rst : STD_LOGIC := '1'; + SIGNAL dp_clk : STD_LOGIC := '1'; + SIGNAL dp_rst : STD_LOGIC := '1'; + SIGNAL tb_end : STD_LOGIC := '0'; + + SIGNAL stimuli_src_in : t_dp_siso := c_dp_siso_rdy; + SIGNAL stimuli_src_out : t_dp_sosi; + SIGNAL stimuli_src_out_data : STD_LOGIC_VECTOR(g_data_w-1 DOWNTO 0); + + SIGNAL verify_snk_in_enable : t_dp_sosi_sl := c_dp_sosi_sl_rst; + SIGNAL last_snk_in : t_dp_sosi; + SIGNAL last_snk_in_evt : STD_LOGIC; + SIGNAL verify_last_snk_in_evt : t_dp_sosi_sl := c_dp_sosi_sl_rst; + + SIGNAL verify_snk_out : t_dp_siso := c_dp_siso_rdy; + SIGNAL verify_snk_in : t_dp_sosi; + SIGNAL verify_snk_in_data : STD_LOGIC_VECTOR(g_data_w-1 DOWNTO 0); + +BEGIN + + ------------------------------------------------------------------------------ + -- Clock & reset + ------------------------------------------------------------------------------ + mm_clk <= (NOT mm_clk) OR tb_end AFTER c_mm_clk_period/2; + mm_rst <= '1', '0' AFTER c_mm_clk_period*7; + dp_clk <= (NOT dp_clk) OR tb_end AFTER c_dp_clk_period/2; + dp_rst <= '1', '0' AFTER c_dp_clk_period*7; + + ------------------------------------------------------------------------------ + -- DATA GENERATION + ------------------------------------------------------------------------------ + + u_dp_stream_stimuli : ENTITY work.dp_stream_stimuli + GENERIC MAP ( + g_instance_nr => 0, -- only one stream so choose index 0 + -- flow control + g_random_w => 15, -- use different random width for stimuli and for verify to have different random sequences + g_pulse_active => c_stimuli_pulse_active, + g_pulse_period => c_stimuli_pulse_period, + g_flow_control => g_flow_control_stimuli, -- always active, random or pulse flow control + -- initializations + g_sync_period => c_sync_period, + g_sync_offset => c_sync_offset, + -- specific + g_in_dat_w => g_data_w, + g_nof_repeat => g_nof_repeat, + g_pkt_len => g_pkt_len, + g_pkt_gap => g_pkt_gap, + g_wait_last_evt => c_wait_last_evt + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + + -- Generate stimuli + src_in => stimuli_src_in, + src_out => stimuli_src_out, + + -- End of stimuli + last_snk_in => last_snk_in, -- expected verify_snk_in after end of stimuli + last_snk_in_evt => last_snk_in_evt, -- trigger verify to verify the last_snk_in + tb_end => tb_end -- signal end of tb as far as this dp_stream_stimuli is concerned + ); + + + ------------------------------------------------------------------------------ + -- DATA VERIFICATION + ------------------------------------------------------------------------------ + + -- Select fields that need to be verified + -- . during the test + verify_snk_in_enable.sync <= '1'; + verify_snk_in_enable.bsn <= '1'; + verify_snk_in_enable.data <= '1'; + verify_snk_in_enable.re <= '0'; + verify_snk_in_enable.im <= '0'; + verify_snk_in_enable.valid <= '1'; + verify_snk_in_enable.sop <= '1'; + verify_snk_in_enable.eop <= '1'; + verify_snk_in_enable.empty <= '0'; + verify_snk_in_enable.channel <= '0'; + verify_snk_in_enable.err <= '0'; + + -- . after the test + verify_last_snk_in_evt.sync <= last_snk_in_evt; + verify_last_snk_in_evt.bsn <= last_snk_in_evt; -- thanks to using rx_hdr_fields_raw_arr for bsn field + verify_last_snk_in_evt.data <= last_snk_in_evt; + verify_last_snk_in_evt.re <= '0'; + verify_last_snk_in_evt.im <= '0'; + verify_last_snk_in_evt.valid <= last_snk_in_evt; + verify_last_snk_in_evt.sop <= last_snk_in_evt; + verify_last_snk_in_evt.eop <= last_snk_in_evt; + verify_last_snk_in_evt.empty <= '0'; + verify_last_snk_in_evt.channel <= '0'; + verify_last_snk_in_evt.err <= '0'; + + u_dp_stream_verify : ENTITY work.dp_stream_verify + GENERIC MAP ( + g_instance_nr => 0, -- only one stream so choose index 0 + -- flow control + g_random_w => 14, -- use different random width for stimuli and for verify to have different random sequences + g_pulse_active => c_verify_pulse_active, + g_pulse_period => c_verify_pulse_period, + g_flow_control => g_flow_control_verify, -- always active, random or pulse flow control + -- initializations + g_sync_period => c_sync_period, + g_sync_offset => c_sync_offset, + g_snk_in_cnt_max => c_verify_snk_in_cnt_max, + g_snk_in_cnt_gap => c_verify_snk_in_cnt_gap, + -- specific + g_in_dat_w => g_data_w, + g_pkt_len => c_expected_pkt_len + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + + -- Verify data + snk_out => verify_snk_out, + snk_in => verify_snk_in, + + -- During stimuli + verify_snk_in_enable => verify_snk_in_enable, -- enable verify to verify that the verify_snk_in fields are incrementing + + -- End of stimuli + expected_snk_in => last_snk_in, -- expected verify_snk_in after end of stimuli + verify_expected_snk_in_evt => verify_last_snk_in_evt -- trigger verify to verify the last_snk_in + ); + + ------------------------------------------------------------------------------ + -- DUT offload Tx + ------------------------------------------------------------------------------ + stimuli_src_in <= c_dp_siso_rdy; + + -- Use FIFO to mimic apertif_unb1_fn_beamformer_udp_offload.vhd, without FIFO dp_stream_stimuli + -- would handle the back pressure + u_dp_fifo_sc : ENTITY work.dp_fifo_sc + GENERIC MAP ( + g_data_w => g_data_w, + g_bsn_w => 64, + g_use_sync => TRUE, + g_use_bsn => TRUE, + g_fifo_size => 1024 + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + + snk_out => OPEN, -- stimuli_src_in + snk_in => stimuli_src_out, + + src_in => dp_fifo_sc_src_in, + src_out => dp_fifo_sc_src_out + ); + + dp_offload_tx_snk_in_arr(0) <= dp_fifo_sc_src_out; + dp_fifo_sc_src_in <= dp_offload_tx_snk_out_arr(0); + + -- Extract the chip and backplane numbers from c_NODE_ID + id_backplane <= RESIZE_UVEC(c_NODE_ID(7 DOWNTO 3), c_byte_w); + id_chip <= RESIZE_UVEC(c_NODE_ID(2 DOWNTO 0), c_byte_w); + + -- Wire the hardwired header fields to DP signals and c_NODE_ID + tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "eth_src_mac" ) DOWNTO field_lo(c_udp_offload_hdr_field_arr, "eth_src_mac" )) <= x"00228608" & id_backplane & id_chip; + tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "udp_src_port") DOWNTO field_lo(c_udp_offload_hdr_field_arr, "udp_src_port" )) <= x"D0" & c_NODE_ID; + tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "udp_dst_port") DOWNTO field_lo(c_udp_offload_hdr_field_arr, "udp_dst_port" )) <= x"D0" & c_NODE_ID; + tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "ip_src_addr" ) DOWNTO field_lo(c_udp_offload_hdr_field_arr, "ip_src_addr" )) <= x"0A63" & id_backplane & INCR_UVEC(id_chip, 1); + + tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "dp_sync" ) DOWNTO field_lo(c_udp_offload_hdr_field_arr, "dp_sync" )) <= slv(dp_offload_tx_snk_in_arr(0).sync); + tx_hdr_fields_in_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "dp_bsn" ) DOWNTO field_lo(c_udp_offload_hdr_field_arr, "dp_bsn" )) <= dp_offload_tx_snk_in_arr(0).bsn(63 DOWNTO 0); + + u_tx : ENTITY work.dp_offload_tx_v3 + GENERIC MAP ( + g_nof_streams => 1, + g_data_w => g_data_w, + g_symbol_w => g_data_w, + g_hdr_field_arr => c_udp_offload_hdr_field_arr, + g_hdr_field_sel => c_hdr_field_ovr_init + ) + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + + dp_rst => dp_rst, + dp_clk => dp_clk, + + reg_hdr_dat_mosi => reg_dp_offload_tx_hdr_dat_mosi, + reg_hdr_dat_miso => reg_dp_offload_tx_hdr_dat_miso, + + snk_in_arr => dp_offload_tx_snk_in_arr, + snk_out_arr => dp_offload_tx_snk_out_arr, + + src_out_arr => tx_offload_sosi_arr, + src_in_arr => tx_offload_siso_arr, + + hdr_fields_in_arr => tx_hdr_fields_in_arr, + hdr_fields_out_arr => tx_hdr_fields_out_arr + ); + + ------------------------------------------------------------------------------ + -- Link + ------------------------------------------------------------------------------ + + p_link_offload : PROCESS(tx_offload_sosi_arr, link_offload_siso_arr) + BEGIN + -- Model active packet fields of tr_10GbE Rx sosi output interface + link_offload_sosi_arr(0) <= c_dp_sosi_rst; + link_offload_sosi_arr(0).data <= tx_offload_sosi_arr(0).data; + link_offload_sosi_arr(0).empty <= tx_offload_sosi_arr(0).empty; + link_offload_sosi_arr(0).valid <= tx_offload_sosi_arr(0).valid; + link_offload_sosi_arr(0).sop <= tx_offload_sosi_arr(0).sop; + link_offload_sosi_arr(0).eop <= tx_offload_sosi_arr(0).eop; + + tx_offload_siso_arr <= (OTHERS=>c_dp_siso_rdy); + END PROCESS; + + ------------------------------------------------------------------------------ + -- DUT offload Rx + ------------------------------------------------------------------------------ + + u_rx : ENTITY work.dp_offload_rx + GENERIC MAP ( + g_nof_streams => 1, + g_data_w => g_data_w, + g_hdr_field_arr => c_udp_offload_hdr_field_arr, + g_remove_crc => FALSE, + g_crc_nof_words => 0 + ) + PORT MAP ( + mm_rst => mm_rst, + mm_clk => mm_clk, + + dp_rst => dp_rst, + dp_clk => dp_clk, + + reg_hdr_dat_mosi => reg_dp_offload_rx_hdr_dat_mosi, + reg_hdr_dat_miso => reg_dp_offload_rx_hdr_dat_miso, + + snk_in_arr => link_offload_sosi_arr, + snk_out_arr => link_offload_siso_arr, + + src_out_arr => dp_offload_rx_src_out_arr, + src_in_arr => dp_offload_rx_src_in_arr, + + hdr_fields_out_arr => rx_hdr_fields_out_arr, + hdr_fields_raw_arr => rx_hdr_fields_raw_arr + ); + + p_restore_sync_bsn : PROCESS(dp_offload_rx_src_out_arr, rx_hdr_fields_out_arr) + BEGIN + verify_snk_in <= dp_offload_rx_src_out_arr(0); + verify_snk_in.sync <= sl(rx_hdr_fields_out_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "dp_sync") DOWNTO field_lo(c_udp_offload_hdr_field_arr, "dp_sync" ))); + verify_snk_in.bsn <= RESIZE_UVEC(rx_hdr_fields_raw_arr(0)(field_hi(c_udp_offload_hdr_field_arr, "dp_bsn" ) DOWNTO field_lo(c_udp_offload_hdr_field_arr, "dp_bsn" )), c_dp_stream_bsn_w); + END PROCESS; + + dp_offload_rx_src_in_arr <= (OTHERS=>c_dp_siso_rdy); + dp_offload_rx_src_in_arr(0) <= verify_snk_out; + + ------------------------------------------------------------------------------ + -- Auxiliary + ------------------------------------------------------------------------------ + + -- Map to slv to ease monitoring in wave window + stimuli_src_out_data <= stimuli_src_out.data(g_data_w-1 DOWNTO 0); + verify_snk_in_data <= verify_snk_in.data(g_data_w-1 DOWNTO 0); + +END tb; diff --git a/libraries/io/nw_10GbE/hdllib.cfg b/libraries/io/nw_10GbE/hdllib.cfg new file mode 100644 index 0000000000000000000000000000000000000000..51c46a705a0d9f85106860cc0590e7764976a39b --- /dev/null +++ b/libraries/io/nw_10GbE/hdllib.cfg @@ -0,0 +1,27 @@ +hdl_lib_name = nw_10GbE +hdl_library_clause_name = nw_10GbE_lib +hdl_lib_uses_synth = common dp technology tech_mac_10g tr_10GbE +hdl_lib_uses_sim = +hdl_lib_technology = + +synth_files = + src/vhdl/nw_arp_request.vhd + src/vhdl/nw_ping_response.vhd + src/vhdl/nw_10GbE.vhd + +test_bench_files = + tb/vhdl/tb_nw_10GbE.vhd + tb/vhdl/tb_tb_nw_10GbE.vhd + tb/vhdl/tb_nw_ping_response.vhd + tb/vhdl/tb_nw_arp_request.vhd + +#regression_test_vhdl = +# tb/vhdl/tb_nw_10GbE.vhd +# tb/vhdl/tb_tb_nw_10GbE.vhd + + +[modelsim_project_file] + + +[quartus_project_file] + diff --git a/libraries/io/nw_10GbE/src/vhdl/nw_10GbE.vhd b/libraries/io/nw_10GbE/src/vhdl/nw_10GbE.vhd new file mode 100644 index 0000000000000000000000000000000000000000..2df5755b77df0eb5972e90bcb37344756cd6b1a9 --- /dev/null +++ b/libraries/io/nw_10GbE/src/vhdl/nw_10GbE.vhd @@ -0,0 +1,291 @@ +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Author: R. van der Walle +-- Purpose: Adds basic networking capabilities to tr_10GbE by sending ARP request +-- packets on a predefined interval as well as respond to PING requests. +-- To avoid that the packet transmission will get a gap that will abort it. +-- The average DP data rate depends on dp_clk and on the DP data valid. +-- NOTE: When connected to a PC make sure you can handle backpressure for +-- a large amount of clock cycles (can be > 16k). This backpressure +-- is due to the possibility of receiving pause frames from the PC. +-- If your design cannot handle the backpressure from PC, you should +-- disable it on the PC side. This can be done with ethtool: +-- # ethtool -A ethX autoneg off rx off tx off +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib, technology_lib, tech_mac_10g_lib, tr_10GbE_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; +USE common_lib.common_interface_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_field_pkg.ALL; +USE technology_lib.technology_select_pkg.ALL; +USE technology_lib.technology_pkg.ALL; +USE tech_mac_10g_lib.tech_mac_10g_component_pkg.ALL; + +ENTITY nw_10GbE IS + GENERIC ( + g_technology : NATURAL := c_tech_select_default; + g_sim : BOOLEAN; + g_sim_level : NATURAL := 1; -- 0 = use IP; 1 = use fast serdes model + g_nof_macs : NATURAL; + g_direction : STRING := "TX_RX"; -- "TX_RX", "TX_ONLY", "RX_ONLY" + g_use_mdio : BOOLEAN := FALSE; + g_mdio_epcs_dis : BOOLEAN := FALSE; -- TRUE disables EPCS on init; e.g. to target a 10GbE card in PC that does not support it + g_tx_fifo_fill : NATURAL := 10; -- Release tx packet only when sufficiently data is available such that no data gaps are introduced. + g_tx_fifo_size : NATURAL := 256; -- 2 * 32b * 256 = 2 M9K (DP interface has 64b data, so at least 2 M9K needed) + g_rx_fifo_size : NATURAL := 256; -- 2 * 32b * 256 = 2 M9K (DP interface has 64b data, so at least 2 M9K needed) + g_word_alignment_padding : BOOLEAN := FALSE; + g_arp_period_s : NATURAL := 30; + g_ip_hdr_field_arr : t_common_field_arr + ); + PORT ( + -- Transceiver PLL reference clock + tr_ref_clk_644 : IN STD_LOGIC := '0'; -- 644.531250 MHz for 10GBASE-R + tr_ref_clk_312 : IN STD_LOGIC := '0'; -- 312.5 MHz for 10GBASE-R + tr_ref_clk_156 : IN STD_LOGIC := '0'; -- 156.25 MHz for 10GBASE-R or for XAUI + tr_ref_rst_156 : IN STD_LOGIC := '0'; -- for 10GBASE-R or for XAUI + + -- Calibration & reconfig clock + cal_rec_clk : IN STD_LOGIC := '0'; -- for XAUI; + + -- MM interface + mm_rst : IN STD_LOGIC; + mm_clk : IN STD_LOGIC; + + reg_mac_mosi : IN t_mem_mosi := c_mem_mosi_rst; + reg_mac_miso : OUT t_mem_miso; + + xaui_mosi : IN t_mem_mosi := c_mem_mosi_rst; + xaui_miso : OUT t_mem_miso; + + reg_eth10g_mosi : IN t_mem_mosi := c_mem_mosi_rst; -- ETH10G (link status register) + reg_eth10g_miso : OUT t_mem_miso; + + mdio_mosi_arr : IN t_mem_mosi_arr(g_nof_macs-1 DOWNTO 0) := (OTHERS=>c_mem_mosi_rst); + mdio_miso_arr : OUT t_mem_miso_arr(g_nof_macs-1 DOWNTO 0); + + reg_10gbase_r_24_mosi : IN t_mem_mosi := c_mem_mosi_rst; + reg_10gbase_r_24_miso : OUT t_mem_miso; + + -- DP interface + dp_rst : IN STD_LOGIC := '0'; + dp_clk : IN STD_LOGIC := '0'; + dp_pps : IN STD_LOGIC := '0'; + + snk_out_arr : OUT t_dp_siso_arr(g_nof_macs-1 DOWNTO 0); + snk_in_arr : IN t_dp_sosi_arr(g_nof_macs-1 DOWNTO 0) := (OTHERS=>c_dp_sosi_rst); + + src_in_arr : IN t_dp_siso_arr(g_nof_macs-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy); + src_out_arr : OUT t_dp_sosi_arr(g_nof_macs-1 DOWNTO 0); + + -- Serial XAUI IO + xaui_tx_arr : OUT t_xaui_arr(g_nof_macs-1 DOWNTO 0); + xaui_rx_arr : IN t_xaui_arr(g_nof_macs-1 DOWNTO 0) := (OTHERS=>(OTHERS=>'0')); + + -- Serial IO + serial_tx_arr : OUT STD_LOGIC_VECTOR(g_nof_macs-1 downto 0); + serial_rx_arr : IN STD_LOGIC_VECTOR(g_nof_macs-1 downto 0) := (OTHERS=>'0'); + + -- MDIO interface + mdio_rst : OUT STD_LOGIC; + mdio_mdc_arr : OUT STD_LOGIC_VECTOR(g_nof_macs-1 DOWNTO 0); + mdio_mdat_in_arr : IN STD_LOGIC_VECTOR(g_nof_macs-1 DOWNTO 0) := (OTHERS=>'0'); + mdio_mdat_oen_arr : OUT STD_LOGIC_VECTOR(g_nof_macs-1 DOWNTO 0); + + hdr_fields_in_arr : IN t_slv_1024_arr(g_nof_macs-1 DOWNTO 0) + ); +END nw_10GbE; + +ARCHITECTURE str OF nw_10GbE IS + + CONSTANT c_nof_mux_streams : NATURAL := 3; + + SIGNAL nw_arp_request_src_out_arr : t_dp_sosi_arr(g_nof_macs-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + SIGNAL nw_arp_request_src_in_arr : t_dp_siso_arr(g_nof_macs-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy); + + SIGNAL nw_ping_response_src_out_arr : t_dp_sosi_arr(g_nof_macs-1 DOWNTO 0) := (OTHERS => c_dp_sosi_rst); + SIGNAL nw_ping_response_src_in_arr : t_dp_siso_arr(g_nof_macs-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy); + + SIGNAL dp_mux_snk_in_2arr : t_dp_sosi_2arr_3(g_nof_macs-1 DOWNTO 0) := (OTHERS => (OTHERS => c_dp_sosi_rst)); + SIGNAL dp_mux_snk_out_2arr : t_dp_siso_2arr_3(g_nof_macs-1 DOWNTO 0); + + SIGNAL tr_10GbE_snk_in_arr : t_dp_sosi_arr(g_nof_macs-1 DOWNTO 0); + SIGNAL tr_10GbE_snk_out_arr : t_dp_siso_arr(g_nof_macs-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy); + SIGNAL tr_10GbE_src_out_arr : t_dp_sosi_arr(g_nof_macs-1 DOWNTO 0); + SIGNAL tr_10GbE_src_in_arr : t_dp_siso_arr(g_nof_macs-1 DOWNTO 0) := (OTHERS => c_dp_siso_rdy); + + SIGNAL eth_src_mac_arr : t_slv_48_arr(g_nof_macs-1 DOWNTO 0); + SIGNAL ip_src_addr_arr : t_slv_32_arr(g_nof_macs-1 DOWNTO 0); + SIGNAL ip_dst_addr_arr : t_slv_32_arr(g_nof_macs-1 DOWNTO 0); + +BEGIN + + src_out_arr <= tr_10GbE_src_out_arr; + tr_10GbE_src_in_arr <= src_in_arr; + + gen_nof_macs : FOR I in 0 TO g_nof_macs-1 GENERATE + + -- Wire hdr_fields_in_arr + eth_src_mac_arr(I) <= hdr_fields_in_arr(I)(field_hi(g_ip_hdr_field_arr, "eth_src_mac") DOWNTO field_lo(g_ip_hdr_field_arr, "eth_src_mac")); + ip_src_addr_arr(I) <= hdr_fields_in_arr(I)(field_hi(g_ip_hdr_field_arr, "ip_src_addr") DOWNTO field_lo(g_ip_hdr_field_arr, "ip_src_addr")); + ip_dst_addr_arr(I) <= hdr_fields_in_arr(I)(field_hi(g_ip_hdr_field_arr, "ip_dst_addr") DOWNTO field_lo(g_ip_hdr_field_arr, "ip_dst_addr")); + + --------------------------------------------------------------------------------------- + -- ARP request + --------------------------------------------------------------------------------------- + u_nw_arp_request : ENTITY work.nw_arp_request + GENERIC MAP ( + g_period_s => g_arp_period_s + ) + PORT MAP ( + dp_pps => dp_pps, + dp_clk => dp_clk, + dp_rst => dp_rst, + + src_out => nw_arp_request_src_out_arr(I), + src_in => nw_arp_request_src_in_arr(I), + + arp_sha => eth_src_mac_arr(I), + arp_spa => ip_src_addr_arr(I), + arp_tpa => ip_dst_addr_arr(I) + ); + + --------------------------------------------------------------------------------------- + -- PING response + --------------------------------------------------------------------------------------- + u_nw_ping_response : ENTITY work.nw_ping_response + GENERIC MAP ( + g_technology => g_technology + ) + PORT MAP ( + clk => dp_clk, + rst => dp_rst, + + snk_in => tr_10GbE_src_out_arr(I), + + src_in => nw_ping_response_src_in_arr(I), + src_out => nw_ping_response_src_out_arr(I), + + eth_src_mac => eth_src_mac_arr(I) + ); + + --------------------------------------------------------------------------------------- + -- dp_mux to multiplex the three possible data streams + --------------------------------------------------------------------------------------- + dp_mux_snk_in_2arr(I)(0) <= snk_in_arr(I); + dp_mux_snk_in_2arr(I)(1) <= nw_ping_response_src_out_arr(I); + dp_mux_snk_in_2arr(I)(2) <= nw_arp_request_src_out_arr(I); + + snk_out_arr(I) <= dp_mux_snk_out_2arr(I)(0); + nw_ping_response_src_in_arr(I) <= dp_mux_snk_out_2arr(I)(1); + nw_arp_request_src_in_arr(I) <= dp_mux_snk_out_2arr(I)(2); + + u_dp_mux : ENTITY dp_lib.dp_mux + GENERIC MAP ( + g_nof_input => c_nof_mux_streams, + g_sel_ctrl_invert => TRUE, + g_fifo_size => array_init(0,c_nof_mux_streams), --no FIFO used but must match g_nof_input + g_fifo_fill => array_init(0,c_nof_mux_streams) --no FIFO used but must match g_nof_input + ) + PORT MAP ( + clk => dp_clk, + rst => dp_rst, + + snk_in_arr => dp_mux_snk_in_2arr(I), + snk_out_arr => dp_mux_snk_out_2arr(I), + + src_out => tr_10GbE_snk_in_arr(I), + src_in => tr_10GbE_snk_out_arr(I) + ); + + END GENERATE; + + ------------- + -- tr_10GbE + ------------- + u_tr_10GbE: ENTITY tr_10GbE_lib.tr_10GbE + GENERIC MAP ( + g_technology => g_technology, + g_sim => g_sim, + g_sim_level => g_sim_level, + g_nof_macs => g_nof_macs, + g_direction => g_direction, + g_use_mdio => g_use_mdio, + g_mdio_epcs_dis => g_mdio_epcs_dis, + g_tx_fifo_fill => g_tx_fifo_fill, + g_tx_fifo_size => g_tx_fifo_size, + g_rx_fifo_size => g_rx_fifo_size, + g_word_alignment_padding => g_word_alignment_padding + ) + PORT MAP ( + -- Transceiver PLL reference clock + tr_ref_clk_644 => tr_ref_clk_644, + tr_ref_clk_312 => tr_ref_clk_312, -- 312.5 MHz for 10GBASE-R + tr_ref_clk_156 => tr_ref_clk_156, -- 156.25 MHz for 10GBASE-R or for XAUI + tr_ref_rst_156 => tr_ref_rst_156, -- for 10GBASE-R or for XAUI + + -- Calibration & reconfig clock + cal_rec_clk => cal_rec_clk, -- for XAUI; + + -- MM interface + mm_rst => mm_rst, + mm_clk => mm_clk, + + reg_mac_mosi => reg_mac_mosi, + reg_mac_miso => reg_mac_miso, + + xaui_mosi => xaui_mosi, + xaui_miso => xaui_miso, + + reg_eth10g_mosi => reg_eth10g_mosi, + reg_eth10g_miso => reg_eth10g_miso, + + mdio_mosi_arr => mdio_mosi_arr, + mdio_miso_arr => mdio_miso_arr, + + reg_10gbase_r_24_mosi => reg_10gbase_r_24_mosi, + reg_10gbase_r_24_miso => reg_10gbase_r_24_miso, + + -- DP interface + dp_rst => dp_rst, + dp_clk => dp_clk, + + src_out_arr => tr_10GbE_src_out_arr, + src_in_arr => tr_10GbE_src_in_arr, + + snk_out_arr => tr_10GbE_snk_out_arr, + snk_in_arr => tr_10GbE_snk_in_arr, + + -- Serial XAUI IO + xaui_tx_arr => xaui_tx_arr, + xaui_rx_arr => xaui_rx_arr, + + -- Serial IO + serial_tx_arr => serial_tx_arr, + serial_rx_arr => serial_rx_arr, + + -- MDIO interface + mdio_rst => mdio_rst, + mdio_mdc_arr => mdio_mdc_arr, + mdio_mdat_in_arr => mdio_mdat_in_arr, + mdio_mdat_oen_arr => mdio_mdat_oen_arr + ); + +END str; diff --git a/libraries/io/nw_10GbE/src/vhdl/nw_arp_request.vhd b/libraries/io/nw_10GbE/src/vhdl/nw_arp_request.vhd new file mode 100644 index 0000000000000000000000000000000000000000..0b1cf79bcdf78a9c2d1a00407bad000069b48014 --- /dev/null +++ b/libraries/io/nw_10GbE/src/vhdl/nw_arp_request.vhd @@ -0,0 +1,155 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2020 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Author: R. van der Walle +-- Purpose: Generate ARP request packets at a predefined interval. +-- Description: +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib, technology_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_network_total_header_pkg.ALL; +USE common_lib.common_interface_layers_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE common_lib.common_field_pkg.ALL; + +ENTITY nw_arp_request IS + GENERIC ( + g_period_s : NATURAL := 30 + ); + PORT ( + dp_pps : IN STD_LOGIC; + dp_clk : IN STD_LOGIC; + dp_rst : IN STD_LOGIC; + + src_in : IN t_dp_siso := c_dp_siso_rst; + src_out : OUT t_dp_sosi := c_dp_sosi_rst; + + arp_sha : IN STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0); + arp_spa : IN STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0); + arp_tpa : IN STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0) + + ); +END nw_arp_request; + +ARCHITECTURE rtl of nw_arp_request IS + + CONSTANT c_data_w : NATURAL := c_xgmii_data_w; + CONSTANT c_nof_hdr_fields : NATURAL := 12; + CONSTANT c_hdr_field_sel : STD_LOGIC_VECTOR(c_nof_hdr_fields-1 DOWNTO 0) := (OTHERS => '0'); + CONSTANT c_hdr_field_arr : t_common_field_arr(c_nof_hdr_fields-1 DOWNTO 0) := ( ( field_name_pad("eth_dst_mac" ), "RW", 48, field_default(c_network_eth_bc_mac) ), --broadcast address + ( field_name_pad("eth_src_mac" ), "RW", 48, field_default(0) ), --same as arp_sha + ( field_name_pad("eth_type" ), "RW", 16, field_default(x"0806") ), -- ARP type + ( field_name_pad("arp_htype" ), "RW", 16, field_default(1) ), -- eth type + ( field_name_pad("arp_ptype" ), "RW", 16, field_default(x"0800") ), -- IP type + ( field_name_pad("arp_hlen" ), "RW", 8, field_default(6) ), -- Mac length is 6 bytes + ( field_name_pad("arp_plen" ), "RW", 8, field_default(4) ), -- IP length is 4 bytes + ( field_name_pad("arp_operation" ), "RW", 16, field_default(1) ), -- operation is request + ( field_name_pad("arp_sha" ), "RW", 48, field_default(0) ), --set later + ( field_name_pad("arp_spa" ), "RW", 32, field_default(0) ), --set later + ( field_name_pad("arp_tha" ), "RW", 48, field_default(0) ), --set to 0 + ( field_name_pad("arp_tpa" ), "RW", 32, field_default(0) )); -- set later + + CONSTANT c_dp_field_blk_snk_data_w : NATURAL := field_slv_len(c_hdr_field_arr); + CONSTANT c_dp_field_blk_src_data_w : NATURAL := c_data_w; + + SIGNAL pps_cnt : NATURAL := 0; + SIGNAL trigger : BOOLEAN := FALSE; + + SIGNAL dp_field_blk_snk_in : t_dp_sosi := c_dp_sosi_rst; + SIGNAL nxt_dp_field_blk_snk_in : t_dp_sosi := c_dp_sosi_rst; + SIGNAL dp_field_blk_snk_out : t_dp_siso := c_dp_siso_rdy; + +BEGIN + + p_field_wires : PROCESS (arp_sha, arp_spa, arp_tpa) + BEGIN + -- Set defaults + loop_field_wires: FOR i IN c_hdr_field_arr'RANGE LOOP + nxt_dp_field_blk_snk_in.data(field_hi(c_hdr_field_arr, i) DOWNTO field_lo(c_hdr_field_arr, i)) <= c_hdr_field_arr(i).default(c_hdr_field_arr(i).size-1 DOWNTO 0); + END LOOP; + -- Overwrite fields comming from inputs + nxt_dp_field_blk_snk_in.data(field_hi(c_hdr_field_arr, "eth_src_mac") DOWNTO field_lo(c_hdr_field_arr, "eth_src_mac")) <= arp_sha; + nxt_dp_field_blk_snk_in.data(field_hi(c_hdr_field_arr, "arp_sha") DOWNTO field_lo(c_hdr_field_arr, "arp_sha")) <= arp_sha; + nxt_dp_field_blk_snk_in.data(field_hi(c_hdr_field_arr, "arp_spa") DOWNTO field_lo(c_hdr_field_arr, "arp_spa")) <= arp_spa; + nxt_dp_field_blk_snk_in.data(field_hi(c_hdr_field_arr, "arp_tpa") DOWNTO field_lo(c_hdr_field_arr, "arp_tpa")) <= arp_tpa; + END PROCESS; + + -- pps counter process setting sop, eop and valid + p_dp_pps : PROCESS (dp_clk, dp_rst) + BEGIN + IF dp_rst = '1' THEN + trigger <= FALSE; + pps_cnt <= 0; + dp_field_blk_snk_in <= c_dp_sosi_rst; + ELSIF RISING_EDGE(dp_clk) THEN + + dp_field_blk_snk_in <= nxt_dp_field_blk_snk_in; + IF trigger AND dp_field_blk_snk_out.ready = '1' AND dp_field_blk_snk_out.xon = '1' THEN + trigger <= FALSE; + dp_field_blk_snk_in.sop <= '1'; + dp_field_blk_snk_in.eop <= '1'; + dp_field_blk_snk_in.valid <= '1'; + END IF; + + IF dp_pps = '1' THEN + IF pps_cnt < g_period_s-1 THEN + pps_cnt <= pps_cnt + 1; + ELSE + pps_cnt <= 0; + trigger <= TRUE; + END IF; + END IF; + + END IF; + END PROCESS; + + -- dp_field_blk to convert the ARP packet SLV to multi-cycle + u_dp_field_blk : ENTITY dp_lib.dp_field_blk + GENERIC MAP ( + g_field_arr => c_hdr_field_arr, + g_field_sel => c_hdr_field_sel, + g_snk_data_w => c_dp_field_blk_snk_data_w, + g_src_data_w => c_dp_field_blk_src_data_w, + g_in_symbol_w => c_byte_w, + g_out_symbol_w => c_byte_w + ) + PORT MAP ( + dp_clk => dp_clk, + dp_rst => dp_rst, + + mm_clk => '0', + mm_rst => '0', + + snk_in => dp_field_blk_snk_in, + snk_out => dp_field_blk_snk_out, + + src_out => src_out, + src_in => src_in + + ); + + +END rtl; diff --git a/libraries/io/nw_10GbE/src/vhdl/nw_ping_response.vhd b/libraries/io/nw_10GbE/src/vhdl/nw_ping_response.vhd new file mode 100644 index 0000000000000000000000000000000000000000..9ecaa256899c7fbafa32bf0ad8754e4b09ea9bb4 --- /dev/null +++ b/libraries/io/nw_10GbE/src/vhdl/nw_ping_response.vhd @@ -0,0 +1,240 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2020 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Author: R. van der Walle +-- Purpose: generate PING response packet if a PING request is received. +-- Description: A response header is derived from the incoming request header. +-- . The payload of the response is created by pipelining the request packet. +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib, technology_lib, tech_mac_10g_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_network_total_header_pkg.ALL; +USE common_lib.common_interface_layers_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE technology_lib.technology_select_pkg.ALL; +USE tech_mac_10g_lib.tech_mac_10g_component_pkg.ALL; + +ENTITY nw_ping_response IS + GENERIC ( + g_technology : NATURAL := c_tech_select_default + ); + PORT ( + clk : IN STD_LOGIC; + rst : IN STD_LOGIC; + + snk_in : IN t_dp_sosi := c_dp_sosi_rst; + + src_in : IN t_dp_siso := c_dp_siso_rdy; + src_out : OUT t_dp_sosi := c_dp_sosi_rst; + + eth_src_mac : IN STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0) + ); +END nw_ping_response; + +ARCHITECTURE rtl of nw_ping_response IS + CONSTANT c_data_w : NATURAL := c_xgmii_data_w; + CONSTANT c_dp_fifo_empty_w : NATURAL := c_tech_mac_10g_empty_w; + CONSTANT c_dp_fifo_size : NATURAL := 16; + + CONSTANT c_cin_w : NATURAL := 4; + CONSTANT c_pipeline : NATURAL := c_network_total_header_64b_nof_words + 5; -- Header length and 5 more pipeline cycles to allow for the other states + + TYPE t_state IS (s_idle, s_capture, s_check, s_sum, s_output, s_wait); + + TYPE t_reg IS RECORD + state : t_state; + word_cnt : NATURAL RANGE 0 TO c_network_total_header_64b_nof_words; + hdr_words_arr : t_network_total_header_64b_arr; + hdr_fields : t_network_total_header; + hdr_response : t_network_total_header_64b_arr; + ip_checksum : STD_LOGIC_VECTOR(c_halfword_w -1 DOWNTO 0); + icmp_checksum : STD_LOGIC_VECTOR(c_halfword_w -1 DOWNTO 0); + ip_sum : UNSIGNED(c_halfword_w + c_cin_w -1 DOWNTO 0); + src_out : t_dp_sosi; + END RECORD; + + SIGNAL r, rin : t_reg; + + CONSTANT c_r_rst : t_reg := ( state => s_idle, + word_cnt => 0, + hdr_words_arr => (OTHERS=>(OTHERS=>'0')), + hdr_fields => c_network_total_header_ones, + hdr_response => (OTHERS=>(OTHERS=>'0')), + ip_checksum => (OTHERS => '0'), + icmp_checksum => (OTHERS => '0'), + ip_sum => (OTHERS => '0'), + src_out => c_dp_sosi_rst ); + + SIGNAL dp_pipeline_src_out : t_dp_sosi; + SIGNAL dp_fifo_sc_src_out : t_dp_sosi; + SIGNAL dp_fifo_sc_rd_emp : STD_LOGIC; + +BEGIN + +-- Combinational Process + p_comb : PROCESS(r, rst, snk_in, dp_pipeline_src_out, dp_fifo_sc_rd_emp) + VARIABLE v : t_reg; + BEGIN + v := r; + + CASE r.state IS + + WHEN s_idle => -- Wait for valid SOP + IF snk_in.sop = '1' AND snk_in.valid = '1' THEN + v.state := s_capture; + v.hdr_words_arr(r.word_cnt) := snk_in.data(c_data_w-1 DOWNTO 0); + v.word_cnt := r.word_cnt + 1; + END IF; + + WHEN s_capture => -- Capture header + IF snk_in.valid = '1' AND r.word_cnt < c_network_total_header_64b_nof_words THEN + v.word_cnt := r.word_cnt + 1; + v.hdr_words_arr(r.word_cnt) := snk_in.data(c_data_w-1 DOWNTO 0); + ELSIF snk_in.eop = '1' AND snk_in.valid = '1' THEN + v := c_r_rst; + ELSIF r.word_cnt >= c_network_total_header_64b_nof_words THEN + v.word_cnt := 0; + v.state := s_check; + v.hdr_fields.eth := func_network_total_header_no_align_extract_eth( r.hdr_words_arr); + v.hdr_fields.ip := func_network_total_header_no_align_extract_ip( r.hdr_words_arr); + v.hdr_fields.icmp := func_network_total_header_no_align_extract_icmp( r.hdr_words_arr); + END IF; + + WHEN s_check => -- Check if packet is ICMP echo request, create response header if it is the case. + IF TO_UINT(r.hdr_fields.eth.eth_type)=c_network_eth_type_ip AND + TO_UINT(r.hdr_fields.ip.protocol)=c_network_ip_protocol_icmp AND + TO_UINT(r.hdr_fields.icmp.msg_type)=c_network_icmp_msg_type_request THEN + v.hdr_response := func_network_total_header_no_align_response_icmp(r.hdr_words_arr, eth_src_mac); + v.state := s_sum; + ELSE + v := c_r_rst; + END IF; + + WHEN s_sum => -- Sum halfwords of headers for checksum + v.state := s_output; + v.ip_sum := r.ip_sum + + UNSIGNED(r.hdr_response(1)(c_halfword_w-1 DOWNTO 0)) -- ip_version, ip_header_length, ip_services + + UNSIGNED(r.hdr_response(2)(c_halfword_w*4 -1 DOWNTO c_halfword_w *3)) -- ip_total_length + + UNSIGNED(r.hdr_response(2)(c_halfword_w*3 -1 DOWNTO c_halfword_w *2)) -- ip_identification + + UNSIGNED(r.hdr_response(2)(c_halfword_w*2 -1 DOWNTO c_halfword_w)) -- ip_flags, ip_fragment_offset + + UNSIGNED(r.hdr_response(2)(c_halfword_w -1 DOWNTO 0)) -- ip_time_to_live, ip_protocol + + UNSIGNED(r.hdr_response(3)(c_halfword_w*3 -1 DOWNTO c_halfword_w *2)) -- ip_src_addr(1/2) + + UNSIGNED(r.hdr_response(3)(c_halfword_w*2 -1 DOWNTO c_halfword_w)) -- ip_src_addr(2/2) + + UNSIGNED(r.hdr_response(3)(c_halfword_w -1 DOWNTO 0)) -- ip_dst_addr(1/2) + + UNSIGNED(r.hdr_response(4)(c_halfword_w*4 -1 DOWNTO c_halfword_w *3)); -- ip_dst_addr(2/2) + + + WHEN s_output => -- Send out ICMP response + v.src_out := dp_pipeline_src_out; + IF dp_pipeline_src_out.valid = '1' THEN + CASE r.word_cnt IS + WHEN 0 => + -- Also perform final checksum calculation + IF dp_pipeline_src_out.sop = '1' THEN -- Wait for SOP + v.src_out.data(c_data_w-1 DOWNTO 0) := r.hdr_response(r.word_cnt); + v.ip_checksum := NOT(STD_LOGIC_VECTOR(r.ip_sum(c_halfword_w-1 DOWNTO 0)+r.ip_sum(r.ip_sum'HIGH DOWNTO c_halfword_w))); -- checksum = inverted (sum + carry) + v.icmp_checksum := TO_UVEC((2048 + TO_UINT(r.hdr_fields.icmp.checksum)), c_halfword_w); -- checksum = original checksum + 0x0800 (incremental update) + v.word_cnt := r.word_cnt+1; + ELSE + v.src_out := c_dp_sosi_rst; + END IF; + WHEN 1 TO 2 => + v.src_out.data(c_data_w-1 DOWNTO 0) := r.hdr_response(r.word_cnt); + v.word_cnt := r.word_cnt+1; + WHEN 3 => + v.src_out.data(c_data_w-1 DOWNTO 0) := r.hdr_response(r.word_cnt); + v.src_out.data(c_halfword_w*4 -1 DOWNTO c_halfword_w *3) := r.ip_checksum; + v.word_cnt := r.word_cnt+1; + WHEN 4 => + v.src_out.data(c_data_w-1 DOWNTO 0) := r.hdr_response(r.word_cnt); + v.src_out.data(c_halfword_w*2 -1 DOWNTO c_halfword_w) := r.icmp_checksum; + v.word_cnt := r.word_cnt+1; + WHEN OTHERS => + IF dp_pipeline_src_out.eop = '1' THEN + v.state := s_wait; + END IF; + END CASE; + END IF; + + WHEN s_wait => + v.src_out := c_dp_sosi_rst; + IF dp_fifo_sc_rd_emp = '1' THEN -- Wait until ping response has left the fifo + v := c_r_rst; + END IF; + + END CASE; + + IF rst = '1' THEN + v := c_r_rst; + END IF; + + rin <= v; + END PROCESS; + + -- Sequential process + p_regs : PROCESS(clk) + BEGIN + IF RISING_EDGE(clk) THEN + r <= rin; + END IF; + END PROCESS; + + -- Pipeline packet payload + u_dp_pipeline : ENTITY dp_lib.dp_pipeline + GENERIC MAP ( + g_pipeline => c_pipeline + ) + PORT MAP ( + clk => clk, + rst => rst, + snk_in => snk_in, + src_out => dp_pipeline_src_out + ); + + -- Store response packet until ready + u_dp_fifo_sc : ENTITY dp_lib.dp_fifo_sc + GENERIC MAP ( + g_technology => g_technology, + g_data_w => c_data_w, + g_empty_w => c_dp_fifo_empty_w, + g_use_empty => TRUE, + g_fifo_size => c_dp_fifo_size + ) + PORT MAP ( + rst => rst, + clk => clk, + + rd_emp => dp_fifo_sc_rd_emp, + + snk_out => OPEN, + snk_in => r.src_out, + + src_in => src_in, + src_out => dp_fifo_sc_src_out + ); + src_out <= dp_fifo_sc_src_out; + +END rtl; diff --git a/libraries/io/nw_10GbE/tb/vhdl/tb_nw_10GbE.vhd b/libraries/io/nw_10GbE/tb/vhdl/tb_nw_10GbE.vhd new file mode 100644 index 0000000000000000000000000000000000000000..cdfbd201328f82057cbace3528bb93958cdad93c --- /dev/null +++ b/libraries/io/nw_10GbE/tb/vhdl/tb_nw_10GbE.vhd @@ -0,0 +1,411 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2020 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Author: R. van der Walle +-- Purpose: Testbench for tb_nw_10GbE. +-- Description: +-- The tb is self checking based on: +-- . proc_tech_mac_10g_rx_packet() for expected header and data type +-- . tx_pkt_cnt=rx_pkt_cnt > 0 must be true at the tb_end. +-- +-- The tb finishes using severity failure because the simulation can not +-- finish by stopping the clocks and applying the resets due to that the IP +-- keeps on toggling internally. +-- Usage: +-- > as 10 +-- > run -all +-- +-- Remarks: +-- . c_tx_rx_loopback: +-- The tb uses a single DUT and c_tx_rx_loopback to model the link. +-- The g_direction = "TX_RX" is verified properly by c_tx_rx_loopback = +-- TRUE. Internally "RX_ONLY" is equivalent to "TX_RX" so there +-- c_tx_rx_loopback = TRUE is also suitable. For TX_ONLY the MAC Tx is +-- internally loopbacked to the MAC Rx, so there the external loopback is +-- not used and set to c_tx_rx_loopback = FALSE. +------------------------------------------------------------------------------- + +LIBRARY IEEE, technology_lib, tech_pll_lib, tech_mac_10g_lib, common_lib, dp_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.common_interface_layers_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; +USE common_lib.common_network_total_header_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE technology_lib.technology_pkg.ALL; +USE technology_lib.technology_select_pkg.ALL; +USE tech_mac_10g_lib.tech_mac_10g_component_pkg.ALL; +USE tech_mac_10g_lib.tb_tech_mac_10g_pkg.ALL; +USE tech_pll_lib.tech_pll_component_pkg.ALL; +USE common_lib.common_field_pkg.ALL; + +ENTITY tb_nw_10GbE IS + -- Test bench control parameters + GENERIC ( + g_technology : NATURAL := c_tech_select_default; + g_tb_end : BOOLEAN := TRUE; -- when TRUE then tb_end ends this simulation, else a higher multi-testbench will end the simulation + g_no_dut : BOOLEAN := FALSE; -- default FALSE to verify the DUT, else use TRUE to verify the tb itself without the DUT + g_dp_clk_period : TIME := 5 ns; -- must be ~< 9000/(9000-c_tx_fifo_fill) * g_ref_clk_156_period + g_sim_level : NATURAL := 0; -- 0 = use IP; 1 = use fast serdes model + g_nof_channels : NATURAL := 1; + g_direction : STRING := "TX_RX"; -- "TX_RX", "TX_ONLY", "RX_ONLY" + g_ref_clk_644_period : TIME := tech_pll_clk_644_period; -- for 10GBASE-R + g_ref_clk_156_period : TIME := 6.4 ns; -- for XAUI + g_data_type : NATURAL := c_tb_tech_mac_10g_data_type_symbols; + g_verify_link_recovery : BOOLEAN := TRUE + ); + PORT ( + tb_end : OUT STD_LOGIC + ); +END tb_nw_10GbE; + +ARCHITECTURE tb OF tb_nw_10GbE IS + + CONSTANT c_sim : BOOLEAN := TRUE; -- tr_xaui_align_dly has time delay ~ 1 sec, so not suitable for simulation + + CONSTANT cal_clk_period : TIME := 25 ns; -- 40 MHz + + CONSTANT phy_delay : TIME := sel_a_b(g_sim_level=0, 0 ns, 0 ns); + CONSTANT c_tx_rx_loopback : BOOLEAN := g_direction/="TX_ONLY"; + + CONSTANT c_tx_fifo_fill : NATURAL := 100; + + CONSTANT c_pkt_length_arr1 : t_nat_natural_arr := array_init(0, 50, 1) & (1472, 1473) & 9000; -- frame longer than 1518-46 = 1472 is received with rx_sosi.err = 8 + -- jumbo frame is 9018-46 = 8972 + CONSTANT c_pkt_length_arr2 : t_nat_natural_arr := array_init(46, 10, 139) & 1472; + CONSTANT c_pkt_length_arr : t_nat_natural_arr := c_pkt_length_arr1 & c_pkt_length_arr2; + CONSTANT c_nof_pkt1 : NATURAL := c_pkt_length_arr1'LENGTH; + CONSTANT c_nof_pkt2 : NATURAL := c_pkt_length_arr2'LENGTH; + CONSTANT c_nof_pkt : NATURAL := sel_a_b(g_verify_link_recovery, c_nof_pkt1 + c_nof_pkt2, c_nof_pkt1); + + CONSTANT c_dst_mac : STD_LOGIC_VECTOR(c_network_eth_mac_slv'RANGE) := X"10FA01020300"; + CONSTANT c_src_mac : STD_LOGIC_VECTOR(c_network_eth_mac_slv'RANGE) := X"123456789ABC"; -- = 12-34-56-78-9A-BC + CONSTANT c_src_mac_tx : STD_LOGIC_VECTOR(c_network_eth_mac_slv'RANGE) := c_src_mac; + --CONSTANT c_src_mac_tx : STD_LOGIC_VECTOR(c_network_eth_mac_slv'RANGE) := X"100056789ABC"; -- = 10-00-56-78-9A-BC + CONSTANT c_ethertype : STD_LOGIC_VECTOR(c_network_eth_type_slv'RANGE) := X"10FA"; + CONSTANT c_etherlen : STD_LOGIC_VECTOR(c_network_eth_type_slv'RANGE) := "0000000000010000"; + + -- Packet headers + CONSTANT c_eth_header_ethertype : t_network_eth_header := (c_dst_mac, c_src_mac_tx, c_ethertype); + CONSTANT c_eth_header_etherlen : t_network_eth_header := (c_dst_mac, c_src_mac_tx, c_etherlen); + + SIGNAL total_header : t_network_total_header := c_network_total_header_ones; -- default fill all fields with value 1 + + CONSTANT c_ip_hdr_field_arr : t_common_field_arr(3+12-1 DOWNTO 0) := ( ( field_name_pad("eth_dst_mac" ), "RW", 48, field_default(x"ffffffffffff") ), + ( field_name_pad("eth_src_mac" ), "RW", 48, field_default(x"e840f2acff78") ), + ( field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), + ( field_name_pad("ip_version" ), "RW", 4, field_default(4) ), + ( field_name_pad("ip_header_length" ), "RW", 4, field_default(5) ), + ( field_name_pad("ip_services" ), "RW", 8, field_default(0) ), + ( field_name_pad("ip_total_length" ), "RW", 16, field_default(x"54") ), + ( field_name_pad("ip_identification" ), "RW", 16, field_default(x"3daf") ), + ( field_name_pad("ip_flags" ), "RW", 3, field_default(2) ), + ( field_name_pad("ip_fragment_offset"), "RW", 13, field_default(0) ), + ( field_name_pad("ip_time_to_live" ), "RW", 8, field_default(x"40") ), + ( field_name_pad("ip_protocol" ), "RW", 8, field_default(1) ), + ( field_name_pad("ip_header_checksum"), "RW", 16, field_default(x"e580") ), + ( field_name_pad("ip_src_addr" ), "RW", 32, field_default(x"0a570224") ), + ( field_name_pad("ip_dst_addr" ), "RW", 32, field_default(x"0a5700a8") ) ); + -- Clocks and reset + SIGNAL tx_end_arr : STD_LOGIC_VECTOR(g_nof_channels-1 DOWNTO 0); + SIGNAL tx_end : STD_LOGIC; + SIGNAL rx_end : STD_LOGIC; + SIGNAL cal_clk : STD_LOGIC := '1'; -- calibration clock + SIGNAL mm_clk : STD_LOGIC; -- memory-mapped bus clock + SIGNAL mm_rst : STD_LOGIC; -- reset synchronous with mm_clk + SIGNAL dp_clk : STD_LOGIC := '1'; -- data path clock + SIGNAL dp_pps : STD_LOGIC := '0'; -- data path clock + SIGNAL dp_rst : STD_LOGIC; -- reset synchronous with dp_clk + + -- External reference clocks + SIGNAL tr_ref_clk_644 : STD_LOGIC := '1'; -- 10GBASE-R + SIGNAL tr_ref_clk_312 : STD_LOGIC; -- 10GBASE-R + SIGNAL tr_ref_clk_156 : STD_LOGIC := '1'; -- 10GBASE-R or XAUI + SIGNAL tr_ref_rst_156 : STD_LOGIC; -- 10GBASE-R or XAUI + + -- MAC 10G control interface + SIGNAL mm_init : STD_LOGIC; + SIGNAL mac_mosi_wrdata : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); -- for channel 0, 32 bit + SIGNAL mac_mosi : t_mem_mosi; + SIGNAL mac_miso : t_mem_miso; + SIGNAL mac_miso_rdval : STD_LOGIC; -- for channel 0 + SIGNAL mac_miso_rddata : STD_LOGIC_VECTOR(c_word_w-1 DOWNTO 0); -- for channel 0, 32 bit + + -- MAC 10G transmit interface + SIGNAL tx_en : STD_LOGIC := '1'; + SIGNAL tx_siso_arr : t_dp_siso_arr(g_nof_channels-1 DOWNTO 0); + SIGNAL tx_sosi_arr : t_dp_sosi_arr(g_nof_channels-1 DOWNTO 0); + SIGNAL tx_sosi_data : STD_LOGIC_VECTOR(c_tech_mac_10g_data_w-1 DOWNTO 0); -- for channel 0, 64 bit + + -- MAC 10G receive interface + SIGNAL rx_siso_arr : t_dp_siso_arr(g_nof_channels-1 DOWNTO 0); + SIGNAL rx_sosi_arr : t_dp_sosi_arr(g_nof_channels-1 DOWNTO 0); + SIGNAL rx_sosi_data : STD_LOGIC_VECTOR(c_tech_mac_10g_data_w-1 DOWNTO 0); -- for channel 0, 64 bit + + -- PHY XAUI serial I/O + SIGNAL xaui_tx_arr : t_xaui_arr(g_nof_channels-1 DOWNTO 0); + SIGNAL xaui_rx_arr : t_xaui_arr(g_nof_channels-1 DOWNTO 0) := (OTHERS=>(OTHERS=>'0')); + + -- PHY 10GBASE-R serial IO + SIGNAL serial_tx_arr : STD_LOGIC_VECTOR(g_nof_channels-1 downto 0); + SIGNAL serial_rx_arr : STD_LOGIC_VECTOR(g_nof_channels-1 downto 0) := (OTHERS=>'0'); + + -- Model a serial link fault + SIGNAL link_fault_arr : STD_LOGIC_VECTOR(g_nof_channels-1 downto 0); + + -- Verification + SIGNAL tx_pkt_cnt_arr : t_natural_arr(g_nof_channels-1 downto 0) := (OTHERS=>0); + SIGNAL rx_pkt_cnt_arr : t_natural_arr(g_nof_channels-1 downto 0) := (OTHERS=>0); + SIGNAL rx_toggle_arr : STD_LOGIC_VECTOR(g_nof_channels-1 downto 0) := (OTHERS=>'0'); -- toggle after every received packet + +BEGIN + + cal_clk <= NOT cal_clk AFTER cal_clk_period/2; -- Calibration clock + + dp_clk <= NOT dp_clk AFTER g_dp_clk_period/2; -- DP clock + dp_rst <= '1', '0' AFTER g_dp_clk_period*10; + + -- debug signals to ease monitoring in wave window + mac_mosi_wrdata <= mac_mosi.wrdata(c_word_w-1 DOWNTO 0); + mac_miso_rddata <= mac_miso.rddata(c_word_w-1 DOWNTO 0); + mac_miso_rdval <= '1' WHEN mac_mosi.rd='1' AND mac_miso.waitrequest='0' ELSE '0'; -- c_rd_latency = 1 + + tx_sosi_data <= tx_sosi_arr(0).data(c_tech_mac_10g_data_w-1 DOWNTO 0); + rx_sosi_data <= rx_sosi_arr(0).data(c_tech_mac_10g_data_w-1 DOWNTO 0); + + -- Use signal to leave unused fields 'X' + total_header.eth <= c_eth_header_ethertype; + + -- Generate reference clocks + gen_ref_clocks_xaui : IF g_technology=c_tech_stratixiv GENERATE + tr_ref_clk_644 <= 'X'; + tr_ref_clk_312 <= 'X'; + tr_ref_clk_156 <= NOT tr_ref_clk_156 AFTER g_ref_clk_156_period/2; + tr_ref_rst_156 <= '1', '0' AFTER g_ref_clk_156_period*5; + END GENERATE; + + gen_ref_clocks_10gbase_r : IF g_technology/=c_tech_stratixiv GENERATE + tr_ref_clk_644 <= NOT tr_ref_clk_644 AFTER g_ref_clk_644_period/2; + + pll : ENTITY tech_pll_lib.tech_pll_xgmii_mac_clocks + GENERIC MAP ( + g_technology => g_technology + ) + PORT MAP ( + refclk_644 => tr_ref_clk_644, + rst_in => mm_rst, + clk_156 => tr_ref_clk_156, + clk_312 => tr_ref_clk_312, + rst_156 => tr_ref_rst_156, + rst_312 => OPEN + ); + END GENERATE; + + -- Setup all MACs in series + u_mm_setup : ENTITY tech_mac_10g_lib.tb_tech_mac_10g_setup + GENERIC MAP ( + g_technology => g_technology, + g_nof_macs => g_nof_channels, + g_src_mac => c_src_mac + ) + PORT MAP ( + tb_end => rx_end, + mm_clk => mm_clk, + mm_rst => mm_rst, + mm_init => mm_init, + mac_mosi => mac_mosi, + mac_miso => mac_miso + ); + + gen_transmitter : FOR I IN 0 TO g_nof_channels-1 GENERATE + -- Packet transmitter + u_transmitter : ENTITY tech_mac_10g_lib.tb_tech_mac_10g_transmitter + GENERIC MAP ( + g_data_type => g_data_type, + g_pkt_length_arr1 => c_pkt_length_arr1, + g_pkt_length_arr2 => c_pkt_length_arr2, + g_verify_link_recovery => g_verify_link_recovery + ) + PORT MAP ( + mm_init => mm_init, + total_header => total_header, + tx_clk => dp_clk, + tx_siso => tx_siso_arr(I), + tx_sosi => tx_sosi_arr(I), + link_fault => link_fault_arr(I), + tx_end => tx_end_arr(I) + ); + END GENERATE; + + no_dut : IF g_no_dut=TRUE GENERATE + rx_sosi_arr <= tx_sosi_arr; + tx_siso_arr <= rx_siso_arr; + END GENERATE; + + gen_dut : IF g_no_dut=FALSE GENERATE + u_nw_10GbE : ENTITY work.nw_10GbE + GENERIC MAP ( + g_technology => g_technology, + g_sim => c_sim, + g_sim_level => g_sim_level, -- 0 = use IP; 1 = use fast serdes model + g_nof_macs => g_nof_channels, + g_direction => g_direction, + g_use_mdio => TRUE, + g_mdio_epcs_dis => TRUE, -- TRUE disables Enhanced PCS on init; e.g. to target a 10GbE card in PC that does not support it + g_tx_fifo_fill => c_tx_fifo_fill, + g_tx_fifo_size => 256, + g_word_alignment_padding => TRUE, + g_ip_hdr_field_arr => c_ip_hdr_field_arr + ) + PORT MAP ( + -- Transceiver PLL reference clock + tr_ref_clk_644 => tr_ref_clk_644, -- 644.531250 MHz for 10GBASE-R + tr_ref_clk_312 => tr_ref_clk_312, -- 312.5 MHz for 10GBASE-R + tr_ref_clk_156 => tr_ref_clk_156, -- 156.25 MHz for 10GBASE-R or for XAUI + tr_ref_rst_156 => tr_ref_rst_156, -- for 10GBASE-R or for XAUI + + -- Calibration & reconfig clock + cal_rec_clk => cal_clk, + + -- MM interface + mm_rst => mm_rst, + mm_clk => mm_clk, + + reg_mac_mosi => mac_mosi, + reg_mac_miso => mac_miso, + + xaui_mosi => c_mem_mosi_rst, + xaui_miso => OPEN, + + mdio_mosi_arr => (OTHERS=>c_mem_mosi_rst), + mdio_miso_arr => OPEN, + + -- DP interface + dp_rst => dp_rst, + dp_clk => dp_clk, + dp_pps => dp_pps, + + snk_out_arr => tx_siso_arr, + snk_in_arr => tx_sosi_arr, + + src_in_arr => rx_siso_arr, + src_out_arr => rx_sosi_arr, + + -- Serial XAUI interface + xaui_tx_arr => xaui_tx_arr, + xaui_rx_arr => xaui_rx_arr, + + -- Serial IO + serial_tx_arr => serial_tx_arr, + serial_rx_arr => serial_rx_arr, + + -- MDIO interface + mdio_rst => OPEN, + mdio_mdc_arr => OPEN, + mdio_mdat_in_arr => (OTHERS=>'0'), + mdio_mdat_oen_arr => OPEN, + + hdr_fields_in_arr => (OTHERS => (OTHERS => '0')) + ); + END GENERATE; + + gen_link_connect : FOR I IN 0 TO g_nof_channels-1 GENERATE + u_link_connect : ENTITY tech_mac_10g_lib.tb_tech_mac_10g_link_connect + GENERIC MAP ( + g_loopback => c_tx_rx_loopback, + g_link_delay => phy_delay + ) + PORT MAP ( + link_fault => link_fault_arr(I), -- when '1' then forces rx_serial_arr(0)='0' + + -- 10GBASE-R serial layer connect + serial_tx => serial_tx_arr(I), + serial_rx => serial_rx_arr(I), -- connects to delayed tx_serial when g_loopback=TRUE + + -- XAUI serial layer connect + xaui_tx => xaui_tx_arr(I), + xaui_rx => xaui_rx_arr(I) -- connects to delayed xaui_tx when g_loopback=TRUE + ); + END GENERATE; + + gen_receiver : FOR I IN 0 TO g_nof_channels-1 GENERATE + u_receiver : ENTITY tech_mac_10g_lib.tb_tech_mac_10_receiver + GENERIC MAP ( + g_data_type => g_data_type + ) + PORT MAP ( + mm_init => mm_init, + total_header => total_header, + rx_clk => dp_clk, + rx_sosi => rx_sosi_arr(I), + rx_siso => rx_siso_arr(I), + rx_toggle => rx_toggle_arr(I) + ); + END GENERATE; + + gen_verify_rx_at_eop : FOR I IN 0 TO g_nof_channels-1 GENERATE + u_verify_rx_at_eop : ENTITY tech_mac_10g_lib.tb_tech_mac_10_verify_rx_at_eop + GENERIC MAP ( + g_no_padding => g_no_dut, + g_pkt_length_arr => c_pkt_length_arr + ) + PORT MAP ( + tx_clk => dp_clk, + tx_sosi => tx_sosi_arr(I), + rx_clk => dp_clk, + rx_sosi => rx_sosi_arr(I) + ); + END GENERATE; + + gen_verify_rx_pkt_cnt : FOR I IN 0 TO g_nof_channels-1 GENERATE + u_verify_rx_pkt_cnt : ENTITY tech_mac_10g_lib.tb_tech_mac_10g_verify_rx_pkt_cnt + GENERIC MAP ( + g_nof_pkt => c_nof_pkt + ) + PORT MAP ( + tx_clk => dp_clk, + tx_sosi => tx_sosi_arr(I), + rx_clk => dp_clk, + rx_sosi => rx_sosi_arr(I), + tx_pkt_cnt => tx_pkt_cnt_arr(I), + rx_pkt_cnt => rx_pkt_cnt_arr(I), + rx_end => rx_end + ); + END GENERATE; + + -- Stop the simulation + tx_end <= andv(tx_end_arr); + + u_simulation_end : ENTITY tech_mac_10g_lib.tb_tech_mac_10g_simulation_end + GENERIC MAP ( + g_tb_end => g_tb_end, + g_nof_clk_to_rx_end => 1000 + ) + PORT MAP ( + clk => dp_clk, + tx_end => tx_end, + rx_end => rx_end, + tb_end => tb_end + ); + +END tb; diff --git a/libraries/io/nw_10GbE/tb/vhdl/tb_nw_arp_request.vhd b/libraries/io/nw_10GbE/tb/vhdl/tb_nw_arp_request.vhd new file mode 100644 index 0000000000000000000000000000000000000000..950aedd237ca96781c34831b29d3124098ea8cb4 --- /dev/null +++ b/libraries/io/nw_10GbE/tb/vhdl/tb_nw_arp_request.vhd @@ -0,0 +1,101 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2020 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Author: R. van der Walle +-- Purpose: Verify nw_arp_request.vhd +-- Description: +-- Usage: +-- > as 10 +-- > run -all -- signal tb_end will stop the simulation by stopping the clk +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE common_lib.common_field_pkg.ALL; +USE common_lib.common_network_layers_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE dp_lib.tb_dp_pkg.ALL; + +ENTITY tb_nw_arp_request IS +GENERIC ( + g_test_backpressure : BOOLEAN := TRUE + ); +END tb_nw_arp_request; + +ARCHITECTURE tb OF tb_nw_arp_request IS + + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL clk : STD_LOGIC := '1'; + SIGNAL dp_pps : STD_LOGIC := '1'; + SIGNAL rst : STD_LOGIC := '1'; + + SIGNAL src_in : t_dp_siso := c_dp_siso_rst; + SIGNAL src_out : t_dp_sosi := c_dp_sosi_rst; + + SIGNAL arp_sha : STD_LOGIC_VECTOR(c_network_eth_mac_addr_w-1 DOWNTO 0) := x"AABBCCDDEEFF"; + SIGNAL arp_spa : STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0) := x"A1A2A3A4"; + SIGNAL arp_tpa : STD_LOGIC_VECTOR(c_network_ip_addr_w-1 DOWNTO 0) := x"B1B2B3B4"; + +BEGIN + + clk <= (NOT clk) OR tb_end AFTER clk_period/2; + rst <= '1', '0' AFTER clk_period*7; + src_in.xon <= '1'; + + p_stimuli : PROCESS + BEGIN + IF g_test_backpressure THEN + src_in.ready <= '0'; + ELSE + src_in.ready <= '1'; + END IF; + dp_pps <= '0'; + proc_common_wait_some_cycles(clk, 10); + dp_pps <= '1'; + proc_common_wait_some_cycles(clk, 1); + dp_pps <= '0'; + proc_common_wait_some_cycles(clk, 10); + src_in.ready <= '1'; + proc_common_wait_until_evt(clk, src_out.eop); + tb_end <= '1'; + END PROCESS; + + dut: ENTITY work.nw_arp_request + GENERIC MAP( + g_period_s => 1 + ) + PORT MAP( + dp_pps => dp_pps, + dp_clk => clk, + dp_rst => rst, + + src_in => src_in, + src_out => src_out, + + arp_sha => arp_sha, + arp_spa => arp_spa, + arp_tpa => arp_tpa + ); + +END tb; diff --git a/libraries/io/nw_10GbE/tb/vhdl/tb_nw_ping_response.vhd b/libraries/io/nw_10GbE/tb/vhdl/tb_nw_ping_response.vhd new file mode 100644 index 0000000000000000000000000000000000000000..0f38f4ae42540a7d0a57eb17e156bf3d5bbe9795 --- /dev/null +++ b/libraries/io/nw_10GbE/tb/vhdl/tb_nw_ping_response.vhd @@ -0,0 +1,257 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2020 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Author: R. van der Walle +-- Purpose: Verify nw_ping_response.vhd +-- Description: +-- Usage: +-- > as 10 +-- > run -all -- signal tb_end will stop the simulation by stopping the clk +------------------------------------------------------------------------------- + +LIBRARY IEEE, common_lib, dp_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_lfsr_sequences_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE common_lib.common_field_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE dp_lib.tb_dp_pkg.ALL; + +ENTITY tb_nw_ping_response IS +END tb_nw_ping_response; + +ARCHITECTURE tb OF tb_nw_ping_response IS + + CONSTANT c_data_w : NATURAL := 64; + + CONSTANT c_nof_ping_packet_fields : NATURAL := 21; + CONSTANT c_nof_udp_packet_fields : NATURAL := 20; + + CONSTANT c_ping_packet : t_common_field_arr(c_nof_ping_packet_fields-1 DOWNTO 0) := ( ( field_name_pad("eth_dst_mac" ), "RW", 48, field_default(x"ffffffffffff") ), + ( field_name_pad("eth_src_mac" ), "RW", 48, field_default(x"e840f2acff78") ), + ( field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), + ( field_name_pad("ip_version" ), "RW", 4, field_default(4) ), + ( field_name_pad("ip_header_length" ), "RW", 4, field_default(5) ), + ( field_name_pad("ip_services" ), "RW", 8, field_default(0) ), + ( field_name_pad("ip_total_length" ), "RW", 16, field_default(x"54") ), + ( field_name_pad("ip_identification" ), "RW", 16, field_default(x"3daf") ), + ( field_name_pad("ip_flags" ), "RW", 3, field_default(2) ), + ( field_name_pad("ip_fragment_offset"), "RW", 13, field_default(0) ), + ( field_name_pad("ip_time_to_live" ), "RW", 8, field_default(x"40") ), + ( field_name_pad("ip_protocol" ), "RW", 8, field_default(1) ), + ( field_name_pad("ip_header_checksum"), "RW", 16, field_default(x"e580") ), + ( field_name_pad("ip_src_addr" ), "RW", 32, field_default(x"0a570224") ), + ( field_name_pad("ip_dst_addr" ), "RW", 32, field_default(x"0a5700a8") ), + ( field_name_pad("icmp_type" ), "RW", 8, field_default(8) ), + ( field_name_pad("icmp_code" ), "RW", 8, field_default(0) ), + ( field_name_pad("icmp_checksum" ), "RW", 16, field_default(x"117B") ), + ( field_name_pad("icmp_identifier" ), "RW", 16, field_default(x"7052") ), + ( field_name_pad("icmp_seq_number" ), "RW", 16, field_default(x"0001") ), + ( field_name_pad("icmp_payload" ), "RW", 160, field_default(x"123456789ABCDEF01234123456789ABCDEF01234") ) ); + + + CONSTANT c_udp_packet : t_common_field_arr(c_nof_udp_packet_fields-1 DOWNTO 0) := ( ( field_name_pad("eth_dst_mac" ), "RW", 48, field_default(x"00074306C700") ), + ( field_name_pad("eth_src_mac" ), "RW", 48, field_default(0) ), + ( field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), + ( field_name_pad("ip_version" ), "RW", 4, field_default(4) ), + ( field_name_pad("ip_header_length" ), "RW", 4, field_default(5) ), + ( field_name_pad("ip_services" ), "RW", 8, field_default(0) ), + ( field_name_pad("ip_total_length" ), "RW", 16, field_default(810) ), + ( field_name_pad("ip_identification" ), "RW", 16, field_default(0) ), + ( field_name_pad("ip_flags" ), "RW", 3, field_default(2) ), + ( field_name_pad("ip_fragment_offset"), "RW", 13, field_default(0) ), + ( field_name_pad("ip_time_to_live" ), "RW", 8, field_default(127) ), + ( field_name_pad("ip_protocol" ), "RW", 8, field_default(17) ), + ( field_name_pad("ip_header_checksum"), "RW", 16, field_default(0) ), + ( field_name_pad("ip_src_addr" ), "RW", 32, field_default(0) ), + ( field_name_pad("ip_dst_addr" ), "RW", 32, field_default(x"C0A80001") ), + ( field_name_pad("udp_src_port" ), "RW", 16, field_default(0) ), + ( field_name_pad("udp_dst_port" ), "RW", 16, field_default(0) ), + ( field_name_pad("udp_total_length" ), "RW", 16, field_default(790) ), + ( field_name_pad("udp_checksum" ), "RW", 16, field_default(0) ), + ( field_name_pad("udp_payload" ), "RW", 160, field_default(x"123456789ABCDEF01234123456789ABCDEF01234") ) ); + + CONSTANT c_ping_packet_len : NATURAL := field_slv_out_len(c_ping_packet); + CONSTANT c_udp_packet_len : NATURAL := field_slv_out_len(c_udp_packet); + + CONSTANT c_ping_packet_slv : STD_LOGIC_VECTOR(c_ping_packet_len -1 DOWNTO 0) := field_map_defaults(c_ping_packet); + CONSTANT c_udp_packet_slv : STD_LOGIC_VECTOR(c_udp_packet_len -1 DOWNTO 0) := field_map_defaults(c_udp_packet); + + CONSTANT c_ping_packet_field_sel : STD_LOGIC_VECTOR(c_nof_ping_packet_fields-1 DOWNTO 0) := (OTHERS => '0'); + CONSTANT c_udp_packet_field_sel : STD_LOGIC_VECTOR(c_nof_udp_packet_fields-1 DOWNTO 0) := (OTHERS => '0'); + + CONSTANT c_nof_ping_responses : NATURAL := 20; + + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL clk : STD_LOGIC := '1'; + SIGNAL rst : STD_LOGIC := '1'; + SIGNAL ping_dp_field_blk_snk_in : t_dp_sosi; + SIGNAL ping_dp_field_blk_snk_out : t_dp_siso; + SIGNAL ping_dp_field_blk_src_out : t_dp_sosi; + SIGNAL ping_dp_field_blk_src_in : t_dp_siso; + + SIGNAL udp_dp_field_blk_snk_in : t_dp_sosi; + SIGNAL udp_dp_field_blk_snk_out : t_dp_siso; + SIGNAL udp_dp_field_blk_src_out : t_dp_sosi; + SIGNAL udp_dp_field_blk_src_in : t_dp_siso; + + SIGNAL nw_ping_response_snk_in : t_dp_sosi; + SIGNAL nw_ping_response_src_in : t_dp_siso; + SIGNAL nw_ping_response_src_out : t_dp_sosi; + + SIGNAL cnt : NATURAL := 0; + +BEGIN + + clk <= (NOT clk) OR tb_end AFTER clk_period/2; + rst <= '1', '0' AFTER clk_period*7; + + p_packets : PROCESS(clk) + BEGIN + IF RISING_EDGE(clk) THEN + + ping_dp_field_blk_snk_in.data(c_ping_packet_len-1 DOWNTO 0 ) <= c_ping_packet_slv; + ping_dp_field_blk_snk_in.valid <= ping_dp_field_blk_snk_out.ready; + ping_dp_field_blk_snk_in.sop <= ping_dp_field_blk_snk_out.ready; + ping_dp_field_blk_snk_in.eop <= ping_dp_field_blk_snk_out.ready; + + udp_dp_field_blk_snk_in.data(c_udp_packet_len-1 DOWNTO 0 ) <= c_udp_packet_slv; + udp_dp_field_blk_snk_in.valid <= udp_dp_field_blk_snk_out.ready; + udp_dp_field_blk_snk_in.sop <= udp_dp_field_blk_snk_out.ready; + udp_dp_field_blk_snk_in.eop <= udp_dp_field_blk_snk_out.ready; + + END IF; + END PROCESS; + + p_stimuli : PROCESS(clk) + VARIABLE start : BOOLEAN := FALSE; + BEGIN + IF RISING_EDGE(clk) THEN + IF cnt = 5 THEN + nw_ping_response_snk_in.valid <= '0'; + nw_ping_response_snk_in.sop <= '0'; + nw_ping_response_snk_in.eop <= '0'; + IF ping_dp_field_blk_src_out.sop = '1' THEN + start := TRUE; + END IF; + IF start AND ping_dp_field_blk_src_out.valid = '1' THEN + nw_ping_response_snk_in <= ping_dp_field_blk_src_out; + END IF; + IF udp_dp_field_blk_src_out.eop = '1' THEN + cnt <= 0; + start := FALSE; + END IF; + + ELSE + nw_ping_response_snk_in.valid <= '0'; + nw_ping_response_snk_in.sop <= '0'; + nw_ping_response_snk_in.eop <= '0'; + IF udp_dp_field_blk_src_out.sop = '1' THEN + start := TRUE; + END IF; + IF start AND udp_dp_field_blk_src_out.valid = '1' THEN + nw_ping_response_snk_in <= udp_dp_field_blk_src_out; + END IF; + IF ping_dp_field_blk_src_out.eop = '1' THEN + cnt <= cnt +1; + start := FALSE; + END IF; + END IF; + END IF; + END PROCESS; + + p_tb_end : PROCESS + BEGIN + FOR I IN 0 TO 2*c_nof_ping_responses LOOP + proc_common_wait_until_evt(clk, nw_ping_response_src_out.eop); + END LOOP; + tb_end <= '1'; + END PROCESS; + + nw_ping_response_src_in.xon <= '1'; + nw_ping_response_src_in.ready <= '1'; + dut : ENTITY work.nw_ping_response + PORT MAP ( + clk => clk, + rst => rst, + + snk_in => nw_ping_response_snk_in, + + src_in => nw_ping_response_src_in, + src_out => nw_ping_response_src_out, + + eth_src_mac => x"14dda9ec2e0f" + + ); + + ping_dp_field_blk_src_in.ready <= '1'; + ping_dp_field_blk_src_in.xon <= '1'; + udp_dp_field_blk_src_in.ready <= '1'; + udp_dp_field_blk_src_in.xon <= '1'; + + u_ping_dp_field_blk : ENTITY dp_lib.dp_field_blk + GENERIC MAP ( + g_field_arr => c_ping_packet, + g_field_sel => c_ping_packet_field_sel, + g_snk_data_w => c_ping_packet_len, + g_src_data_w => c_data_w, + g_in_symbol_w => c_byte_w, + g_out_symbol_w => c_byte_w + ) + PORT MAP ( + dp_clk => clk, + dp_rst => rst, + + mm_clk => '0', + mm_rst => '0', + + snk_in => ping_dp_field_blk_snk_in, + snk_out => ping_dp_field_blk_snk_out, + + src_out => ping_dp_field_blk_src_out, + src_in => ping_dp_field_blk_src_in + ); + + u_udp_dp_field_blk : ENTITY dp_lib.dp_field_blk + GENERIC MAP ( + g_field_arr => c_udp_packet, + g_field_sel => c_udp_packet_field_sel, + g_snk_data_w => c_udp_packet_len, + g_src_data_w => c_data_w, + g_in_symbol_w => c_byte_w, + g_out_symbol_w => c_byte_w + ) + PORT MAP ( + dp_clk => clk, + dp_rst => rst, + + mm_clk => '0', + mm_rst => '0', + + snk_in => udp_dp_field_blk_snk_in, + snk_out => udp_dp_field_blk_snk_out, + + src_out => udp_dp_field_blk_src_out, + src_in => udp_dp_field_blk_src_in + ); +END tb; diff --git a/libraries/io/nw_10GbE/tb/vhdl/tb_tb_nw_10GbE.vhd b/libraries/io/nw_10GbE/tb/vhdl/tb_tb_nw_10GbE.vhd new file mode 100644 index 0000000000000000000000000000000000000000..34d1c7abcda9693cb9d6558de44adef524361a79 --- /dev/null +++ b/libraries/io/nw_10GbE/tb/vhdl/tb_tb_nw_10GbE.vhd @@ -0,0 +1,86 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2020 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +-- Author: R. van der Walle +-- Purpose: Multi testbench for nw_10GbE the 10G Ethernet IO module +-- Description: +-- The multi-tb finishes when all instances have signaled tb_end. +-- Usage: +-- > as 5 +-- > run -all +------------------------------------------------------------------------------- + +LIBRARY IEEE, technology_lib, tech_pll_lib, tech_mac_10g_lib; +USE IEEE.std_logic_1164.ALL; +USE technology_lib.technology_pkg.ALL; +USE technology_lib.technology_select_pkg.ALL; +USE tech_mac_10g_lib.tb_tech_mac_10g_pkg.ALL; +USE tech_pll_lib.tech_pll_component_pkg.ALL; + +ENTITY tb_tb_nw_10GbE IS +END tb_tb_nw_10GbE; + +ARCHITECTURE tb OF tb_tb_nw_10GbE IS + CONSTANT c_644 : TIME := tech_pll_clk_644_period; + CONSTANT c_156 : TIME := 6.4 ns; + CONSTANT c_data_type : NATURAL := c_tb_tech_mac_10g_data_type_symbols; + + CONSTANT c_tb_end_vec : STD_LOGIC_VECTOR(7 DOWNTO 0) := (OTHERS=>'1'); + SIGNAL tb_end_vec : STD_LOGIC_VECTOR(7 DOWNTO 0) := c_tb_end_vec; -- sufficiently long to fit all tb instances + SIGNAL tb_end : STD_LOGIC := '0'; +BEGIN + +-- g_technology : NATURAL := c_tech_select_default; +-- g_tb_end : BOOLEAN := TRUE; -- when TRUE then tb_end ends this simulation, else a higher multi-testbench will end the simulation +-- g_no_dut : BOOLEAN := FALSE; -- default FALSE to verify the DUT, else use TRUE to verify the tb itself without the DUT +-- g_dp_clk_period : TIME := 5 ns; -- 200 MHz +-- g_sim_level : NATURAL := 1; -- 0 = use IP; 1 = use fast serdes model +-- g_nof_channels : NATURAL := 1; +-- g_direction : STRING := "TX_RX"; -- "TX_RX", "TX_ONLY", "RX_ONLY" +-- g_ref_clk_644_period : TIME := tech_pll_clk_644_period; -- for 10GBASE-R +-- g_ref_clk_156_period : TIME := 6.4 ns; -- for XAUI +-- g_data_type : NATURAL := c_tb_tech_mac_10g_data_type_symbols; +-- g_verify_link_recovery : BOOLEAN := TRUE; + + u_no_dut : ENTITY work.tb_nw_10GbE GENERIC MAP (c_tech_select_default, FALSE, TRUE, 5 ns, 0, 1, "TX_RX", c_644, c_156, c_data_type, TRUE) PORT MAP (tb_end_vec(0)); + u_nw_10GbE : ENTITY work.tb_nw_10GbE GENERIC MAP (c_tech_select_default, FALSE, FALSE, 5 ns, 0, 1, "TX_RX", c_644, c_156, c_data_type, TRUE) PORT MAP (tb_end_vec(1)); + u_nw_10GbE_tx_only : ENTITY work.tb_nw_10GbE GENERIC MAP (c_tech_select_default, FALSE, FALSE, 5 ns, 0, 1, "TX_ONLY", c_644, c_156, c_data_type, TRUE) PORT MAP (tb_end_vec(2)); + u_nw_10GbE_rx_only : ENTITY work.tb_nw_10GbE GENERIC MAP (c_tech_select_default, FALSE, FALSE, 5 ns, 0, 1, "RX_ONLY", c_644, c_156, c_data_type, TRUE) PORT MAP (tb_end_vec(3)); + u_nw_10GbE_dp_clk_6_5ns : ENTITY work.tb_nw_10GbE GENERIC MAP (c_tech_select_default, FALSE, FALSE, 6.5 ns, 0, 1, "TX_RX", c_644, c_156, c_data_type, TRUE) PORT MAP (tb_end_vec(4)); + gen_2_channels : IF c_tech_select_default = c_tech_stratixiv GENERATE + u_nw_10GbE_nof_channels_is_2 : ENTITY work.tb_nw_10GbE GENERIC MAP (c_tech_select_default, FALSE, FALSE, 5 ns, 0, 2, "TX_RX", c_644, c_156, c_data_type, TRUE) PORT MAP (tb_end_vec(5)); + END GENERATE; + -- For arria10, nof_channels need to be 1, 4, 12, 24, 48. + gen_24_channels : IF c_tech_select_default /= c_tech_stratixiv GENERATE + u_nw_10GbE_nof_channels_is_24 : ENTITY work.tb_nw_10GbE GENERIC MAP (c_tech_select_default, FALSE, FALSE, 5 ns, 0, 24, "TX_RX", c_644, c_156, c_data_type, TRUE) PORT MAP (tb_end_vec(5)); + END GENERATE; + u_nw_10GbE_sim_level_is_1 : ENTITY work.tb_nw_10GbE GENERIC MAP (c_tech_select_default, FALSE, FALSE, 5 ns, 1, 1, "TX_RX", c_644, c_156, c_data_type, TRUE) PORT MAP (tb_end_vec(6)); + + tb_end <= '1' WHEN tb_end_vec=c_tb_end_vec ELSE '0'; + + p_tb_end : PROCESS + BEGIN + WAIT UNTIL tb_end='1'; + WAIT FOR 1 ns; + REPORT "Multi tb simulation finished." SEVERITY FAILURE; + WAIT; + END PROCESS; +END tb;