diff --git a/libraries/io/ddr/src/vhdl/io_ddr.vhd b/libraries/io/ddr/src/vhdl/io_ddr.vhd index 36f9ab5db6b01afa822bf00414e445e56c607e22..1df78c88cb69a91ba4d0aed2c3cbf28c23d1310c 100644 --- a/libraries/io/ddr/src/vhdl/io_ddr.vhd +++ b/libraries/io/ddr/src/vhdl/io_ddr.vhd @@ -37,7 +37,7 @@ ENTITY io_ddr IS 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 := "VALID"; -- "VALID", "SOP", "SYNC" + 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 @@ -63,6 +63,7 @@ ENTITY io_ddr IS dvr_end_addr : IN t_tech_ddr_addr; dvr_done : OUT STD_LOGIC; dvr_flush_en : IN STD_LOGIC := '0'; + dvr_wr_fifo_usedw : OUT STD_LOGIC_VECTOR(ceil_log2(g_wr_fifo_depth * (func_tech_ddr_ctlr_data_w(g_tech_ddr)/g_wr_data_w) )-1 DOWNTO 0); -- for monitoring purposes -- Write FIFO clock domain wr_clk : IN STD_LOGIC; @@ -105,12 +106,12 @@ ARCHITECTURE str OF io_ddr IS SIGNAL wr_flush : STD_LOGIC := '0'; + SIGNAL wr_fifo_src_in : t_dp_siso; + SIGNAL wr_fifo_src_out : 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; - SIGNAL flush_wr_siso : t_dp_siso; - SIGNAL flush_wr_sosi : t_dp_sosi := c_dp_sosi_rst; - SIGNAL ctlr_rd_src_in : t_dp_siso; SIGNAL ctlr_rd_src_out : t_dp_sosi := c_dp_sosi_rst; @@ -121,6 +122,7 @@ BEGIN ctlr_init_done <= i_ctlr_init_done; ctlr_rdy <= ctlr_miso.waitrequest_n; dvr_done <= i_dvr_done; + dvr_wr_fifo_usedw <= wr_fifo_usedw; u_wr_fifo : ENTITY dp_lib.dp_fifo_dc_mixed_widths GENERIC MAP ( @@ -144,8 +146,8 @@ BEGIN rd_usedw => wr_fifo_usedw, rd_emp => OPEN, - src_in => flush_wr_siso, - src_out => flush_wr_sosi + src_in => wr_fifo_src_in, + src_out => wr_fifo_src_out ); u_dp_flush : ENTITY dp_lib.dp_flush @@ -158,8 +160,8 @@ BEGIN rst => ctlr_rst_in, clk => ctlr_clk_in, - snk_in => flush_wr_sosi, - snk_out => flush_wr_siso, + snk_in => wr_fifo_src_out, + snk_out => wr_fifo_src_in, src_out => ctlr_wr_snk_in, src_in => ctlr_wr_snk_out, @@ -175,15 +177,15 @@ BEGIN g_nof_channels => g_flush_nof_channels ) PORT MAP ( - rst => wr_rst, - clk => wr_clk, + rst => ctlr_rst_in, + clk => ctlr_clk_in, dvr_flush_en => dvr_flush_en, dvr_en => dvr_en, dvr_wr_not_rd => dvr_wr_not_rd, dvr_done => i_dvr_done, - wr_sosi => wr_sosi, + wr_sosi => wr_fifo_src_out, 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 7f3534ad3db561b9ad89eb7c70d2569709f055ba..90018df621a1f4eb2f3fbc609a32d5173c98ad38 100644 --- a/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd +++ b/libraries/io/ddr/tb/vhdl/tb_io_ddr.vhd @@ -49,6 +49,8 @@ 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 @@ -71,6 +73,14 @@ ARCHITECTURE str of tb_io_ddr IS --CONSTANT c_dp_data_w : NATURAL := 32; CONSTANT c_dp_data_w : NATURAL := 256; CONSTANT c_dp_factor : NATURAL := c_ctlr_data_w/c_dp_data_w; + + CONSTANT c_wr_fifo_depth : NATURAL := 128; + 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; SIGNAL tb_end : STD_LOGIC := '0'; SIGNAL ctlr_ref_clk : STD_LOGIC := '0'; @@ -89,13 +99,17 @@ ARCHITECTURE str of tb_io_ddr IS SIGNAL dvr_en : STD_LOGIC; SIGNAL dvr_wr_not_rd : STD_LOGIC; SIGNAL dvr_done : STD_LOGIC; - SIGNAL dvr_flush_en : STD_LOGIC := '0'; + SIGNAL dvr_flush_en : STD_LOGIC; + SIGNAL dvr_wr_fifo_usedw : STD_LOGIC_VECTOR(ceil_log2(c_wr_fifo_depth * c_dp_factor)-1 DOWNTO 0); - SIGNAL wr_siso : t_dp_siso; - SIGNAL wr_sosi : t_dp_sosi; + SIGNAL diag_wr_src_in : t_dp_siso; + SIGNAL diag_wr_src_out : t_dp_sosi; + + SIGNAL wr_src_out : t_dp_sosi; + SIGNAL wr_val_cnt : NATURAL := 0; - SIGNAL rd_siso : t_dp_siso; - SIGNAL rd_sosi : t_dp_sosi; + SIGNAL diag_rd_snk_out : t_dp_siso; + SIGNAL diag_rd_snk_in : t_dp_sosi; SIGNAL src_diag_en : STD_LOGIC; SIGNAL src_val_cnt : STD_LOGIC_VECTOR(31 DOWNTO 0); @@ -123,6 +137,7 @@ BEGIN VARIABLE v_addr_hi : t_tech_ddr_addr; BEGIN tb_end <= '0'; + dvr_flush_en <= '0'; dvr_en <= '0'; src_diag_en <= '0'; dvr_wr_not_rd <= '0'; @@ -132,40 +147,56 @@ BEGIN proc_common_wait_until_high(ctlr_clk, ctlr_init_done); proc_common_wait_some_cycles(ctlr_clk, 2); -- Give the driver FSM a cycle to go into idle mode - -- START diagnostics source for write and sink for verify read - src_diag_en <= '1'; - snk_diag_en <= '1'; + -- Start diagnostics source for write and sink for verify read + src_diag_en <= '1'; + snk_diag_en <= '1'; - -- When dvr_flush_en='0' then the write FIFO is flushed until the first write access is started + -- 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 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); + FOR R IN 0 TO c_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); + + dvr_start_addr <= v_addr_lo; + dvr_end_addr <= v_addr_hi; + + -- START ACCESS + dvr_wr_not_rd <= c_wr_not_rd_arr(I); + dvr_en <= '1'; + proc_common_wait_some_cycles(ctlr_clk, 1); + dvr_en <= '0'; + + -- ACCESS DONE + proc_common_wait_until_lo_hi(ctlr_clk, dvr_done); + + IF c_wr_not_rd_arr(I)='0' THEN + expected_cnt <= expected_cnt + c_nof_address_arr(I)*c_dp_factor; + + ASSERT snk_diag_res_val = '1' REPORT "[ERROR] DIAG_RES INVALID!" SEVERITY FAILURE; + ASSERT snk_diag_res = '0' REPORT "[ERROR] NON-ZERO DIAG_RES!" SEVERITY FAILURE; + END IF; + END LOOP; - dvr_start_addr <= v_addr_lo; - dvr_end_addr <= v_addr_hi; + -- Stop diagnostics source and sink + src_diag_en <= '0'; + snk_diag_en <= '0'; - -- START ACCESS - dvr_wr_not_rd <= c_wr_not_rd_arr(I); - dvr_en <= '1'; + -- Flush the wr fifo + dvr_flush_en <= '1'; proc_common_wait_some_cycles(ctlr_clk, 1); - dvr_en <= '0'; - - -- ACCESS DONE - proc_common_wait_until_lo_hi(ctlr_clk, dvr_done); + dvr_flush_en <= '0'; - IF c_wr_not_rd_arr(I)='0' THEN - expected_cnt <= expected_cnt + c_nof_address_arr(I)*c_dp_factor; + proc_common_wait_some_cycles(ctlr_clk, 500); + ASSERT UNSIGNED(dvr_wr_fifo_usedw) = 0 REPORT "[ERROR] Write FIFO is flushed but not empty!" SEVERITY FAILURE; + ASSERT UNSIGNED(snk_val_cnt) = expected_cnt REPORT "[ERROR] Unexpected number of read data!" SEVERITY FAILURE; - ASSERT snk_diag_res_val = '1' REPORT "[ERROR] DIAG_RES INVALID!" SEVERITY FAILURE; - ASSERT snk_diag_res = '0' REPORT "[ERROR] NON-ZERO DIAG_RES!" SEVERITY FAILURE; - END IF; + -- Restart diagnostics source and sink + src_diag_en <= '1'; + snk_diag_en <= '1'; END LOOP; - proc_common_wait_some_cycles(ctlr_clk, 500); - ASSERT UNSIGNED(snk_val_cnt) = expected_cnt REPORT "[ERROR] Unexpected number of read data!" SEVERITY FAILURE; - REPORT "[OK] Test passed." SEVERITY NOTE; tb_end <= '1'; @@ -181,32 +212,55 @@ BEGIN rst => dp_rst, clk => dp_clk, - snk_out_arr(0) => rd_siso, - snk_in_arr(0) => rd_sosi, + snk_out_arr(0) => diag_rd_snk_out, + snk_in_arr(0) => diag_rd_snk_in, snk_diag_en(0) => snk_diag_en, snk_diag_md(0) => '1', snk_diag_res(0) => snk_diag_res, snk_diag_res_val(0) => snk_diag_res_val, snk_val_cnt(0) => snk_val_cnt, - src_out_arr(0) => wr_sosi, - src_in_arr(0) => wr_siso, + src_out_arr(0) => diag_wr_src_out, + src_in_arr(0) => diag_wr_src_in, src_diag_en(0) => src_diag_en, src_diag_md(0) => '1', src_val_cnt(0) => src_val_cnt ); + wr_val_cnt <= wr_val_cnt + 1 WHEN rising_edge(dp_clk) AND diag_wr_src_out.valid='1'; + + p_sop_eop : PROCESS (diag_wr_src_out, wr_val_cnt) + BEGIN + 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; + 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_rd_data_w => c_dp_data_w + 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 ) PORT MAP ( + -- DDR reference clock ctlr_ref_clk => ctlr_ref_clk, ctlr_ref_rst => ctlr_ref_rst, + -- DDR controller clock domain ctlr_clk_out => ctlr_clk, ctlr_rst_out => ctlr_rst, @@ -222,15 +276,18 @@ BEGIN dvr_start_addr => dvr_start_addr, dvr_end_addr => dvr_end_addr, dvr_flush_en => dvr_flush_en, + dvr_wr_fifo_usedw => dvr_wr_fifo_usedw, + -- Write FIFO clock domain wr_clk => dp_clk, wr_rst => dp_rst, - wr_sosi => wr_sosi, - wr_siso => wr_siso, + wr_sosi => wr_src_out, + wr_siso => diag_wr_src_in, - rd_sosi => rd_sosi, - rd_siso => rd_siso, + -- Read FIFO clock domain + rd_sosi => diag_rd_snk_in, + rd_siso => diag_rd_snk_out, rd_clk => dp_clk, rd_rst => dp_rst,