diff --git a/applications/rdma_demo/libraries/rdma_packetiser/hdllib.cfg b/applications/rdma_demo/libraries/rdma_packetiser/hdllib.cfg new file mode 100644 index 0000000000000000000000000000000000000000..c449e83d95a91ecdf4244a1e792bbbc7ca5316ae --- /dev/null +++ b/applications/rdma_demo/libraries/rdma_packetiser/hdllib.cfg @@ -0,0 +1,22 @@ +hdl_lib_name = rdma_packetiser +hdl_library_clause_name = rdma_packetiser_lib +hdl_lib_uses_synth = common dp eth +hdl_lib_uses_sim = diag technology +hdl_lib_technology = + +synth_files = + src/vhdl/rdma_packetiser_pkg.vhd + src/vhdl/rdma_packetiser_assemble_header.vhd + +test_bench_files = + tb/vhdl/tb_rdma_packetiser_assemble_header.vhd + tb/vhdl/tb_tb_rdma_packetiser_assemble_header.vhd + +regression_test_vhdl = + tb/vhdl/tb_tb_rdma_packetiser_assemble_header.vhd + + +[modelsim_project_file] + +[quartus_project_file] + diff --git a/applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_assemble_header.vhd b/applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_assemble_header.vhd new file mode 100644 index 0000000000000000000000000000000000000000..e51876b7d4d5972fcb4e5f70adbbe29595b0f768 --- /dev/null +++ b/applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_assemble_header.vhd @@ -0,0 +1,195 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2023 +-- 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: Assembles the RDMA header at snk_in.sop +-- Description: +-- Generates a RoCEv2 header (ETH + UDP + IP + RDMA). See [1]. +-- Generics: +-- . g_use_immediate: When true, the immediate data field will be added to the +-- header. +-- . g_use_msg_cnt_as_immediate: When true, the message counter going from 0 to +-- "nof_msg" is used as immediate data. When false, the "immediate_data" +-- input port is used. +-- Signal inputs: +-- . immediate_data: Will be used as immediate data when +-- g_use_msg_cnt_as_immediate = False. +-- . block_len: Should be set to the length of the incoming data frame in octets. +-- . nof_packets_in_msg: Should be set to the desired amount of packets in a message. +-- . nof_msg: Should be set to the desired amount of messages, this determines the +-- address space aswell, see remarks. +-- . dma_len: The amount with which the address should increase every message, +-- this should be set to >= nof_packets_in_msg * block_len. +-- . start_address: The start address for the virtual_address field. +-- Remarks +-- . The hdr_fields_slv output is set one st_clk cycle after snk_in.sop and will +-- contain the RoCEv2 (RDMA over Converged Ethernet v2) header information for +-- the corresponding data frame. +-- . The virtual_address is set automatically by increasing it with dma_len every +-- new message. The virtual address is reset to "start_address" when the number +-- of messages has reached "nof_msg". Then the cycle repeats. +-- . The PSN field (= Packet Sequence Number) is set to LSBs of the incoming BSN. +-- This can be used to check the order or detect missing packets at the receiver. + +-- References: +-- . [1] https://support.astron.nl/confluence/x/3pKrB + +library IEEE, common_lib, dp_lib, eth_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_layers_pkg.all; + use common_lib.common_field_pkg.all; + use dp_lib.dp_stream_pkg.all; + use dp_lib.dp_components_pkg.all; + use eth_lib.eth_pkg.all; + use eth_lib.eth_tester_pkg.all; + use work.rdma_packetiser_pkg.all; + +entity rdma_packetiser_assemble_header is + generic ( + g_use_immediate : boolean := true; + g_use_msg_cnt_as_immediate : boolean := true + ); + port ( + -- Clocks and reset + st_clk : in std_logic; + st_rst : in std_logic; + + snk_in : in t_dp_sosi := c_dp_sosi_rst; + + hdr_fields_slv : out std_logic_vector(1023 downto 0) := (others => '0'); + + immediate_data : in std_logic_vector(c_rdma_packetiser_roce_imm_len * c_octet_w - 1 downto 0) := (others => '0'); + block_len : in std_logic_vector(c_halfword_w - 1 downto 0); -- in octets + nof_packets_in_msg : in std_logic_vector(c_word_w - 1 downto 0); + nof_msg : in std_logic_vector(c_word_w - 1 downto 0); + dma_len : in std_logic_vector(c_word_w - 1 downto 0); -- = block_len * nof_packets_in_msg + start_address : in std_logic_vector(c_longword_w - 1 downto 0) + ); +end rdma_packetiser_assemble_header; + +architecture str of rdma_packetiser_assemble_header is + constant c_hdr_field_arr : t_common_field_arr := sel_a_b(g_use_immediate, c_rdma_packetiser_roce_hdr_field_arr, c_rdma_packetiser_roce_no_imm_hdr_field_arr); + constant c_app_hdr_length : natural := sel_a_b(g_use_immediate, c_rdma_packetiser_roce_hdr_len, c_rdma_packetiser_roce_no_imm_hdr_len); + constant c_udp_app_hdr_length : natural := c_network_udp_header_len + c_app_hdr_length; + constant c_ip_udp_app_hdr_length : natural := c_network_ip_header_len + c_udp_app_hdr_length; + + type t_state is (s_first, s_middle, s_last); + type t_reg is record -- record to keep the registers organized. + state : t_state; + opcode : std_logic_vector(c_byte_w - 1 downto 0); + immediate_data : std_logic_vector(c_rdma_packetiser_roce_imm_len * c_octet_w - 1 downto 0); + psn : std_logic_vector(c_word_w - 1 downto 0); + virtual_address : unsigned(c_longword_w - 1 downto 0); + dma_len : unsigned(c_word_w - 1 downto 0); + p_cnt : natural; -- Packet count (0 to nof_packets_in_msg). + msg_cnt : natural; -- message count (0 to nof_msg). + udp_total_length : natural; + ip_total_length : natural; + nof_packets_in_msg : natural; + end record; + + constant c_reg_rst : t_reg := (s_first, (others => '1'), (others => '0'), (others => '0'), (others => '0'), (others => '0'), 0, 0, 0, 0, 0); + signal d, q : t_reg; +begin + q <= d when rising_edge(st_clk); + + -- State machine to derive RDMA header fields. + p_comb : process(st_rst, q, snk_in, nof_packets_in_msg, start_address, nof_msg, immediate_data, dma_len, block_len) + variable v : t_reg; + begin + v := q; + if snk_in.sop = '1' then + v.psn := resize_uvec(snk_in.bsn, c_word_w); + v.p_cnt := q.p_cnt + 1; + case q.state is + when s_first => -- wait to start a new message and set the first opcode. + v.p_cnt := 1; + if q.p_cnt >= v.nof_packets_in_msg then -- (re)set message counter and virtual address. + if q.msg_cnt >= to_uint(nof_msg) - 1 then + v.msg_cnt := 0; + else + v.msg_cnt := q.msg_cnt + 1; + v.virtual_address := q.virtual_address + q.dma_len; + end if; + end if; + + if v.nof_packets_in_msg = 1 then -- set opcode to write_only. + v.opcode := c_rdma_packetiser_opcode_uc_write_only; + if g_use_immediate then -- set opcode to write_only with immediate data. + v.opcode := c_rdma_packetiser_opcode_uc_write_only_imm; + end if; + elsif v.nof_packets_in_msg = 2 then -- set opcode to write_first. + v.state := s_last; -- next state is last as there are only 2 packets. + v.opcode := c_rdma_packetiser_opcode_uc_write_first; + elsif v.nof_packets_in_msg > 2 then + v.state := s_middle; + v.opcode := c_rdma_packetiser_opcode_uc_write_first; + end if; + + when s_middle => -- wait unitl the first packet is done and set next opcode. + v.opcode := c_rdma_packetiser_opcode_uc_write_middle; + if q.p_cnt >= v.nof_packets_in_msg - 2 then -- wait until last middle packet + v.state := s_last; + end if; + + when s_last => -- next packet must be last packet, set opcode. + v.state := s_first; + v.opcode := c_rdma_packetiser_opcode_uc_write_last; + if g_use_immediate then -- set opcode to write_last with immediate data + v.opcode := c_rdma_packetiser_opcode_uc_write_last_imm; + end if; + end case; + end if; + + if v.msg_cnt = 0 then -- set on new message + v.virtual_address := unsigned(start_address); + v.dma_len := unsigned(dma_len); + v.udp_total_length := c_udp_app_hdr_length + to_uint(block_len) + c_rdma_packetiser_roce_icrc_len; + v.ip_total_length := c_ip_udp_app_hdr_length + to_uint(block_len) + c_rdma_packetiser_roce_icrc_len; + v.nof_packets_in_msg := to_uint(nof_packets_in_msg); + v.immediate_data := immediate_data; + end if; + + if st_rst = '1' then + v := c_reg_rst; + end if; + + d <= v; + end process; + + hdr_fields_slv(field_hi(c_hdr_field_arr, "ip_total_length" ) downto field_lo(c_hdr_field_arr, "ip_total_length" )) <= TO_UVEC(q.ip_total_length, 16); + hdr_fields_slv(field_hi(c_hdr_field_arr, "udp_total_length" ) downto field_lo(c_hdr_field_arr, "udp_total_length" )) <= TO_UVEC(q.udp_total_length, 16); + hdr_fields_slv(field_hi(c_hdr_field_arr, "bth_opcode" ) downto field_lo(c_hdr_field_arr, "bth_opcode" )) <= q.opcode; + hdr_fields_slv(field_hi(c_hdr_field_arr, "bth_psn" ) downto field_lo(c_hdr_field_arr, "bth_psn" )) <= q.psn; + hdr_fields_slv(field_hi(c_hdr_field_arr, "reth_virtual_address") downto field_lo(c_hdr_field_arr, "reth_virtual_address")) <= std_logic_vector(q.virtual_address); + hdr_fields_slv(field_hi(c_hdr_field_arr, "reth_dma_length" ) downto field_lo(c_hdr_field_arr, "reth_dma_length" )) <= std_logic_vector(q.dma_len); + + gen_use_immediate : if g_use_immediate generate + gen_use_msg_cnt : if g_use_msg_cnt_as_immediate generate + hdr_fields_slv(field_hi(c_hdr_field_arr, "immediate_data") downto field_lo(c_hdr_field_arr, "immediate_data")) <= TO_UVEC(q.msg_cnt, 32); + end generate; + + gen_use_no_msg_cnt : if not g_use_msg_cnt_as_immediate generate + hdr_fields_slv(field_hi(c_hdr_field_arr, "immediate_data") downto field_lo(c_hdr_field_arr, "immediate_data")) <= q.immediate_data; + end generate; + end generate; +end str; diff --git a/applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_pkg.vhd b/applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_pkg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..bebc9205415d93fa2e33336d48b6a880852ae40c --- /dev/null +++ b/applications/rdma_demo/libraries/rdma_packetiser/src/vhdl/rdma_packetiser_pkg.vhd @@ -0,0 +1,272 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2023 +-- 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. vd Walle +-- Purpose: This package contains rdma_packetiser specific constants and/or functions +-- Description: See [1] for RDMA explanation. +-- References: +-- . [1] https://support.astron.nl/confluence/x/3pKrB +------------------------------------------------------------------------------- +library IEEE, common_lib; + use IEEE.std_logic_1164.all; + use common_lib.common_pkg.all; + use common_lib.common_mem_pkg.all; + use common_lib.common_field_pkg.all; + use common_lib.common_network_layers_pkg.all; + +package rdma_packetiser_pkg is + type t_rdma_packetiser_bth_header is record + opcode : std_logic_vector( 7 downto 0); + se : std_logic_vector( 0 downto 0); + m : std_logic_vector( 0 downto 0); + pad : std_logic_vector( 1 downto 0); + tver : std_logic_vector( 3 downto 0); + partition_key : std_logic_vector(15 downto 0); + fres : std_logic_vector( 0 downto 0); + bres : std_logic_vector( 0 downto 0); + reserved_a : std_logic_vector( 5 downto 0); + dest_qp : std_logic_vector(15 downto 0); + ack_req : std_logic_vector( 0 downto 0); + reserved_b : std_logic_vector( 6 downto 0); + psn : std_logic_vector(31 downto 0); + end record; + + type t_rdma_packetiser_reth_header is record + virtual_address : std_logic_vector(63 downto 0); + r_key : std_logic_vector(31 downto 0); + dma_length : std_logic_vector(31 downto 0); + end record; + + type t_rdma_packetiser_roce_header is record + eth : t_network_eth_header; + ip : t_network_ip_header; + udp : t_network_udp_header; + bth : t_rdma_packetiser_bth_header; + reth : t_rdma_packetiser_reth_header; + immediate_data : std_logic_vector(31 downto 0); + end record; + + constant c_rdma_packetiser_nof_octet_generate_100gbe : natural := 64; + constant c_rdma_packetiser_nof_octet_output_100gbe : natural := 64; + + -- hdr_field_sel bit selects where the hdr_field value is set: + -- . 0 = data path controlled, value is set in data path, so field_default() + -- is not used. + -- . 1 = MM controlled, value is set via MM or by the field_default(), so any + -- data path setting in eth_tester.vhd is not used. + -- Remarks: + -- . For constant values it is convenient to use MM controlled, because then + -- the field_default() is used that can be set here in + -- c_rdma_packetiser_hdr_field_arr. + -- . For reserved values it is convenient to use MM controlled, because then + -- in future they could still be changed via MM without having to recompile + -- the FW. + -- . Typically only use data path controlled if the value has to be set + -- dynamically, so dependent on the state of the FW. + -- . If a data path controlled field is not set in the FW, then it defaults + -- to 0 by declaring hdr_fields_in_arr with all 0. Hence e.g. udp_checksum + -- = 0 can be achieve via data path and default hdr_fields_in_arr = 0 or + -- via MM controlled and field_default(0). + + -- RoCEv2 header for RDMA operation with immediate data + -- ETH + IP + UDP + Base Transport Header (BTH) + RDMA Extended Transport Header (RETH) + Immediate Data + constant c_rdma_packetiser_roce_nof_hdr_fields : natural := 3 + 12 + 4 + 13 + 3 + 1; + constant c_rdma_packetiser_roce_hdr_field_sel : std_logic_vector(c_rdma_packetiser_roce_nof_hdr_fields - 1 downto 0) := "111" & "111011111001" & "0100" & "1111111111111" & "111" & "1"; + + constant c_rdma_packetiser_roce_hdr_field_arr : t_common_field_arr( + c_rdma_packetiser_roce_nof_hdr_fields - 1 downto 0) := ( + ( field_name_pad("eth_dst_mac" ), "RW", 48, field_default(0) ), -- set by M&C + ( field_name_pad("eth_src_mac" ), "RW", 48, field_default(0) ), -- set by M&C + ( field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), -- fixed + + ( field_name_pad("ip_version" ), "RW", 4, field_default(4) ), -- fixed + ( field_name_pad("ip_header_length" ), "RW", 4, field_default(5) ), -- fixed + ( field_name_pad("ip_services" ), "RW", 8, field_default(0) ), -- fixed + ( field_name_pad("ip_total_length" ), "RW", 16, field_default(0) ), -- set by data path + ( field_name_pad("ip_identification" ), "RW", 16, field_default(0) ), -- fixed + ( field_name_pad("ip_flags" ), "RW", 3, field_default(2) ), -- fixed + ( field_name_pad("ip_fragment_offset" ), "RW", 13, field_default(0) ), -- fixed + ( field_name_pad("ip_time_to_live" ), "RW", 8, field_default(127) ), -- fixed + ( field_name_pad("ip_protocol" ), "RW", 8, field_default(17) ), -- fixed + ( field_name_pad("ip_header_checksum" ), "RW", 16, field_default(0) ), -- set by data path + ( field_name_pad("ip_src_addr" ), "RW", 32, field_default(0) ), -- set by M&C + ( field_name_pad("ip_dst_addr" ), "RW", 32, field_default(0) ), -- set by M&C + + ( field_name_pad("udp_src_port" ), "RW", 16, field_default(0) ), -- set by M&C + ( field_name_pad("udp_dst_port" ), "RW", 16, field_default(0) ), -- set by M&C + ( field_name_pad("udp_total_length" ), "RW", 16, field_default(0) ), -- set by data path + ( field_name_pad("udp_checksum" ), "RW", 16, field_default(0) ), -- fixed + + ( field_name_pad("bth_opcode" ), "RW", 8, field_default(x"FF") ), -- set by data path + ( field_name_pad("bth_se" ), "RW", 1, field_default(0) ), -- set by M&C + ( field_name_pad("bth_m" ), "RW", 1, field_default(0) ), -- set by M&C + ( field_name_pad("bth_pad" ), "RW", 2, field_default(0) ), -- set by M&C + ( field_name_pad("bth_tver" ), "RW", 4, field_default(0) ), -- set by M&C + ( field_name_pad("bth_partition_key" ), "RW", 16, field_default(65535) ), -- set by M&C + ( field_name_pad("bth_fres" ), "RW", 1, field_default(0) ), -- set by M&C + ( field_name_pad("bth_bres" ), "RW", 1, field_default(0) ), -- set by M&C + ( field_name_pad("bth_reserved_a" ), "RW", 6, field_default(0) ), -- fixed + ( field_name_pad("bth_dest_qp" ), "RW", 16, field_default(0) ), -- set by M&C + ( field_name_pad("bth_ack_req" ), "RW", 1, field_default(0) ), -- set by M&C + ( field_name_pad("bth_reserved_b" ), "RW", 7, field_default(0) ), -- fixed + ( field_name_pad("bth_psn" ), "RW", 32, field_default(0) ), -- set by data path + + ( field_name_pad("reth_virtual_address"), "RW", 64, field_default(0) ), -- set by data path + ( field_name_pad("reth_r_key" ), "RW", 32, field_default(0) ), -- set by M&C + ( field_name_pad("reth_dma_length" ), "RW", 32, field_default(0) ), -- set by M&C + + ( field_name_pad("immediate_data" ), "RW", 32, field_default(0) ) -- set by data path or M&C + ); + constant c_rdma_packetiser_roce_reg_hdr_dat_addr_w : natural := ceil_log2(field_nof_words(c_rdma_packetiser_roce_hdr_field_arr, c_word_w)); + constant c_rdma_packetiser_roce_reg_hdr_dat_addr_span : natural := 2**c_rdma_packetiser_roce_reg_hdr_dat_addr_w; + + -- RoCEv2 header for RDMA operation without immediate data + -- ETH + IP + UDP + Base Transport Header (BTH) + RDMA Extended Transport Header (RETH), so no immediate data ("no_imm"). + constant c_rdma_packetiser_roce_no_imm_nof_hdr_fields : natural := 3 + 12 + 4 + 13 + 3; + constant c_rdma_packetiser_roce_no_imm_hdr_field_sel : std_logic_vector(c_rdma_packetiser_roce_no_imm_nof_hdr_fields - 1 downto 0) := "111" & "111011111001" & "0100" & "1111111111111" & "111"; + + constant c_rdma_packetiser_roce_no_imm_hdr_field_arr : t_common_field_arr( + c_rdma_packetiser_roce_no_imm_nof_hdr_fields - 1 downto 0) := ( + ( field_name_pad("eth_dst_mac" ), "RW", 48, field_default(0) ), -- set by M&C + ( field_name_pad("eth_src_mac" ), "RW", 48, field_default(0) ), -- set by M&C + ( field_name_pad("eth_type" ), "RW", 16, field_default(x"0800") ), -- fixed + + ( field_name_pad("ip_version" ), "RW", 4, field_default(4) ), -- fixed + ( field_name_pad("ip_header_length" ), "RW", 4, field_default(5) ), -- fixed + ( field_name_pad("ip_services" ), "RW", 8, field_default(0) ), -- fixed + ( field_name_pad("ip_total_length" ), "RW", 16, field_default(0) ), -- set by data path + ( field_name_pad("ip_identification" ), "RW", 16, field_default(0) ), -- fixed + ( field_name_pad("ip_flags" ), "RW", 3, field_default(2) ), -- fixed + ( field_name_pad("ip_fragment_offset" ), "RW", 13, field_default(0) ), -- fixed + ( field_name_pad("ip_time_to_live" ), "RW", 8, field_default(127) ), -- fixed + ( field_name_pad("ip_protocol" ), "RW", 8, field_default(17) ), -- fixed + ( field_name_pad("ip_header_checksum" ), "RW", 16, field_default(0) ), -- set by data path + ( field_name_pad("ip_src_addr" ), "RW", 32, field_default(0) ), -- set by M&C + ( field_name_pad("ip_dst_addr" ), "RW", 32, field_default(0) ), -- set by M&C + + ( field_name_pad("udp_src_port" ), "RW", 16, field_default(0) ), -- set by M&C + ( field_name_pad("udp_dst_port" ), "RW", 16, field_default(0) ), -- set by M&C + ( field_name_pad("udp_total_length" ), "RW", 16, field_default(0) ), -- set by data path + ( field_name_pad("udp_checksum" ), "RW", 16, field_default(0) ), -- fixed + + ( field_name_pad("bth_opcode" ), "RW", 8, field_default(x"FF") ), -- set by data path + ( field_name_pad("bth_se" ), "RW", 1, field_default(0) ), -- set by M&C + ( field_name_pad("bth_m" ), "RW", 1, field_default(0) ), -- set by M&C + ( field_name_pad("bth_pad" ), "RW", 2, field_default(0) ), -- set by M&C + ( field_name_pad("bth_tver" ), "RW", 4, field_default(0) ), -- set by M&C + ( field_name_pad("bth_partition_key" ), "RW", 16, field_default(65535) ), -- set by M&C + ( field_name_pad("bth_fres" ), "RW", 1, field_default(0) ), -- set by M&C + ( field_name_pad("bth_bres" ), "RW", 1, field_default(0) ), -- set by M&C + ( field_name_pad("bth_reserved_a" ), "RW", 6, field_default(0) ), -- fixed + ( field_name_pad("bth_dest_qp" ), "RW", 16, field_default(0) ), -- set by M&C + ( field_name_pad("bth_ack_req" ), "RW", 1, field_default(0) ), -- set by M&C + ( field_name_pad("bth_reserved_b" ), "RW", 7, field_default(0) ), -- fixed + ( field_name_pad("bth_psn" ), "RW", 32, field_default(0) ), -- set by data path + + ( field_name_pad("reth_virtual_address"), "RW", 64, field_default(0) ), -- set by data path + ( field_name_pad("reth_r_key" ), "RW", 32, field_default(0) ), -- set by M&C + ( field_name_pad("reth_dma_length" ), "RW", 32, field_default(0) ) -- set by M&C + ); + constant c_rdma_packetiser_roce_reg_no_imm_hdr_dat_addr_w : natural := ceil_log2(field_nof_words(c_rdma_packetiser_roce_no_imm_hdr_field_arr, c_word_w)); + constant c_rdma_packetiser_roce_reg_no_imm_hdr_dat_addr_span : natural := 2**c_rdma_packetiser_roce_reg_no_imm_hdr_dat_addr_w; + + constant c_rdma_packetiser_roce_hdr_len : natural := 32; -- octets + constant c_rdma_packetiser_roce_imm_len : natural := 4; -- octets + constant c_rdma_packetiser_roce_icrc_len : natural := 4; -- octets + constant c_rdma_packetiser_roce_no_imm_hdr_len : natural := c_rdma_packetiser_roce_hdr_len - c_rdma_packetiser_roce_imm_len; + + constant c_rdma_packetiser_opcode_uc_send_first : std_logic_vector := "001" & "00000"; + constant c_rdma_packetiser_opcode_uc_send_middle : std_logic_vector := "001" & "00001"; + constant c_rdma_packetiser_opcode_uc_send_last : std_logic_vector := "001" & "00010"; -- without immediate + constant c_rdma_packetiser_opcode_uc_send_last_imm : std_logic_vector := "001" & "00011"; -- with immediate + constant c_rdma_packetiser_opcode_uc_send_only : std_logic_vector := "001" & "00100"; -- without immediate + constant c_rdma_packetiser_opcode_uc_send_only_imm : std_logic_vector := "001" & "00101"; -- with immediate + constant c_rdma_packetiser_opcode_uc_write_first : std_logic_vector := "001" & "00110"; + constant c_rdma_packetiser_opcode_uc_write_middle : std_logic_vector := "001" & "00111"; + constant c_rdma_packetiser_opcode_uc_write_last : std_logic_vector := "001" & "01000"; -- without immediate + constant c_rdma_packetiser_opcode_uc_write_last_imm : std_logic_vector := "001" & "01001"; -- with immediate + constant c_rdma_packetiser_opcode_uc_write_only : std_logic_vector := "001" & "01010"; -- without immediate + constant c_rdma_packetiser_opcode_uc_write_only_imm : std_logic_vector := "001" & "01011"; -- with immediate + + function func_rdma_packetiser_map_header(hdr_fields_raw : std_logic_vector; use_immediate : boolean) return t_rdma_packetiser_roce_header; + +end rdma_packetiser_pkg; + +package body rdma_packetiser_pkg is + function func_rdma_packetiser_map_header(hdr_fields_raw : std_logic_vector; use_immediate : boolean) return t_rdma_packetiser_roce_header is + variable v : t_rdma_packetiser_roce_header; + constant c_hdr_field_arr : t_common_field_arr := sel_a_b(use_immediate, c_rdma_packetiser_roce_hdr_field_arr, c_rdma_packetiser_roce_no_imm_hdr_field_arr); + begin + -- eth header + v.eth.dst_mac := hdr_fields_raw(field_hi(c_hdr_field_arr, "eth_dst_mac") downto field_lo(c_hdr_field_arr, "eth_dst_mac")); + v.eth.src_mac := hdr_fields_raw(field_hi(c_hdr_field_arr, "eth_src_mac") downto field_lo(c_hdr_field_arr, "eth_src_mac")); + v.eth.eth_type := hdr_fields_raw(field_hi(c_hdr_field_arr, "eth_type") downto field_lo(c_hdr_field_arr, "eth_type")); + + -- ip header + v.ip.version := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_version") downto field_lo(c_hdr_field_arr, "ip_version")); + v.ip.header_length := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_header_length") downto field_lo(c_hdr_field_arr, "ip_header_length")); + v.ip.services := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_services") downto field_lo(c_hdr_field_arr, "ip_services")); + v.ip.total_length := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_total_length") downto field_lo(c_hdr_field_arr, "ip_total_length")); + v.ip.identification := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_identification") downto field_lo(c_hdr_field_arr, "ip_identification")); + v.ip.flags := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_flags") downto field_lo(c_hdr_field_arr, "ip_flags")); + v.ip.fragment_offset := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_fragment_offset") downto field_lo(c_hdr_field_arr, "ip_fragment_offset")); + v.ip.time_to_live := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_time_to_live") downto field_lo(c_hdr_field_arr, "ip_time_to_live")); + v.ip.protocol := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_protocol") downto field_lo(c_hdr_field_arr, "ip_protocol")); + v.ip.header_checksum := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_header_checksum") downto field_lo(c_hdr_field_arr, "ip_header_checksum")); + v.ip.src_ip_addr := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_src_addr") downto field_lo(c_hdr_field_arr, "ip_src_addr")); + v.ip.dst_ip_addr := hdr_fields_raw(field_hi(c_hdr_field_arr, "ip_dst_addr") downto field_lo(c_hdr_field_arr, "ip_dst_addr")); + + -- udp header + v.udp.src_port := hdr_fields_raw(field_hi(c_hdr_field_arr, "udp_src_port") downto field_lo(c_hdr_field_arr, "udp_src_port")); + v.udp.dst_port := hdr_fields_raw(field_hi(c_hdr_field_arr, "udp_dst_port") downto field_lo(c_hdr_field_arr, "udp_dst_port")); + v.udp.total_length := hdr_fields_raw(field_hi(c_hdr_field_arr, "udp_total_length") downto field_lo(c_hdr_field_arr, "udp_total_length")); + v.udp.checksum := hdr_fields_raw(field_hi(c_hdr_field_arr, "udp_checksum") downto field_lo(c_hdr_field_arr, "udp_checksum")); + + -- bth header + v.bth.opcode := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_opcode") downto field_lo(c_hdr_field_arr, "bth_opcode")); + v.bth.se := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_se") downto field_lo(c_hdr_field_arr, "bth_se")); + v.bth.m := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_m") downto field_lo(c_hdr_field_arr, "bth_m")); + v.bth.pad := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_pad") downto field_lo(c_hdr_field_arr, "bth_pad")); + v.bth.tver := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_tver") downto field_lo(c_hdr_field_arr, "bth_tver")); + v.bth.partition_key := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_partition_key") downto field_lo(c_hdr_field_arr, "bth_partition_key")); + v.bth.fres := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_fres") downto field_lo(c_hdr_field_arr, "bth_fres")); + v.bth.bres := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_bres") downto field_lo(c_hdr_field_arr, "bth_bres")); + v.bth.reserved_a := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_reserved_a") downto field_lo(c_hdr_field_arr, "bth_reserved_a")); + v.bth.dest_qp := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_dest_qp") downto field_lo(c_hdr_field_arr, "bth_dest_qp")); + v.bth.ack_req := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_ack_req") downto field_lo(c_hdr_field_arr, "bth_ack_req")); + v.bth.reserved_b := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_reserved_b") downto field_lo(c_hdr_field_arr, "bth_reserved_b")); + v.bth.psn := hdr_fields_raw(field_hi(c_hdr_field_arr, "bth_psn") downto field_lo(c_hdr_field_arr, "bth_psn")); + + -- reth header + v.reth.virtual_address := hdr_fields_raw(field_hi(c_hdr_field_arr, "reth_virtual_address") downto field_lo(c_hdr_field_arr, "reth_virtual_address")); + v.reth.r_key := hdr_fields_raw(field_hi(c_hdr_field_arr, "reth_r_key") downto field_lo(c_hdr_field_arr, "reth_r_key")); + v.reth.dma_length := hdr_fields_raw(field_hi(c_hdr_field_arr, "reth_dma_length") downto field_lo(c_hdr_field_arr, "reth_dma_length")); + + --immediate data + v.immediate_data := (others => '0'); + if use_immediate then + v.immediate_data := hdr_fields_raw(field_hi(c_hdr_field_arr, "immediate_data") downto field_lo(c_hdr_field_arr, "immediate_data")); + end if; + + return v; + end func_rdma_packetiser_map_header; + +end rdma_packetiser_pkg; diff --git a/applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_rdma_packetiser_assemble_header.vhd b/applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_rdma_packetiser_assemble_header.vhd new file mode 100644 index 0000000000000000000000000000000000000000..b6a19a3744ecbbf954656b5f6af1b60f151dd18d --- /dev/null +++ b/applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_rdma_packetiser_assemble_header.vhd @@ -0,0 +1,206 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2023 +-- 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. vd Walle +-- Purpose: +-- . test bench for rdma_packetiser_assemble_header +-- Description: +-- . Generates DP data using proc_dp_gen_block_data that streams into DUT. +-- . Verifies the resulting header field array comming from the DUT by +-- comparing to expected values. +-- . The generics can be used to test specific conditions. +-- . g_use_immediate: When true, the DUT will use the optional immediate data +-- field. +-- . g_use_msg_cnt_as_immediate: When true, the DUT will use the message count +-- value as immediate data. When false, the DUT sets the immediate data to +-- the value of the immediate_data input port. +-- . g_nof_rep: number of packets the TB should generate. +-- . g_frame_len: length of the data frames that the TB should generate. +-- . g_start_address: 64 bit value to use as a start address for the DUT +-- . g_nof_packets_in_msg: The number of packets the DUT should put in one +-- RDMA message. +-- . g_nof_msg: Number of RDMA messages the DUT should create. +------------------------------------------------------------------------------- + +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_mem_pkg.all; + use common_lib.common_network_layers_pkg.all; + use common_lib.tb_common_pkg.all; + use common_lib.tb_common_mem_pkg.all; + use dp_lib.tb_dp_pkg.all; + use dp_lib.dp_stream_pkg.all; + use work.rdma_packetiser_pkg.all; + +entity tb_rdma_packetiser_assemble_header is + generic ( + g_use_immediate : boolean := true; + g_use_msg_cnt_as_immediate : boolean := true; + g_nof_rep : natural := 60; + g_frame_len : natural := 15; + g_start_address : unsigned(c_longword_w - 1 downto 0) := (others => '0'); + g_nof_packets_in_msg : natural := 4; + g_nof_msg : natural := 3 + ); +end tb_rdma_packetiser_assemble_header; + +architecture tb of tb_rdma_packetiser_assemble_header is + constant c_dp_clk_period : time := 5 ns; -- 200 MHz + constant c_data_w : natural := c_word_w; + constant c_data_init : natural := 13; + constant c_hdr_fields_slv_rst : std_logic_vector(1023 downto 0) := (others => '0'); + constant c_rdma_hdr_len : natural := c_rdma_packetiser_roce_icrc_len + sel_a_b( + g_use_immediate, + c_rdma_packetiser_roce_hdr_len, c_rdma_packetiser_roce_no_imm_hdr_len); + constant c_block_len : natural := g_frame_len * (c_data_w / c_octet_w); + constant c_dma_len : natural := c_block_len * g_nof_packets_in_msg; + + signal tb_end : std_logic := '0'; + + signal dp_clk : std_logic := '1'; + signal dp_rst : std_logic; + + signal immediate_data : std_logic_vector(c_word_w - 1 downto 0) := X"89ABCDEF"; + signal block_len : std_logic_vector(c_halfword_w - 1 downto 0) := TO_UVEC(c_block_len, c_halfword_w); + signal nof_packets_in_msg : std_logic_vector(c_word_w - 1 downto 0) := TO_UVEC(g_nof_packets_in_msg, c_word_w); + signal nof_msg : std_logic_vector(c_word_w - 1 downto 0) := TO_UVEC(g_nof_msg, c_word_w); + signal dma_len : std_logic_vector(c_word_w - 1 downto 0) := TO_UVEC(c_dma_len, c_word_w); + signal start_address : std_logic_vector(c_longword_w - 1 downto 0) := std_logic_vector(g_start_address); + + signal hdr_fields_slv : std_logic_vector(1023 downto 0) := (others => '0'); + signal rx_rdma_header : t_rdma_packetiser_roce_header; + signal exp_rdma_header : t_rdma_packetiser_roce_header := func_rdma_packetiser_map_header(c_hdr_fields_slv_rst, g_use_immediate); + signal in_en : std_logic := '0'; + + signal snk_in : t_dp_sosi := c_dp_sosi_rst; + signal snk_out : t_dp_siso := c_dp_siso_rdy; +begin + dp_rst <= '1', '0' after c_dp_clk_period * 7; + dp_clk <= (not dp_clk) or tb_end after c_dp_clk_period / 2; + + rx_rdma_header <= func_rdma_packetiser_map_header(hdr_fields_slv, g_use_immediate ); + + p_dp_stimuli : process + begin + -- dp stimuli + proc_common_wait_until_low(dp_clk, dp_rst); + proc_common_wait_some_cycles(dp_clk, 100); + in_en <= '1'; + for rep in 0 to g_nof_rep - 1 loop + proc_dp_gen_block_data(1, true, c_data_w, c_data_w, c_data_init, 0, 0, g_frame_len, 0, 0, '0', TO_DP_BSN(rep), dp_clk, in_en, snk_out, snk_in); + end loop; + proc_common_wait_some_cycles(dp_clk, 100); + in_en <= '0'; + wait; + end process; + + -- check if values in rdma_packetiser_assemble_header match with expected values + p_verify_rdma_header : process + variable v_exp_ip_total_length : natural; + variable v_exp_udp_total_length : natural; + variable v_exp_bth_opcode : std_logic_vector(c_byte_w - 1 downto 0); + variable v_exp_bth_psn : natural; + variable v_exp_reth_virtual_address : unsigned(c_longword_w - 1 downto 0); + variable v_exp_reth_dma_length : natural; + variable v_exp_immediate_data : std_logic_vector(c_word_w - 1 downto 0); + variable v_p, v_m : natural := 0; + begin + for rep in 0 to g_nof_rep - 1 loop + proc_common_wait_until_high(dp_clk, snk_in.sop); -- wait for sop + + v_exp_ip_total_length := c_network_ip_header_len + c_network_udp_header_len + c_rdma_hdr_len + to_uint(block_len); + v_exp_udp_total_length := c_network_udp_header_len + c_rdma_hdr_len + to_uint(block_len); + v_exp_bth_psn := v_p; + v_exp_reth_virtual_address := g_start_address + to_unsigned((v_m mod g_nof_msg) * c_dma_len, c_longword_w); + v_exp_reth_dma_length := c_dma_len; + v_exp_immediate_data := sel_a_b(g_use_immediate, + sel_a_b(g_use_msg_cnt_as_immediate, to_uvec((v_m mod g_nof_msg), c_word_w), immediate_data), to_uvec(0, c_word_w)); + + -- determine expected opcode + if v_p mod g_nof_packets_in_msg = 0 then + v_exp_bth_opcode := c_rdma_packetiser_opcode_uc_write_first; + if g_nof_packets_in_msg = 1 and g_use_immediate then + v_exp_bth_opcode := c_rdma_packetiser_opcode_uc_write_only_imm; + elsif g_nof_packets_in_msg = 1 then + v_exp_bth_opcode := c_rdma_packetiser_opcode_uc_write_only; + end if; + elsif v_p mod g_nof_packets_in_msg = g_nof_packets_in_msg - 1 then + v_exp_bth_opcode := c_rdma_packetiser_opcode_uc_write_last; + if g_use_immediate then + v_exp_bth_opcode := c_rdma_packetiser_opcode_uc_write_last_imm; + end if; + else + v_exp_bth_opcode := c_rdma_packetiser_opcode_uc_write_middle; + end if; + + -- increase counters + v_p := v_p + 1; + v_m := v_p / g_nof_packets_in_msg; + + -- assign expected values to signal to view in wave window. + exp_rdma_header.ip.total_length <= to_uvec(v_exp_ip_total_length, c_halfword_w); + exp_rdma_header.udp.total_length <= to_uvec(v_exp_udp_total_length, c_halfword_w ); + exp_rdma_header.bth.opcode <= v_exp_bth_opcode; + exp_rdma_header.bth.psn <= to_uvec(v_exp_bth_psn, c_word_w); + exp_rdma_header.reth.virtual_address <= std_logic_vector(v_exp_reth_virtual_address); + exp_rdma_header.reth.dma_length <= to_uvec(v_exp_reth_dma_length, c_word_w); + exp_rdma_header.immediate_data <= v_exp_immediate_data; + proc_common_wait_some_cycles(dp_clk, 1); + + -- assert when header is not as expected. + assert rx_rdma_header = exp_rdma_header report "Wrong rx_rdma_header" severity error; + assert rx_rdma_header.ip.total_length = exp_rdma_header.ip.total_length report "Wrong rx_rdma_header.ip.total_length value" severity error; + assert rx_rdma_header.udp.total_length = exp_rdma_header.udp.total_length report "Wrong rx_rdma_header.udp.total_length value" severity error; + assert rx_rdma_header.bth.opcode = exp_rdma_header.bth.opcode report "Wrong rx_rdma_header.bth.opcode value" severity error; + assert rx_rdma_header.bth.psn = exp_rdma_header.bth.psn report "Wrong rx_rdma_header.bth.psn value" severity error; + assert rx_rdma_header.reth.virtual_address = exp_rdma_header.reth.virtual_address report "Wrong rx_rdma_header.reth.virtual_address value" severity error; + assert rx_rdma_header.reth.dma_length = exp_rdma_header.reth.dma_length report "Wrong rx_rdma_header.reth.dma_length value" severity error; + assert rx_rdma_header.immediate_data = exp_rdma_header.immediate_data report "Wrong rx_rdma_header.immediate_data value" severity error; + end loop; + + proc_common_wait_some_cycles(dp_clk, 100); + tb_end <= '1'; + wait; + end process; + + u_dut: entity work.rdma_packetiser_assemble_header + generic map ( + g_use_immediate => g_use_immediate, + g_use_msg_cnt_as_immediate => g_use_msg_cnt_as_immediate + ) + port map ( + st_clk => dp_clk, + st_rst => dp_rst, + + snk_in => snk_in, + hdr_fields_slv => hdr_fields_slv, + + immediate_data => immediate_data, + block_len => block_len, + nof_packets_in_msg => nof_packets_in_msg, + nof_msg => nof_msg, + dma_len => dma_len, + start_address => start_address + ); +end tb; diff --git a/applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_tb_rdma_packetiser_assemble_header.vhd b/applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_tb_rdma_packetiser_assemble_header.vhd new file mode 100644 index 0000000000000000000000000000000000000000..f660180caa85165c58e1994f55addcf8c66bdc66 --- /dev/null +++ b/applications/rdma_demo/libraries/rdma_packetiser/tb/vhdl/tb_tb_rdma_packetiser_assemble_header.vhd @@ -0,0 +1,61 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2023 +-- 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 vd Walle +-- Purpose: Verify multiple variations of tb_rdma_packetiser_assemble_header +-- Description: +-- Usage: +-- > as 3 +-- > run -all +------------------------------------------------------------------------------- + +library IEEE; + use IEEE.std_logic_1164.all; + use IEEE.numeric_std.all; + +entity tb_tb_rdma_packetiser_assemble_header is +end tb_tb_rdma_packetiser_assemble_header; + +architecture tb of tb_tb_rdma_packetiser_assemble_header is + constant c_low_start_addr : unsigned(63 downto 0) := X"000000000000BCDF"; -- arbitrary low start address + constant c_high_start_addr : unsigned(63 downto 0) := X"CBA9876543210000"; -- arbitrary high start address + signal tb_end : std_logic := '0'; -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end' +begin + -- All generics of TB + -- g_use_immediate : boolean := true; + -- g_use_msg_cnt_as_immediate : boolean := true; + -- g_nof_rep : natural := 15; + -- g_frame_len : natural := 15; + -- g_start_address : unsigned(c_longword_w - 1 downto 0) := (others => '0'); + -- g_nof_packets_in_msg : natural := 4; + -- g_nof_msg : natural := 3 + + u_lo_addr : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 20, 15, c_low_start_addr, 4, 5); + u_hi_addr : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 20, 15, c_high_start_addr, 4, 5); + u_no_mid : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 20, 15, c_high_start_addr, 2, 5); + u_wr_only : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 20, 15, c_high_start_addr, 1, 5); + u_large : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 10, 2000, c_low_start_addr, 3, 1); + u_no_imm_cnt : entity work.tb_rdma_packetiser_assemble_header generic map( false, true, 100, 15, c_low_start_addr, 4, 10); + u_no_cnt : entity work.tb_rdma_packetiser_assemble_header generic map( true, false, 20, 15, c_low_start_addr, 4, 5); + u_no_imm : entity work.tb_rdma_packetiser_assemble_header generic map( false, false, 30, 7, c_high_start_addr, 3, 2); + u_one : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 20, 1, c_low_start_addr, 1, 5); + u_many : entity work.tb_rdma_packetiser_assemble_header generic map( true, true, 6000, 3, c_low_start_addr, 5, 1000); +end tb;