diff --git a/libraries/io/ddr/src/vhdl/io_ddr.vhd b/libraries/io/ddr/src/vhdl/io_ddr.vhd index 1df78c88cb69a91ba4d0aed2c3cbf28c23d1310c..99b6353aa67d05b4755298e24c7880f5dd4b7119 100644 --- a/libraries/io/ddr/src/vhdl/io_ddr.vhd +++ b/libraries/io/ddr/src/vhdl/io_ddr.vhd @@ -33,14 +33,13 @@ ENTITY io_ddr IS g_technology : NATURAL := c_tech_select_default; g_tech_ddr : t_c_tech_ddr; g_wr_data_w : NATURAL := 32; - g_wr_use_ctrl : BOOLEAN := FALSE; -- TRUE to allow filling the write FIFO by disabling flush after an EOP g_wr_fifo_depth : NATURAL := 128; -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO. g_rd_fifo_depth : NATURAL := 256; -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO. g_rd_data_w : NATURAL := 32; - g_flush_mode : STRING := "VAL"; -- "VAL", "SOP", "SYN" - g_flush_use_channel : BOOLEAN := FALSE; - g_flush_start_channel : NATURAL := 0; - g_flush_nof_channels : POSITIVE := 1 + g_wr_flush_mode : STRING := "VAL"; -- "VAL", "SOP", "SYN" + g_wr_flush_use_channel : BOOLEAN := FALSE; + g_wr_flush_start_channel : NATURAL := 0; + g_wr_flush_nof_channels : POSITIVE := 1 ); PORT ( -- DDR reference clock @@ -91,6 +90,10 @@ END io_ddr; ARCHITECTURE str OF io_ddr IS + CONSTANT c_wr_use_sync : BOOLEAN := sel_a_b(g_wr_flush_mode="SYN", TRUE, FALSE); + CONSTANT c_wr_use_ctrl : BOOLEAN := sel_a_b(g_wr_flush_mode="SOP", TRUE, FALSE); + CONSTANT c_wr_fifo_use_ctrl : BOOLEAN := c_wr_use_sync OR c_wr_use_ctrl; + CONSTANT c_ctlr_data_w : NATURAL := func_tech_ddr_ctlr_data_w(g_tech_ddr); CONSTANT c_wr_fifo_depth : NATURAL := g_wr_fifo_depth * (c_ctlr_data_w/g_wr_data_w); -- get FIFO depth at write side @@ -106,9 +109,13 @@ ARCHITECTURE str OF io_ddr IS SIGNAL wr_flush : STD_LOGIC := '0'; + SIGNAL wr_fifo_snk_in : t_dp_sosi; + SIGNAL wr_fifo_src_in : t_dp_siso; SIGNAL wr_fifo_src_out : t_dp_sosi := c_dp_sosi_rst; + SIGNAL wr_flush_snk_in : t_dp_sosi := c_dp_sosi_rst; + SIGNAL ctlr_wr_snk_out : t_dp_siso := c_dp_siso_rdy; -- default xon='1' SIGNAL ctlr_wr_snk_in : t_dp_sosi := c_dp_sosi_rst; @@ -124,11 +131,21 @@ BEGIN dvr_done <= i_dvr_done; dvr_wr_fifo_usedw <= wr_fifo_usedw; + p_wr_fifo_snk_in : PROCESS (wr_sosi) + BEGIN + wr_fifo_snk_in <= wr_sosi; + IF c_wr_use_sync=TRUE THEN + -- Work around : Transport sync via sop through the dp_fifo_dc_mixed_widths + wr_fifo_snk_in.sop <= wr_sosi.sync; + wr_fifo_snk_in.eop <= '0'; + END IF; + END PROCESS; + u_wr_fifo : ENTITY dp_lib.dp_fifo_dc_mixed_widths GENERIC MAP ( g_wr_data_w => g_wr_data_w, g_rd_data_w => c_ctlr_data_w, - g_use_ctrl => g_wr_use_ctrl, + g_use_ctrl => c_wr_fifo_use_ctrl, g_wr_fifo_size => c_wr_fifo_depth, g_wr_fifo_af_margin => c_wr_fifo_af_margin, g_rd_fifo_rl => 0 @@ -140,7 +157,7 @@ BEGIN rd_clk => ctlr_clk_in, snk_out => wr_siso, - snk_in => wr_sosi, + snk_in => wr_fifo_snk_in, wr_usedw => OPEN, rd_usedw => wr_fifo_usedw, @@ -149,12 +166,12 @@ BEGIN src_in => wr_fifo_src_in, src_out => wr_fifo_src_out ); - + u_dp_flush : ENTITY dp_lib.dp_flush GENERIC MAP ( g_ready_latency => 0, - g_framed_xon => g_wr_use_ctrl, -- stop flushing when wr_flush is low and a sop has arrived - g_framed_xoff => FALSE -- immediately start flushing when wr_flush goes high + g_framed_xon => c_wr_fifo_use_ctrl, -- stop flushing when wr_flush is low and a sop (or sync via sop) has arrived + g_framed_xoff => FALSE -- immediately start flushing when wr_flush goes high ) PORT MAP ( rst => ctlr_rst_in, @@ -169,12 +186,22 @@ BEGIN flush_en => wr_flush ); + p_wr_flush_snk_in : PROCESS (wr_fifo_src_out) + BEGIN + wr_flush_snk_in <= wr_fifo_src_out; + IF c_wr_use_sync=TRUE THEN + -- Work around : Transport sync via sop through the dp_fifo_dc_mixed_widths + wr_flush_snk_in.sync <= wr_fifo_src_out.sop; + wr_flush_snk_in.sop <= '0'; + END IF; + END PROCESS; + u_io_ddr_driver_flush_ctrl : ENTITY work.io_ddr_driver_flush_ctrl GENERIC MAP ( - g_mode => g_flush_mode, - g_use_channel => g_flush_use_channel, - g_start_channel => g_flush_start_channel, - g_nof_channels => g_flush_nof_channels + g_mode => g_wr_flush_mode, + g_use_channel => g_wr_flush_use_channel, + g_start_channel => g_wr_flush_start_channel, + g_nof_channels => g_wr_flush_nof_channels ) PORT MAP ( rst => ctlr_rst_in, @@ -185,7 +212,7 @@ BEGIN dvr_wr_not_rd => dvr_wr_not_rd, dvr_done => i_dvr_done, - wr_sosi => wr_fifo_src_out, + wr_sosi => wr_flush_snk_in, wr_flush => wr_flush ); diff --git a/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd b/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd index 90018df621a1f4eb2f3fbc609a32d5173c98ad38..23afd17eea03bac8629a54f6c212474170177c7f 100644 --- a/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd +++ b/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd @@ -44,12 +44,15 @@ USE dp_lib.dp_stream_pkg.ALL; USE technology_lib.technology_select_pkg.ALL; USE tech_ddr_lib.tech_ddr_pkg.ALL; -ENTITY tb_io_ddr IS +ENTITY tb_io_ddr IS + GENERIC ( + g_nof_repeat : NATURAL := 2; + g_wr_flush_mode : STRING := "SYN" -- "VAL", "SOP", "SYN" + ); END ENTITY tb_io_ddr; ARCHITECTURE str of tb_io_ddr IS - CONSTANT c_nof_repeat : NATURAL := 2; CONSTANT c_ctlr_ref_clk_period : TIME := 5 ns; -- 200 MHz CONSTANT c_dp_clk_period : TIME := 5000 ps; -- 200 MHz @@ -78,9 +81,9 @@ ARCHITECTURE str of tb_io_ddr IS CONSTANT c_rd_fifo_depth : NATURAL := 256; -- Frame size for sop/eop - CONSTANT c_wr_flush_mode : STRING := "SOP"; -- "VAL", "SOP", "SYN" - CONSTANT c_wr_use_ctrl : BOOLEAN := sel_a_b(c_wr_flush_mode="VAL", FALSE, TRUE); CONSTANT c_wr_frame_size : NATURAL := 32; + -- Sync period + CONSTANT c_wr_sync_period : NATURAL := 512; SIGNAL tb_end : STD_LOGIC := '0'; SIGNAL ctlr_ref_clk : STD_LOGIC := '0'; @@ -154,7 +157,7 @@ BEGIN -- After reset even when dvr_flush_en='0' then the write FIFO is flushed until the first write access is started proc_common_wait_some_cycles(ctlr_clk, 100); - FOR R IN 0 TO c_nof_repeat-1 LOOP + FOR R IN 0 TO g_nof_repeat-1 LOOP FOR I IN c_address_lo_arr'RANGE LOOP v_addr_lo := func_tech_ddr_dq_address(TO_DDR_CTLR_ADDRESS(4*c_address_lo_arr(I)) , c_tech_ddr); v_addr_hi := func_tech_ddr_dq_address(TO_DDR_CTLR_ADDRESS(4*c_address_lo_arr(I)+4*c_nof_address_arr(I)-1), c_tech_ddr); @@ -231,29 +234,39 @@ BEGIN p_sop_eop : PROCESS (diag_wr_src_out, wr_val_cnt) BEGIN + -- Default, fits g_wr_flush_mode="VAL" wr_src_out <= diag_wr_src_out; - wr_src_out.sop <= '0'; - wr_src_out.eop <= '0'; - IF wr_val_cnt MOD c_wr_frame_size = 0 THEN - wr_src_out.sop <= diag_wr_src_out.valid; - ELSIF wr_val_cnt MOD c_wr_frame_size = c_wr_frame_size-1 THEN - wr_src_out.eop <= diag_wr_src_out.valid; + + IF g_wr_flush_mode="SOP" THEN + wr_src_out.sop <= '0'; + wr_src_out.eop <= '0'; + IF wr_val_cnt MOD c_wr_frame_size = 0 THEN + wr_src_out.sop <= diag_wr_src_out.valid; + ELSIF wr_val_cnt MOD c_wr_frame_size = c_wr_frame_size-1 THEN + wr_src_out.eop <= diag_wr_src_out.valid; + END IF; + END IF; + + IF g_wr_flush_mode="SYN" THEN + wr_src_out.sync <= '0'; + IF wr_val_cnt MOD c_wr_sync_period = 0 THEN + wr_src_out.sync <= diag_wr_src_out.valid; + END IF; END IF; END PROCESS; u_io_ddr: ENTITY work.io_ddr GENERIC MAP( - g_technology => c_tech_select_default, - g_tech_ddr => c_tech_ddr, - g_wr_data_w => c_dp_data_w, - g_wr_use_ctrl => c_wr_use_ctrl, -- TRUE to allow filling the write FIFO by disabling flush after an EOP - g_wr_fifo_depth => c_wr_fifo_depth, -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO. - g_rd_fifo_depth => c_rd_fifo_depth, -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO. - g_rd_data_w => c_dp_data_w, - g_flush_mode => c_wr_flush_mode, -- "VAL", "SOP", "SYN" - g_flush_use_channel => FALSE, - g_flush_start_channel => 0, - g_flush_nof_channels => 1 + g_technology => c_tech_select_default, + g_tech_ddr => c_tech_ddr, + g_wr_data_w => c_dp_data_w, + g_wr_fifo_depth => c_wr_fifo_depth, -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO. + g_rd_fifo_depth => c_rd_fifo_depth, -- >=16 AND >g_tech_ddr.maxburstsize, defined at DDR side of the FIFO. + g_rd_data_w => c_dp_data_w, + g_wr_flush_mode => g_wr_flush_mode, + g_wr_flush_use_channel => FALSE, + g_wr_flush_start_channel => 0, + g_wr_flush_nof_channels => 1 ) PORT MAP ( -- DDR reference clock