diff --git a/libraries/base/dp/src/vhdl/dp_offload_tx.vhd b/libraries/base/dp/src/vhdl/dp_offload_tx.vhd index 5e152cdb62ce3a1d6e0fee73a0811ca3049c87c1..96c9109c44a0b78984d4e79f5bfdd81393f1a96f 100644 --- a/libraries/base/dp/src/vhdl/dp_offload_tx.vhd +++ b/libraries/base/dp/src/vhdl/dp_offload_tx.vhd @@ -29,7 +29,9 @@ -- interface is not used, the default settings passed via g_hdr_field_arr are used. -- . NOTE: dp_frame_rd DOES NOT SUPPORT 1 WORD FRAMES due to its separate s_sof and -- s_eof states. - +-- Remarks: +-- . Note that an output (fill) FIFO may be needed if the packets have gaps in them! +-- The Ethernet cores require this so an EOP-triggered FIFO may added to them. LIBRARY IEEE, common_lib, work, mm_lib; USE IEEE.STD_LOGIC_1164.ALL; @@ -50,7 +52,8 @@ ENTITY dp_offload_tx IS g_def_nof_blocks_per_packet : NATURAL; g_output_fifo_depth : NATURAL; g_hdr_field_arr : t_common_field_arr; - g_hdr_field_ovr_init : STD_LOGIC_VECTOR + g_hdr_field_ovr_init : STD_LOGIC_VECTOR; + g_use_post_split_fifo : BOOLEAN := FALSE ); PORT ( mm_rst : IN STD_LOGIC; @@ -84,6 +87,8 @@ ARCHITECTURE str OF dp_offload_tx IS CONSTANT c_dp_split_val_latency : NATURAL := 1; CONSTANT c_dp_packet_merge_val_latency : NATURAL := 2; CONSTANT c_nof_header_words : NATURAL := field_slv_len(g_hdr_field_arr) / g_data_w; + 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 dp_split_snk_in_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); SIGNAL dp_split_snk_out_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); @@ -91,8 +96,11 @@ ARCHITECTURE str OF dp_offload_tx IS SIGNAL dp_split_src_out_2arr : t_dp_sosi_2arr_2(g_nof_streams-1 DOWNTO 0); SIGNAL dp_split_src_in_2arr : t_dp_siso_2arr_2(g_nof_streams-1 DOWNTO 0); + SIGNAL dp_packet_merge_snk_in_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL dp_packet_merge_snk_out_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL dp_packet_merge_src_out_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); - SIGNAL dp_packet_merge_src_in_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy); + SIGNAL dp_packet_merge_src_in_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); 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); @@ -103,15 +111,15 @@ ARCHITECTURE str OF dp_offload_tx IS SIGNAL hdr_fields_in_piped_arr : t_slv_1024_arr(g_nof_streams-1 DOWNTO 0); SIGNAL hdr_fields_to_field_blk : t_slv_1024_arr(g_nof_streams-1 DOWNTO 0); - TYPE t_dp_fifo_sc_usedw_arr IS ARRAY(g_nof_streams-1 DOWNTO 0) OF STD_LOGIC_VECTOR(ceil_log2(g_output_fifo_depth)-1 DOWNTO 0); - SIGNAL dp_fifo_sc_usedw_arr : t_dp_fifo_sc_usedw_arr; +-- TYPE t_dp_fifo_sc_usedw_arr IS ARRAY(g_nof_streams-1 DOWNTO 0) OF STD_LOGIC_VECTOR(ceil_log2(g_output_fifo_depth)-1 DOWNTO 0); +-- SIGNAL dp_fifo_sc_usedw_arr : t_dp_fifo_sc_usedw_arr; - SIGNAL dp_frame_rd_frm_req_arr : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0); +-- SIGNAL dp_frame_rd_frm_req_arr : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0); - SIGNAL dp_frame_rd_snk_in_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); - SIGNAL dp_frame_rd_snk_out_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); +-- SIGNAL dp_frame_rd_snk_in_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); +-- SIGNAL dp_frame_rd_snk_out_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); - SIGNAL dp_frame_rd_src_out_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); +-- SIGNAL dp_frame_rd_src_out_arr : t_dp_sosi_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); @@ -130,13 +138,13 @@ ARCHITECTURE str OF dp_offload_tx IS TYPE t_nof_words_per_block_arr IS ARRAY(g_nof_streams-1 DOWNTO 0) OF STD_LOGIC_VECTOR(ceil_log2(g_max_nof_words_per_block+1)-1 DOWNTO 0); SIGNAL nof_words_per_block_arr : t_nof_words_per_block_arr; - SIGNAL nof_words_per_block_stat_arr : t_nof_words_per_block_arr; - SIGNAL nof_words_per_block_stat_piped_arr : t_nof_words_per_block_arr; +-- SIGNAL nof_words_per_block_stat_arr : t_nof_words_per_block_arr; +-- SIGNAL nof_words_per_block_stat_piped_arr : t_nof_words_per_block_arr; TYPE t_nof_blocks_per_packet_arr IS ARRAY(g_nof_streams-1 DOWNTO 0) OF STD_LOGIC_VECTOR(ceil_log2(g_max_nof_blocks_per_packet+1)-1 DOWNTO 0); SIGNAL nof_blocks_per_packet_arr : t_nof_blocks_per_packet_arr; - SIGNAL nof_blocks_per_packet_stat_arr : t_nof_blocks_per_packet_arr; +-- SIGNAL nof_blocks_per_packet_stat_arr : t_nof_blocks_per_packet_arr; SIGNAL reg_mosi_arr : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0); SIGNAL reg_miso_arr : t_mem_miso_arr(g_nof_streams-1 DOWNTO 0); @@ -146,13 +154,13 @@ ARCHITECTURE str OF dp_offload_tx IS SIGNAL reg_hdr_ovr_mosi_arr : t_mem_mosi_arr(g_nof_streams-1 DOWNTO 0); SIGNAL reg_hdr_ovr_miso_arr : t_mem_miso_arr(g_nof_streams-1 DOWNTO 0); - - - - 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 dp_pipeline_hdr_fields_snk_in_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL dp_pipeline_hdr_fields_snk_out_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL dp_pipeline_hdr_fields_src_out_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + SIGNAL dp_pipeline_hdr_fields_src_in_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0); + BEGIN --------------------------------------------------------------------------------------- @@ -189,7 +197,7 @@ BEGIN clk => dp_clk, nof_symbols => nof_words_per_block_arr(i), - nof_symbols_out => nof_words_per_block_stat_arr(i), +-- nof_symbols_out => nof_words_per_block_stat_arr(i), snk_out => dp_split_snk_out_arr(i), snk_in => dp_split_snk_in_arr(i), @@ -202,6 +210,33 @@ BEGIN END GENERATE; + --------------------------------------------------------------------------------------- + -- Use a post-split FIFO when the source has no flow control and its inter-block gap + -- is shorter than required for the header to be inserted. + --------------------------------------------------------------------------------------- + gen_dp_fifo_sc : FOR i IN 0 TO sel_a_b(g_use_post_split_fifo, g_nof_streams-1, -1) GENERATE + u_dp_fifo_sc : ENTITY work.dp_fifo_sc + GENERIC MAP ( + g_data_w => g_data_w, + g_fifo_size => g_max_nof_words_per_block + ) + PORT MAP ( + rst => dp_rst, + clk => dp_clk, + + snk_in => dp_split_src_out_2arr(i)(1), + snk_out => dp_split_src_in_2arr(i)(1), + + src_out => dp_packet_merge_snk_in_arr(i), + src_in => dp_packet_merge_snk_out_arr(i) + ); + END GENERATE; + + no_dp_fifo_sc : FOR i IN 0 TO sel_a_b(g_use_post_split_fifo, -1, g_nof_streams-1) GENERATE + dp_packet_merge_snk_in_arr(i) <= dp_split_src_out_2arr(i)(1); + dp_split_src_in_2arr(i)(1) <= dp_packet_merge_snk_out_arr(i); + END GENERATE; + --------------------------------------------------------------------------------------- -- Merge nof_blocks_per_packet --------------------------------------------------------------------------------------- @@ -215,14 +250,18 @@ BEGIN clk => dp_clk, nof_pkt => nof_blocks_per_packet_arr(i), - nof_pkt_out => nof_blocks_per_packet_stat_arr(i), +-- nof_pkt_out => nof_blocks_per_packet_stat_arr(i), - snk_out => dp_split_src_in_2arr(i)(1), - snk_in => dp_split_src_out_2arr(i)(1), + snk_out => dp_packet_merge_snk_out_arr(i), + snk_in => dp_packet_merge_snk_in_arr(i), src_in => dp_packet_merge_src_in_arr(i), src_out => dp_packet_merge_src_out_arr(i) ); + + dp_concat_snk_in_2arr(i)(0) <= dp_packet_merge_src_out_arr(i); + dp_packet_merge_src_in_arr(i) <= dp_concat_snk_out_2arr(i)(0); + END GENERATE; --------------------------------------------------------------------------------------- @@ -242,168 +281,31 @@ BEGIN -- hdr_fields_in_piped_arr(i).............________X_________X_________X____ -- --------------------------------------------------------------------------------------- - gen_common_pipeline_hdr_fields_in_arr : FOR i IN 0 TO g_nof_streams-1 GENERATE - u_common_pipeline : ENTITY common_lib.common_pipeline - GENERIC MAP ( - g_pipeline => c_dp_split_val_latency + c_dp_packet_merge_val_latency, - g_in_dat_w => field_slv_len(g_hdr_field_arr), - g_out_dat_w => field_slv_len(g_hdr_field_arr) - ) - PORT MAP ( - rst => dp_rst, - clk => dp_clk, - in_dat => hdr_fields_in_arr(i)(field_slv_len(g_hdr_field_arr)-1 DOWNTO 0), - out_dat => hdr_fields_in_piped_arr(i)(field_slv_len(g_hdr_field_arr)-1 DOWNTO 0) - ); - END GENERATE; - --------------------------------------------------------------------------------------- - -- If the user defined internally used fields in g_hdr_field_arr, wire the corresponding - -- internal status signals to these header fields with the correct delay, so they are - -- valid at dp_packet_merge_src_out_arr(i).sop like the other header fields. - --------------------------------------------------------------------------------------- - gen_common_pipeline_stream : FOR i IN 0 TO g_nof_streams-1 GENERATE - u_common_pipeline : ENTITY common_lib.common_pipeline - GENERIC MAP ( - g_pipeline => c_dp_packet_merge_val_latency, - g_in_dat_w => ceil_log2(g_max_nof_words_per_block+1), - g_out_dat_w => ceil_log2(g_max_nof_words_per_block+1) - ) - PORT MAP ( - rst => dp_rst, - clk => dp_clk, - in_dat => nof_words_per_block_stat_arr(i), - out_dat => nof_words_per_block_stat_piped_arr(i) - ); - END GENERATE; - - gen_dp_offload_tx_len_calc_stream : FOR i IN 0 TO g_nof_streams-1 GENERATE - u_dp_offload_tx_len_calc : ENTITY work.dp_offload_tx_len_calc - GENERIC MAP ( - g_hdr_field_arr => g_hdr_field_arr, - g_data_w => g_data_w - ) - PORT MAP ( - rst => dp_rst, - clk => dp_clk, - - nof_words_per_block => nof_words_per_block_stat_piped_arr(i), - nof_blocks_per_packet => nof_blocks_per_packet_stat_arr(i), - - udp_total_length => udp_total_length_arr(i), - ip_total_length => ip_total_length_arr(i) - ); - END GENERATE; + gen_dp_pipeline_hdr_fields_in_arr : FOR i IN 0 TO g_nof_streams-1 GENERATE - p_overwrite_fields: PROCESS(nof_words_per_block_stat_piped_arr, hdr_fields_in_piped_arr, nof_blocks_per_packet_stat_arr, udp_total_length_arr, ip_total_length_arr) - BEGIN - hdr_fields_to_field_blk <= hdr_fields_in_piped_arr; - FOR i IN 0 TO g_nof_streams-1 LOOP - IF field_exists(g_hdr_field_arr, "nof_words_per_block") THEN - hdr_fields_to_field_blk(i)(field_hi(g_hdr_field_arr, "nof_words_per_block") DOWNTO field_lo(g_hdr_field_arr, "nof_words_per_block")) <= RESIZE_UVEC(nof_words_per_block_stat_piped_arr(i), field_size(g_hdr_field_arr, "nof_words_per_block")); - END IF; - IF field_exists(g_hdr_field_arr, "nof_blocks_per_packet") THEN - hdr_fields_to_field_blk(i)(field_hi(g_hdr_field_arr, "nof_blocks_per_packet") DOWNTO field_lo(g_hdr_field_arr, "nof_blocks_per_packet")) <= RESIZE_UVEC(nof_blocks_per_packet_stat_arr(i), field_size(g_hdr_field_arr, "nof_blocks_per_packet")); - END IF; - IF field_exists(g_hdr_field_arr, "udp_total_length") THEN - hdr_fields_to_field_blk(i)(field_hi(g_hdr_field_arr, "udp_total_length") DOWNTO field_lo(g_hdr_field_arr, "udp_total_length")) <= RESIZE_UVEC(udp_total_length_arr(i), field_size(g_hdr_field_arr, "udp_total_length")); - END IF; - IF field_exists(g_hdr_field_arr, "ip_total_length") THEN - hdr_fields_to_field_blk(i)(field_hi(g_hdr_field_arr, "ip_total_length") DOWNTO field_lo(g_hdr_field_arr, "ip_total_length")) <= RESIZE_UVEC(ip_total_length_arr(i), field_size(g_hdr_field_arr, "ip_total_length")); - END IF; - END LOOP; - END PROCESS; + -- FIXME - Put this DP bus on the entity instead of hdr_fields_in_arr. + dp_pipeline_hdr_fields_snk_in_arr(i).data(field_slv_len(g_hdr_field_arr)-1 DOWNTO 0) <= hdr_fields_in_arr(i)(field_slv_len(g_hdr_field_arr)-1 DOWNTO 0); + dp_pipeline_hdr_fields_snk_in_arr(i).valid <= snk_in_arr(i).sop; - --------------------------------------------------------------------------------------- - -- Frame buffer - --------------------------------------------------------------------------------------- - gen_dp_fifo_sc : FOR i IN 0 TO g_nof_streams-1 GENERATE - u_dp_fifo_sc_frame_buffer : ENTITY work.dp_fifo_sc + u_dp_pipeline : ENTITY work.dp_pipeline GENERIC MAP ( - g_data_w => g_data_w, - g_use_ctrl => TRUE, - g_fifo_size => g_output_fifo_depth + 10 + g_pipeline => c_dp_split_val_latency + c_dp_packet_merge_val_latency ) PORT MAP ( - rst => dp_rst, - clk => dp_clk, - - usedw => dp_fifo_sc_usedw_arr(i), - - snk_out => dp_packet_merge_src_in_arr(i), - snk_in => dp_packet_merge_src_out_arr(i), - - src_in => dp_frame_rd_snk_out_arr(i), - src_out => dp_frame_rd_snk_in_arr(i) - ); - - -- Release frame at EOP. Also release the frame when FIFO gets too full (if user - -- created packets that are too large) to prevent lockups. - dp_frame_rd_frm_req_arr(i) <= '1' WHEN TO_UINT(dp_fifo_sc_usedw_arr(i)) > g_output_fifo_depth ELSE dp_packet_merge_src_out_arr(i).eop; - --dp_frame_rd_frm_req_arr(i) <= dp_packet_merge_src_out_arr(i).eop; - - -- Xon bypasses dp_frame_rd here - dp_frame_rd_snk_out_arr(i).xon <= dp_concat_snk_out_2arr(i)(0).xon; + rst => dp_rst, + clk => dp_clk, - u_dp_frame_rd : ENTITY work.dp_frame_rd - GENERIC MAP ( - g_dat_w => g_data_w, - g_empty_w => 0, - g_channel_w => 0, - g_error_w => 0, - g_frm_cnt_max => g_max_nof_blocks_per_packet -- sufficient to ensure no frm_req are missed that would cause the FIFO to fill with frames and eventually overflow - ) - PORT MAP ( - rst => dp_rst, - clk => dp_clk, - - frm_req => dp_frame_rd_frm_req_arr(i), - frm_flush => '0', - frm_ack => OPEN, - frm_busy => OPEN, - frm_err => OPEN, - frm_done => OPEN, - - rd_req => dp_frame_rd_snk_out_arr(i).ready, - - rd_dat => dp_frame_rd_snk_in_arr(i).data(g_data_w-1 DOWNTO 0), - rd_sync => dp_frame_rd_snk_in_arr(i).sync, - rd_val => dp_frame_rd_snk_in_arr(i).valid, - rd_sof => dp_frame_rd_snk_in_arr(i).sop, - rd_eof => dp_frame_rd_snk_in_arr(i).eop, - - out_dat => dp_frame_rd_src_out_arr(i).data(g_data_w-1 DOWNTO 0), - out_sync => dp_frame_rd_src_out_arr(i).sync, - out_val => dp_frame_rd_src_out_arr(i).valid, - out_sof => dp_frame_rd_src_out_arr(i).sop, - out_eof => dp_frame_rd_src_out_arr(i).eop - ); + snk_in => dp_pipeline_hdr_fields_snk_in_arr(i), + snk_out => OPEN, --dp_pipeline_hdr_fields_snk_out_arr(i), -- snk_in is only valid at the SOP so we won't need this - -- dp_frame_rd does not have output flow control - -- . Depth: - -- . c_nof_header_words for dp_concat - -- . 12 to buffer during non-ready cycles of eth_hdr.vhd in eth.vhd - -- . g_output_fifo_depth to buffer when ethernet MAC itself is not ready and its input FIFO is almost full - -- . This is the same depth as the FIFO in front of dp_frame_rd... - -- . 10 as margin - u_dp_fifo_sc_flow_control : ENTITY work.dp_fifo_sc - GENERIC MAP ( - g_data_w => g_data_w, - g_use_ctrl => TRUE, - g_fifo_size => c_nof_header_words + 12 + g_output_fifo_depth + 10 - ) - PORT MAP ( - rst => dp_rst, - clk => dp_clk, - - snk_out => OPEN, - snk_in => dp_frame_rd_src_out_arr(i), - - src_in => dp_concat_snk_out_2arr(i)(0), - src_out => dp_concat_snk_in_2arr(i)(0) + src_out => dp_pipeline_hdr_fields_src_out_arr(i), + src_in => dp_pipeline_hdr_fields_src_in_arr(i) ); END GENERATE; +-- hdr_fields_to_field_blk(i)(field_slv_len(g_hdr_field_arr)-1 DOWNTO 0) <= dp_pipeline_hdr_fields_src_out_arr(i).data(field_slv_len(g_hdr_field_arr)-1 DOWNTO 0); + --------------------------------------------------------------------------------------- -- Create header block & concatenate header to offload stream. -- . hdr_fields_in_arr(i) is clocked in at snk_in_arr(i).sop after which it can be @@ -411,8 +313,12 @@ BEGIN --------------------------------------------------------------------------------------- gen_dp_field_blk : FOR i IN 0 TO g_nof_streams-1 GENERATE - dp_field_blk_snk_in_arr(i).data(c_dp_field_blk_snk_data_w-1 DOWNTO 0) <= hdr_fields_to_field_blk(i)(field_slv_len(g_hdr_field_arr)-1 DOWNTO 0); - dp_field_blk_snk_in_arr(i).valid <= dp_packet_merge_src_out_arr(i).sop; + -- Flow control for the header source. Should not be needed. + dp_pipeline_hdr_fields_src_in_arr(i) <= dp_field_blk_snk_out_arr(i); + +-- dp_field_blk_snk_in_arr(i).data(c_dp_field_blk_snk_data_w-1 DOWNTO 0) <= hdr_fields_to_field_blk(i)(field_slv_len(g_hdr_field_arr)-1 DOWNTO 0); +-- dp_field_blk_snk_in_arr(i).valid <= dp_packet_merge_src_out_arr(i).sop; + dp_field_blk_snk_in_arr(i) <= dp_pipeline_hdr_fields_src_out_arr(i); u_dp_field_blk : ENTITY work.dp_field_blk GENERIC MAP ( @@ -428,7 +334,8 @@ BEGIN mm_rst => mm_rst, mm_clk => mm_clk, - snk_in => dp_field_blk_snk_in_arr(i), + snk_in => dp_field_blk_snk_in_arr(i), -- Valid for only one cycle. + snk_out => dp_field_blk_snk_out_arr(i), -- slv_in => hdr_fields_to_field_blk(i)(field_slv_len(g_hdr_field_arr)-1 DOWNTO 0), -- slv_in_val => dp_packet_merge_src_out_arr(i).sop,