diff --git a/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/lofar2_unb2b_sdp_station_fsub/tb_lofar2_unb2b_sdp_station_fsub.vhd b/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/lofar2_unb2b_sdp_station_fsub/tb_lofar2_unb2b_sdp_station_fsub.vhd index de437129ff57f6349679bcde7be0a0e98c6d1875..a3955762ff3b7e47a03cb1ae08290e80e24fd54b 100644 --- a/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/lofar2_unb2b_sdp_station_fsub/tb_lofar2_unb2b_sdp_station_fsub.vhd +++ b/applications/lofar2/designs/lofar2_unb2b_sdp_station/revisions/lofar2_unb2b_sdp_station_fsub/tb_lofar2_unb2b_sdp_station_fsub.vhd @@ -462,7 +462,7 @@ BEGIN IF sp_subband_sst > c_eps AND v_power > c_eps THEN sp_subband_sst_crosstalk_snr_dB <= 10.0 * LOG10(sp_subband_sst / v_power); ELSIF g_read_all_SST THEN - REPORT "Wrong, zero crosstalk is unexpected for SP-" & NATURAL'IMAGE(g_sp) SEVERITY ERROR; + REPORT "Zero crosstalk for SP-" & NATURAL'IMAGE(g_sp) SEVERITY NOTE; END IF; proc_common_wait_some_cycles(tb_clk, 10); @@ -514,8 +514,8 @@ BEGIN IF g_read_all_SST THEN -- Verify expected SNR quality measures - ASSERT sp_subband_sst_leakage_snr_dB > c_exp_subband_sst_leakage_snr_dB REPORT "Wrong to much leakage for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; - ASSERT sp_subband_sst_crosstalk_snr_dB > c_exp_subband_sst_crosstalk_snr_dB REPORT "Wrong to much crosstalk for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; + ASSERT sp_subband_sst_leakage = 0.0 OR sp_subband_sst_leakage_snr_dB > c_exp_subband_sst_leakage_snr_dB REPORT "Wrong too much leakage for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; + ASSERT sp_subband_sst_crosstalk = 0.0 OR sp_subband_sst_crosstalk_snr_dB > c_exp_subband_sst_crosstalk_snr_dB REPORT "Wrong too much crosstalk for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; END IF; --------------------------------------------------------------------------- diff --git a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub.vhd b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub.vhd index 887768498a19716994c5b747cae0e18d55784de3..4d70659aa31bd72e71412a6e52368cb376123312 100644 --- a/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub.vhd +++ b/applications/lofar2/designs/lofar2_unb2c_sdp_station/revisions/lofar2_unb2c_sdp_station_fsub/tb_lofar2_unb2c_sdp_station_fsub.vhd @@ -444,7 +444,7 @@ BEGIN IF sp_subband_sst > c_eps AND v_power > c_eps THEN sp_subband_sst_crosstalk_snr_dB <= 10.0 * LOG10(sp_subband_sst / v_power); ELSIF g_read_all_SST THEN - REPORT "Wrong, zero crosstalk is unexpected for SP-" & NATURAL'IMAGE(g_sp) SEVERITY ERROR; + REPORT "Zero crosstalk for SP-" & NATURAL'IMAGE(g_sp) SEVERITY NOTE; END IF; proc_common_wait_some_cycles(tb_clk, 10); @@ -496,8 +496,8 @@ BEGIN IF g_read_all_SST THEN -- Verify expected SNR quality measures - ASSERT sp_subband_sst_leakage_snr_dB > c_exp_subband_sst_leakage_snr_dB REPORT "Wrong to much leakage for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; - ASSERT sp_subband_sst_crosstalk_snr_dB > c_exp_subband_sst_crosstalk_snr_dB REPORT "Wrong to much crosstalk for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; + ASSERT sp_subband_sst_leakage = 0.0 OR sp_subband_sst_leakage_snr_dB > c_exp_subband_sst_leakage_snr_dB REPORT "Wrong too much leakage for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; + ASSERT sp_subband_sst_crosstalk = 0.0 OR sp_subband_sst_crosstalk_snr_dB > c_exp_subband_sst_crosstalk_snr_dB REPORT "Wrong too much crosstalk for SP " & NATURAL'IMAGE(g_sp) SEVERITY ERROR; END IF; --------------------------------------------------------------------------- diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd index 12fec289c03515515ec61df6cfc36a27b47d0442..38214e72d7c3202a66b85fe2fed3e064fda6f004 100644 --- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd +++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd @@ -52,7 +52,8 @@ ENTITY ddrctrl IS g_nof_streams : NATURAL := 12; -- number of input streams g_data_w : NATURAL := 14; -- data with of input data vectors g_stop_percentage : NATURAL := 50; - g_block_size : NATURAL := 1024 + g_block_size : NATURAL := 1024; + g_burstsize : NATURAL := 64 ); PORT ( clk : IN STD_LOGIC := '0'; @@ -83,30 +84,51 @@ END ddrctrl; ARCHITECTURE str OF ddrctrl IS -- constant for readability - CONSTANT c_io_ddr_data_w : NATURAL := func_tech_ddr_ctlr_data_w( g_tech_ddr ); - CONSTANT c_wr_fifo_depth : NATURAL := 256; -- defined at DDR side of the FIFO, >=16 and independent of wr burst size, default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K - CONSTANT c_rd_fifo_depth : NATURAL := 256; -- defined at DDR side of the FIFO, >=16 AND > max number of rd burst sizes (so > c_rd_fifo_af_margin), default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K - CONSTANT c_rd_fifo_uw_w : NATURAL := ceil_log2(c_rd_fifo_depth*(func_tech_ddr_ctlr_data_w(g_tech_ddr)/c_io_ddr_data_w)); + CONSTANT c_io_ddr_data_w : NATURAL := func_tech_ddr_ctlr_data_w( g_tech_ddr ); -- 576 + CONSTANT c_wr_fifo_depth : NATURAL := 256; -- defined at DDR side of the FIFO, >=16 and independent of wr burst size, default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K + CONSTANT c_rd_fifo_depth : NATURAL := 256; -- defined at DDR side of the FIFO, >=16 AND > max number of rd burst sizes (so > c_rd_fifo_af_margin), default >= 256 because 32b*256 fits in 1 M9K so c_ctlr_data_w=256b will require 8 M9K + CONSTANT c_rd_fifo_uw_w : NATURAL := ceil_log2(c_rd_fifo_depth*(func_tech_ddr_ctlr_data_w(g_tech_ddr)/c_io_ddr_data_w)); + + CONSTANT c_adr_w : NATURAL := func_tech_ddr_ctlr_address_w(g_tech_ddr); -- the lengt of the address vector, for simulation this is smaller, otherwise the simulation would take to long, 27 + CONSTANT c_max_adr : NATURAL := 2**(c_adr_w)-1; -- the maximal address that is possible within the vector length of the address + CONSTANT c_bim : NATURAL := (c_max_adr*c_io_ddr_data_w)/(g_block_size*g_nof_streams*g_data_w); -- the amount of whole blocks that fit in memory. + CONSTANT c_adr_per_b : NATURAL := ((g_block_size*g_nof_streams*g_data_w)/c_io_ddr_data_w)+1; -- rounding error removes the amount of extra addresses. + + SIGNAL s_adr_per_b : NATURAL := c_adr_per_b; + + -- the amount of addresses used + CONSTANT c_nof_adr : NATURAL := c_bim*c_adr_per_b; + + SIGNAL s_nof_adr : NATURAL := c_nof_adr; + + -- the amount of overflow after one block is written + CONSTANT c_of_pb : NATURAL := (g_block_size*g_nof_streams*g_data_w)-(((g_block_size*g_nof_streams*g_data_w)/c_io_ddr_data_w)*c_io_ddr_data_w); -- amount of overflow after one block is written to memory + + CONSTANT c_aof_full_burst : NATURAL := c_nof_adr/g_burstsize; + CONSTANT c_last_burstsize : NATURAL := c_nof_adr-(c_aof_full_burst*g_burstsize); + + SIGNAL s_last_burstsize : NATURAL := c_last_burstsize; -- signals for connecting the components - SIGNAL ctrl_clk : STD_LOGIC; - SIGNAL ctrl_rst : STD_LOGIC; - SIGNAL out_of : NATURAL := 0; - SIGNAL out_sosi : t_dp_sosi := c_dp_sosi_init; - SIGNAL out_adr : NATURAL := 0; - SIGNAL dvr_mosi : t_mem_ctlr_mosi := c_mem_ctlr_mosi_rst; - SIGNAL dvr_miso : t_mem_ctlr_miso := c_mem_ctlr_miso_rst; - SIGNAL wr_sosi : t_dp_sosi := c_dp_sosi_init; - SIGNAL rd_siso : t_dp_siso := c_dp_siso_rst; - SIGNAL rd_sosi : t_dp_sosi := c_dp_sosi_init; - SIGNAL stop : STD_LOGIC; - SIGNAL rd_fifo_usedw: STD_LOGIC_VECTOR(c_rd_fifo_uw_w-1 DOWNTO 0); - SIGNAL rd_ready : STD_LOGIC; - SIGNAL inp_ds : NATURAL; - SIGNAL inp_bsn : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); - SIGNAL inp_bsn_adr : NATURAL; - SIGNAL outp_ds : NATURAL; - SIGNAL outp_bsn : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); + SIGNAL ctrl_clk : STD_LOGIC; + SIGNAL ctrl_rst : STD_LOGIC; + SIGNAL rst_ddrctrl_input : STD_LOGIC; + SIGNAL out_of : NATURAL := 0; + SIGNAL out_sosi : t_dp_sosi := c_dp_sosi_init; + SIGNAL out_adr : NATURAL := 0; + SIGNAL dvr_mosi : t_mem_ctlr_mosi := c_mem_ctlr_mosi_rst; + SIGNAL dvr_miso : t_mem_ctlr_miso := c_mem_ctlr_miso_rst; + SIGNAL wr_sosi : t_dp_sosi := c_dp_sosi_init; + SIGNAL rd_siso : t_dp_siso := c_dp_siso_rst; + SIGNAL rd_sosi : t_dp_sosi := c_dp_sosi_init; + SIGNAL stop : STD_LOGIC; + SIGNAL rd_fifo_usedw : STD_LOGIC_VECTOR(c_rd_fifo_uw_w-1 DOWNTO 0); + SIGNAL rd_ready : STD_LOGIC; + SIGNAL inp_ds : NATURAL; + SIGNAL inp_bsn_adr : NATURAL; + SIGNAL outp_ds : NATURAL; + SIGNAL outp_bsn : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); + SIGNAL data_stopped : STD_LOGIC; BEGIN @@ -117,21 +139,23 @@ BEGIN u_ddrctrl_input : ENTITY work.ddrctrl_input GENERIC MAP( g_tech_ddr => g_tech_ddr, - g_sim_model => g_sim_model, g_nof_streams => g_nof_streams, - g_data_w => g_data_w + g_data_w => g_data_w, + g_max_adr => c_nof_adr, + g_bim => c_bim, + g_of_pb => c_of_pb, + g_block_size => g_block_size ) PORT MAP( clk => clk, - rst => rst, + rst => rst_ddrctrl_input, in_sosi_arr => in_sosi_arr, in_stop => stop, - out_of => out_of, out_sosi => out_sosi, out_adr => out_adr, out_bsn_ds => inp_ds, - out_bsn => inp_bsn, - out_bsn_adr => inp_bsn_adr + out_bsn_adr => inp_bsn_adr, + out_data_stopped => data_stopped ); -- functions as a fifo buffer for input data into the sdram stick. also manages input to sdram stick. @@ -141,7 +165,7 @@ BEGIN g_technology => g_technology, g_tech_ddr => g_tech_ddr, g_cross_domain_dvr_ctlr => FALSE, - g_wr_data_w => c_io_ddr_data_w, + g_wr_data_w => c_io_ddr_data_w, g_wr_fifo_depth => c_wr_fifo_depth, g_rd_fifo_depth => c_rd_fifo_depth, g_rd_data_w => c_io_ddr_data_w, @@ -241,7 +265,11 @@ BEGIN g_rd_fifo_depth => c_rd_fifo_depth, g_rd_data_w => c_io_ddr_data_w, g_block_size => g_block_size, - g_rd_fifo_uw_w => c_rd_fifo_uw_w + g_rd_fifo_uw_w => c_rd_fifo_uw_w, + g_max_adr => c_nof_adr, + g_burstsize => g_burstsize, + g_last_burstsize => c_last_burstsize, + g_adr_per_b => c_adr_per_b ) PORT MAP( clk => clk, @@ -252,8 +280,9 @@ BEGIN inp_sosi => out_sosi, inp_adr => out_adr, inp_ds => inp_ds, - inp_bsn => inp_bsn, inp_bsn_adr => inp_bsn_adr, + inp_data_stopped => data_stopped, + rst_ddrctrl_input => rst_ddrctrl_input, -- io_ddr dvr_mosi => dvr_mosi, diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd index d553823455cd3b3a37c61c168c7201b39f02c91c..3f4cab12b7d991c5abd15ddc3fe2030bb5ff222e 100644 --- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd +++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd @@ -40,25 +40,30 @@ ENTITY ddrctrl_controller IS GENERIC ( g_tech_ddr : t_c_tech_ddr; g_stop_percentage : NATURAL := 50; - g_nof_streams : NATURAL; - g_out_data_w : NATURAL; - g_wr_data_w : NATURAL; - g_rd_fifo_depth : NATURAL; - g_rd_data_w : NATURAL; - g_block_size : NATURAL; - g_rd_fifo_uw_w : NATURAL + g_nof_streams : NATURAL; -- 12 + g_out_data_w : NATURAL; -- 14 + g_wr_data_w : NATURAL; -- 168 + g_rd_fifo_depth : NATURAL; -- 256 + g_rd_data_w : NATURAL; -- 256 + g_block_size : NATURAL; -- 1024 + g_rd_fifo_uw_w : NATURAL; -- 8 + g_max_adr : NATURAL; -- 16128 + g_burstsize : NATURAL; -- 64 + g_last_burstsize : NATURAL; -- 18 + g_adr_per_b : NATURAL -- 299 ); PORT ( clk : IN STD_LOGIC; rst : IN STD_LOGIC; -- ddrctrl_input - inp_of : IN NATURAL; - inp_sosi : IN t_dp_sosi; - inp_adr : IN NATURAL; - inp_ds : IN NATURAL; - inp_bsn : IN STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); - inp_bsn_adr : IN NATURAL; + inp_of : IN NATURAL; + inp_sosi : IN t_dp_sosi; + inp_adr : IN NATURAL; + inp_ds : IN NATURAL; + inp_bsn_adr : IN NATURAL; + inp_data_stopped : IN STD_LOGIC; + rst_ddrctrl_input : OUT STD_LOGIC; -- io_ddr dvr_mosi : OUT t_mem_ctlr_mosi; @@ -78,29 +83,40 @@ END ddrctrl_controller; ARCHITECTURE rtl OF ddrctrl_controller IS - CONSTANT c_burstsize : NATURAL := 64; -- max burstsize for max troughput - CONSTANT c_bitshift_adr : NATURAL := ceil_log2(c_burstsize); -- bitshift to make sure there is only a burst start at a interval of c_burstsize. + CONSTANT c_bitshift_w : NATURAL := ceil_log2(g_burstsize); -- bitshift to make sure there is only a burst start at a interval of c_burstsize. CONSTANT c_adr_w : NATURAL := func_tech_ddr_ctlr_address_w( g_tech_ddr ); -- the lengt of the address vector, for simulation this is smaller, otherwise the simulation would take to long, 27 - CONSTANT c_max_adr : NATURAL := 2**(c_adr_w)-1; -- the maximal address that is possible within the vector length of the address - CONSTANT c_pof_ma : NATURAL := (c_max_adr*(100-g_stop_percentage))/100; - CONSTANT c_zeros : STD_LOGIC_VECTOR(c_bitshift_adr-1 DOWNTO 0) := (OTHERS => '0'); + CONSTANT c_pof_ma : NATURAL := (((g_max_adr*(100-g_stop_percentage))/100)/g_adr_per_b)*g_adr_per_b; + + CONSTANT c_zeros : STD_LOGIC_VECTOR(c_bitshift_w-1 DOWNTO 0) := (OTHERS => '0'); -- constant for reading + + CONSTANT c_rd_data_w : NATURAL := g_nof_streams*g_out_data_w; -- 168 CONSTANT c_rest : NATURAL := c_rd_data_w-(g_wr_data_w mod c_rd_data_w); -- 96 - CONSTANT c_max_read_cnt : NATURAL := (c_max_adr+1)/c_burstsize; -- 256 + CONSTANT c_max_read_cnt : NATURAL := (g_max_adr+1)/g_burstsize; -- 256 + CONSTANT c_io_ddr_data_w : NATURAL := func_tech_ddr_ctlr_data_w(g_tech_ddr); -- 576 + CONSTANT c_proportion : NATURAL := (c_io_ddr_data_w/c_rd_data_w)+1; -- type for statemachine - TYPE t_state IS (RESET, WRITING, SET_STOP, STOP_WRITING, START_READING, READING, STOP_READING, IDLE); + TYPE t_state IS (RESET, WRITING, SET_STOP, STOP_WRITING, LAST_WRITE_BURST, START_READING, READING, STOP_READING, IDLE); -- record for readability TYPE t_reg IS RECORD -- state of program state : t_state; + started : STD_LOGIC; -- stopping signals + ready_for_set_stop : STD_LOGIC; stop_adr : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0); + last_adr_to_write_to : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0); + stop_burstsize : NATURAL; stopped : STD_LOGIC; + rst_ddrctrl_input : STD_LOGIC; + + -- writing signals + need_burst : STD_LOGIC; -- reading signals outp_ds : NATURAL; @@ -113,7 +129,7 @@ ARCHITECTURE rtl OF ddrctrl_controller IS wr_sosi : t_dp_sosi; END RECORD; - CONSTANT c_t_reg_init : t_reg := (RESET, TO_UVEC(c_max_adr, c_adr_w), '0', 0, (OTHERS => '0'), 0, '0', c_mem_ctlr_mosi_rst, c_dp_sosi_init); + CONSTANT c_t_reg_init : t_reg := (RESET, '0', '0', TO_UVEC(g_max_adr, c_adr_w), (OTHERS => '0'), 0, '1', '1', '0', 0, (OTHERS => '0'), 0, '0', c_mem_ctlr_mosi_rst, c_dp_sosi_init); -- signals for readability @@ -125,7 +141,7 @@ BEGIN q_reg <= d_reg WHEN rising_edge(clk); -- put the input data into c_v and fill the output vector from c_v - p_state : PROCESS(q_reg, rst, inp_of, inp_sosi, inp_adr, inp_ds, inp_bsn, inp_bsn_adr, dvr_miso, rd_fifo_usedw, stop_in) + p_state : PROCESS(q_reg, rst, inp_of, inp_sosi, inp_adr, inp_ds, inp_bsn_adr, inp_data_stopped, dvr_miso, rd_fifo_usedw, stop_in) VARIABLE v : t_reg := c_t_reg_init; @@ -137,22 +153,32 @@ BEGIN CASE q_reg.state IS WHEN RESET => v := c_t_reg_init; + v.dvr_mosi.burstbegin := '1'; + v.dvr_mosi.burstsize(dvr_mosi.burstsize'length-1 DOWNTO 0) := (OTHERS => '0'); + v.dvr_mosi.wr := '1'; + WHEN WRITING => - -- if adr mod c_burstsize = 0 + -- if adr mod g_burstsize = 0 -- this makes sure that only ones every 64 writes a writeburst is started. - IF TO_UVEC(inp_adr, c_adr_w)(c_bitshift_adr-1 DOWNTO 0) = c_zeros THEN + IF TO_UVEC(inp_adr, c_adr_w)(c_bitshift_w-1 DOWNTO 0) = c_zeros AND q_reg.dvr_mosi.burstbegin = '0'THEN + v.need_burst := '1'; + END IF; + IF dvr_miso.done = '1' AND q_reg.need_burst = '1' THEN v.dvr_mosi.burstbegin := '1'; - IF inp_adr = 0 THEN - v.dvr_mosi.address := TO_UVEC(c_max_adr-c_burstsize, dvr_mosi.address'length); + v.need_burst := '0'; + IF inp_adr < g_burstsize-1 THEN + v.dvr_mosi.address := TO_UVEC(g_max_adr-g_last_burstsize, dvr_mosi.address'length); + v.dvr_mosi.burstsize := TO_UVEC(g_last_burstsize, dvr_mosi.burstsize'length); ELSE - v.dvr_mosi.address := TO_UVEC(inp_adr-c_burstsize, dvr_mosi.address'length); + v.dvr_mosi.address := TO_UVEC(inp_adr-g_burstsize, dvr_mosi.address'length); + v.dvr_mosi.address(c_bitshift_w-1 DOWNTO 0) := c_zeros(c_bitshift_w-1 DOWNTO 0); -- makes sure that a burst is only started on a multiple of g_burstsize + v.dvr_mosi.burstsize := TO_UVEC(g_burstsize, dvr_mosi.burstsize'length); END IF; ELSE v.dvr_mosi.burstbegin := '0'; END IF; - v.dvr_mosi.burstsize := TO_UVEC(c_burstsize, dvr_mosi.burstsize'length); v.dvr_mosi.wr := '1'; v.dvr_mosi.rd := '0'; v.wr_sosi := inp_sosi; @@ -160,69 +186,125 @@ BEGIN WHEN SET_STOP => --setting a stop address dependend on the g_stop_percentage - IF inp_adr+c_pof_ma >= c_max_adr THEN - v.stop_adr(c_adr_w-1 DOWNTO c_bitshift_adr) := TO_UVEC(inp_adr-c_pof_ma, c_adr_w)(c_adr_w-1 DOWNTO c_bitshift_adr); + IF inp_adr+c_pof_ma >= g_max_adr THEN + v.stop_adr(c_adr_w-1 DOWNTO 0) := TO_UVEC(inp_adr-c_pof_ma, c_adr_w)(c_adr_w-1 DOWNTO 0); ELSE - v.stop_adr(c_adr_w-1 DOWNTO c_bitshift_adr) := TO_UVEC(inp_adr+c_pof_ma, c_adr_w)(c_adr_w-1 DOWNTO c_bitshift_adr); + v.stop_adr(c_adr_w-1 DOWNTO 0) := TO_UVEC(inp_adr+c_pof_ma, c_adr_w)(c_adr_w-1 DOWNTO 0); END IF; - v.stop_adr(c_bitshift_adr-1 DOWNTO 0) := c_zeros; + v.ready_for_set_stop := '0'; + v.last_adr_to_write_to(c_adr_w-1 DOWNTO c_bitshift_w) := v.stop_adr(c_adr_w-1 DOWNTO c_bitshift_w); + v.last_adr_to_write_to(c_bitshift_w-1 DOWNTO 0) := (OTHERS => '0'); + v.stop_burstsize := TO_UINT(v.stop_adr(c_adr_w-1 DOWNTO 0))-TO_UINT(v.last_adr_to_write_to); -- still a write cyle - -- if adr mod c_burstsize = 0 + -- if adr mod g_burstsize = 0 -- this makes sure that only ones every 64 writes a writeburst is started. - IF TO_UVEC(inp_adr, c_adr_w)(c_bitshift_adr-1 DOWNTO 0) = c_zeros THEN - v.dvr_mosi.burstbegin := '1'; - IF inp_adr = 0 THEN - v.dvr_mosi.address := TO_UVEC(c_max_adr-c_burstsize, dvr_mosi.address'length); + IF TO_UVEC(inp_adr, c_adr_w)(c_bitshift_w-1 DOWNTO 0) = c_zeros AND q_reg.dvr_mosi.burstbegin = '0'THEN + v.need_burst := '1'; + END IF; + IF dvr_miso.done = '1' AND q_reg.need_burst = '1' THEN + v.dvr_mosi.burstbegin := '1'; + v.need_burst := '0'; + IF inp_adr < g_burstsize-1 THEN + v.dvr_mosi.address := TO_UVEC(g_max_adr-g_last_burstsize, dvr_mosi.address'length); + v.dvr_mosi.burstsize := TO_UVEC(g_last_burstsize, dvr_mosi.burstsize'length); ELSE - v.dvr_mosi.address := TO_UVEC(inp_adr-c_burstsize, dvr_mosi.address'length); + v.dvr_mosi.address := TO_UVEC(inp_adr-g_burstsize, dvr_mosi.address'length); + v.dvr_mosi.address(c_bitshift_w-1 DOWNTO 0) := c_zeros(c_bitshift_w-1 DOWNTO 0); -- makes sure that a burst is only started on a multiple of g_burstsize + v.dvr_mosi.burstsize := TO_UVEC(g_burstsize, dvr_mosi.burstsize'length); END IF; ELSE - v.dvr_mosi.burstbegin := '0'; + v.dvr_mosi.burstbegin := '0'; END IF; - v.dvr_mosi.burstsize := TO_UVEC(c_burstsize, dvr_mosi.burstsize'length); - v.dvr_mosi.wr := '1'; - v.dvr_mosi.rd := '0'; - v.wr_sosi := inp_sosi; + v.dvr_mosi.wr := '1'; + v.dvr_mosi.rd := '0'; + v.wr_sosi := inp_sosi; WHEN STOP_WRITING => v.dvr_mosi.burstbegin := '0'; + v.stopped := '1'; -- wait until the write burst is finished - IF dvr_miso.done = '1' AND q_reg.dvr_mosi.burstbegin = '0' THEN - v.stopped := '1'; + IF inp_data_stopped = '0' THEN + v.state := STOP_WRITING; + ELSIF dvr_miso.done = '1' AND q_reg.dvr_mosi.burstbegin = '0' AND q_reg.need_burst = '0' THEN v.wr_sosi.valid := '0'; - v.dvr_mosi.flush := '1'; - v.state := START_READING; + v.state := LAST_WRITE_BURST; ELSE - v.state := STOP_WRITING; + v.state := STOP_WRITING; END IF; + -- still receiving write data. + -- if adr mod g_burstsize = 0 + -- this makes sure that only ones every 64 writes a writeburst is started. + IF TO_UVEC(inp_adr, c_adr_w)(c_bitshift_w-1 DOWNTO 0) = c_zeros AND q_reg.dvr_mosi.burstbegin = '0'THEN + v.need_burst := '1'; + END IF; + IF dvr_miso.done = '1' AND q_reg.need_burst = '1' THEN + v.dvr_mosi.burstbegin := '1'; + v.need_burst := '0'; + IF inp_adr < g_burstsize-1 THEN + v.dvr_mosi.address := TO_UVEC(g_max_adr-g_last_burstsize, dvr_mosi.address'length); + v.dvr_mosi.burstsize := TO_UVEC(g_last_burstsize, dvr_mosi.burstsize'length); + ELSE + v.dvr_mosi.address := TO_UVEC(inp_adr-g_burstsize, dvr_mosi.address'length); + v.dvr_mosi.address(c_bitshift_w-1 DOWNTO 0) := c_zeros(c_bitshift_w-1 DOWNTO 0); -- makes sure that a burst is only started on a multiple of g_burstsize + v.dvr_mosi.burstsize := TO_UVEC(g_burstsize, dvr_mosi.burstsize'length); + END IF; + ELSE + v.dvr_mosi.burstbegin := '0'; + END IF; + v.dvr_mosi.wr := '1'; + v.dvr_mosi.rd := '0'; + v.wr_sosi := inp_sosi; + + + WHEN LAST_WRITE_BURST => + + IF dvr_miso.done = '1' THEN + v.dvr_mosi.burstbegin := '1'; + v.dvr_mosi.address(c_adr_w-1 DOWNTO 0) := q_reg.last_adr_to_write_to(c_adr_w-1 DOWNTO 0); + v.dvr_mosi.burstsize := TO_UVEC(q_reg.stop_burstsize, dvr_mosi.burstsize'length); + v.state := START_READING; + ELSE + v.dvr_mosi.burstbegin := '0'; + v.state := LAST_WRITE_BURST; + END IF; + v.dvr_mosi.wr := '1'; + v.dvr_mosi.rd := '0'; + + + WHEN START_READING => - v.rd_burst_en := '1'; - v.dvr_mosi.wr := '0'; - v.dvr_mosi.rd := '1'; - v.outp_ds := inp_ds; + v.dvr_mosi.burstbegin := '0'; + v.rd_burst_en := '1'; + v.outp_ds := inp_ds; + v.read_cnt := 0; - FOR I IN 0 TO inp_bsn_adr+(c_max_adr-TO_UINT(q_reg.stop_adr)) LOOP -- takes a while WRONG, wil be fixed after L2SDP-705, 706, 707 and 708 + FOR I IN 0 TO inp_bsn_adr+(g_max_adr-TO_UINT(q_reg.stop_adr)) LOOP -- takes a while WRONG, wil be fixed after L2SDP-705, 706 and 70 IF v.outp_ds-c_rest <= 0 THEN v.outp_ds := v.outp_ds+c_rd_data_w-c_rest; ELSE v.outp_ds := v.outp_ds-c_rest; END IF; END LOOP; - v.outp_bsn := TO_UVEC(TO_UINT(inp_bsn), c_dp_stream_bsn_w); -- WRONG, wil be fixed after L2SDP-705, 706, 707 and 708 + v.outp_bsn := TO_UVEC(TO_UINT(inp_sosi.bsn), c_dp_stream_bsn_w); -- WRONG, wil be fixed after L2SDP-705, 706 and 707 v.state := READING; WHEN READING => -- rd_fifo needs a refil after rd_fifo_usedw <= 10 because of delays, if you wait until rd_fifo_usedw = 0 then you get an empty fifo which results in your outputs sosi.valid not being constatly valid. IF TO_UINT(rd_fifo_usedw) <= 10 AND dvr_miso.done = '1' AND q_reg.rd_burst_en = '1' AND dvr_miso.done = '1' THEN - IF TO_UINT(q_reg.stop_adr(c_adr_w-1 DOWNTO 0))+c_burstsize*q_reg.read_cnt >= c_max_adr THEN - v.dvr_mosi.address(c_adr_w-1 DOWNTO 0) := TO_UVEC((TO_UINT(q_reg.stop_adr(c_adr_w-1 DOWNTO 0))+c_burstsize*q_reg.read_cnt)-c_max_adr-1, c_adr_w); + v.dvr_mosi.burstbegin := '0'; + v.dvr_mosi.burstsize(dvr_mosi.burstsize'length-1 DOWNTO 0) := TO_UVEC(g_burstsize, dvr_mosi.burstsize'length); + v.dvr_mosi.wr := '0'; + v.dvr_mosi.rd := '1'; + v.outp_ds := inp_ds; + IF TO_UINT(q_reg.stop_adr(c_adr_w-1 DOWNTO 0))+g_burstsize*q_reg.read_cnt >= g_max_adr THEN + v.dvr_mosi.address(c_adr_w-1 DOWNTO 0) := TO_UVEC((TO_UINT(q_reg.stop_adr(c_adr_w-1 DOWNTO 0))+g_burstsize*q_reg.read_cnt)-g_max_adr-1, c_adr_w); ELSE - v.dvr_mosi.address(c_adr_w-1 DOWNTO 0) := TO_UVEC(TO_UINT(q_reg.stop_adr(c_adr_w-1 DOWNTO 0))+c_burstsize*q_reg.read_cnt, c_adr_w); + v.dvr_mosi.address(c_adr_w-1 DOWNTO 0) := TO_UVEC(TO_UINT(q_reg.stop_adr(c_adr_w-1 DOWNTO 0))+g_burstsize*q_reg.read_cnt, c_adr_w); END IF; v.dvr_mosi.burstbegin := '1'; v.read_cnt := v.read_cnt+1; @@ -237,17 +319,29 @@ BEGIN END IF; IF q_reg.read_cnt >= c_max_read_cnt THEN - v.state := IDLE; + v.state := STOP_READING; ELSE v.state := READING; END IF; + WHEN STOP_READING => + IF dvr_miso.done = '1' THEN + v.rst_ddrctrl_input := '0'; + v.stopped := '0'; + v.state := IDLE; + ELSE + v.state := STOP_READING; + END IF; + + + + WHEN IDLE => + v.wr_sosi.valid := '0'; -- the statemachine goes to Idle when its finished or when its waiting on other components. - WHEN OTHERS => v := c_t_reg_init; @@ -257,13 +351,18 @@ BEGIN IF q_reg.state = RESET OR q_reg.state = WRITING OR q_reg.state = SET_STOP OR q_reg.state = IDLE THEN IF stop_in = '1' THEN + v.ready_for_set_stop := '1'; + ELSIF q_reg.ready_for_set_stop = '1' AND inp_sosi.eop = '1' THEN v.state := SET_STOP; - ELSIF v.stop_adr = TO_UVEC(inp_adr, c_adr_w) AND v.stop_adr(c_bitshift_adr-1 DOWNTO 0) = c_zeros(c_bitshift_adr-1 DOWNTO 0) AND q_reg.stopped = '0' THEN + ELSIF v.stop_adr = TO_UVEC(inp_adr, c_adr_w) AND q_reg.stopped = '0' THEN v.state := STOP_WRITING; - ELSIF v.stopped = '1' THEN - v.state := IDLE; - ELSE + ELSIF v.stopped = '0' AND inp_sosi.valid = '1' AND q_reg.started = '1' THEN v.state := WRITING; + v.wr_sosi := inp_sosi; + ELSIF q_reg.stopped = '1' THEN + v.state := STOP_READING; + ELSE + v.state := IDLE; END IF; END IF; @@ -272,15 +371,21 @@ BEGIN v.state := RESET; END IF; + IF inp_sosi.eop = '1' THEN + v.started := '1'; + v.wr_sosi.valid := '1'; + END IF; + d_reg <= v; END PROCESS; -- fill outputs - dvr_mosi <= q_reg.dvr_mosi; - wr_sosi <= q_reg.wr_sosi; - stop_out <= q_reg.stopped; - outp_bsn <= q_reg.outp_bsn; - outp_ds <= q_reg.outp_ds; + dvr_mosi <= q_reg.dvr_mosi; + wr_sosi <= q_reg.wr_sosi; + stop_out <= q_reg.stopped; + outp_bsn <= q_reg.outp_bsn; + outp_ds <= q_reg.outp_ds; + rst_ddrctrl_input <= q_reg.rst_ddrctrl_input OR rst; END rtl; diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input.vhd index 6ed2ce9a94fc6a6e7aa84a8fbd1203d66a9e68df..208780472a0e4df9cfc607de8f8f3e87e0ffb783 100644 --- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input.vhd +++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input.vhd @@ -44,22 +44,24 @@ USE dp_lib.dp_stream_pkg.ALL; ENTITY ddrctrl_input IS GENERIC ( - g_tech_ddr : t_c_tech_ddr; -- type of memory - g_sim_model : BOOLEAN := TRUE; -- determens if this is a simulation - g_nof_streams : NATURAL := 12; -- number of input streams - g_data_w : NATURAL := 14 -- data with of input data vectors + g_tech_ddr : t_c_tech_ddr; -- type of memory + g_nof_streams : NATURAL := 12; -- number of input streams + g_data_w : NATURAL := 14; -- data with of input data vectors + g_max_adr : NATURAL; + g_bim : NATURAL; + g_of_pb : NATURAL; + g_block_size : NATURAL ); PORT ( clk : IN STD_LOGIC := '0'; rst : IN STD_LOGIC; in_sosi_arr : IN t_dp_sosi_arr; -- input data in_stop : IN STD_LOGIC; - out_of : OUT NATURAL; -- amount of internal overflow this output out_sosi : OUT t_dp_sosi; -- output data out_adr : OUT NATURAL; out_bsn_ds : OUT NATURAL; - out_bsn : OUT STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); - out_bsn_adr : OUT NATURAL + out_bsn_adr : OUT NATURAL; + out_data_stopped : OUT STD_LOGIC ); END ddrctrl_input; @@ -71,15 +73,12 @@ ARCHITECTURE str OF ddrctrl_input IS -- signals for connecting the components - SIGNAL data : STD_LOGIC_VECTOR(c_out_data_w-1 DOWNTO 0); - SIGNAL sosi : t_dp_sosi := c_dp_sosi_init; - SIGNAL a_of : NATURAL := 0; - SIGNAL bsn_p_rp : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); - SIGNAL bsn_rp_ac : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); - SIGNAL adr : NATURAL := 0; - SIGNAL bsn_wr : STD_LOGIC := '0'; - SIGNAL bsn_ds : NATURAL := 0; - SIGNAL valid : STD_LOGIC := '0'; + SIGNAL sosi_p_rp : t_dp_sosi := c_dp_sosi_init; + SIGNAL sosi_rp_ac : t_dp_sosi := c_dp_sosi_init; + SIGNAL adr : NATURAL := 0; + SIGNAL bsn_ds : NATURAL := 0; + SIGNAL valid : STD_LOGIC := '0'; + SIGNAL data_stopped_rp_ac : STD_LOGIC := '0'; BEGIN @@ -93,52 +92,45 @@ BEGIN ) PORT MAP( in_sosi_arr => in_sosi_arr, -- input data - out_data => data, -- output data - out_bsn => bsn_p_rp, -- output bsn - out_valid => valid + out_sosi => sosi_p_rp -- output data ); -- resizes the input data vector so that the output data vector can be stored into the ddr memory u_ddrctrl_input_repack : ENTITY work.ddrctrl_input_repack GENERIC MAP( - g_tech_ddr => g_tech_ddr, -- type of memory - g_in_data_w => c_out_data_w -- the input data with + g_tech_ddr => g_tech_ddr, -- type of memory + g_in_data_w => c_out_data_w, -- the input data with + g_bim => g_bim, + g_of_pb => g_of_pb, + g_block_size => g_block_size ) PORT MAP( clk => clk, rst => rst, - in_data => data, -- input data - in_bsn => bsn_p_rp, + in_sosi => sosi_p_rp, -- input data in_stop => in_stop, - in_adr => adr, - in_valid => valid, - out_of => a_of, -- amount of internal overflow - out_sosi => sosi, -- output data + out_sosi => sosi_rp_ac, -- output data out_bsn_ds => bsn_ds, -- amount of bits between adr [0] and sosi_arr[0][0] where bsn is assigned to - out_bsn => bsn_rp_ac, - out_bsn_wr => bsn_wr + out_data_stopped => data_stopped_rp_ac ); -- creates address by counting input valids u_ddrctrl_input_address_counter : ENTITY work.ddrctrl_input_address_counter GENERIC MAP( g_tech_ddr => g_tech_ddr, -- type of memory - g_sim_model => g_sim_model -- determens if this is a simulation + g_max_adr => g_max_adr ) PORT MAP( clk => clk, rst => rst, - in_sosi => sosi, -- input data - in_of => a_of, - in_bsn_wr => bsn_wr, + in_sosi => sosi_rp_ac, -- input data in_bsn_ds => bsn_ds, - in_bsn => bsn_rp_ac, + in_data_stopped => data_stopped_rp_ac, out_sosi => out_sosi, -- output data - out_of => out_of, out_adr => adr, out_bsn_adr => out_bsn_adr, out_bsn_ds => out_bsn_ds, - out_bsn => out_bsn + out_data_stopped => out_data_stopped ); END str; diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_address_counter.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_address_counter.vhd index 937b8858cc07672e343319285d9882a2de3b0191..916bbb2a18196a555303ca81f99dc0f79b188292 100644 --- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_address_counter.vhd +++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_address_counter.vhd @@ -1,173 +1,167 @@ -------------------------------------------------------------------------------- --- --- Copyright 2022 --- 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: Job van Wee --- Purpose: Creates address by counting input valids --- --- Description: --- The counter starts on the first valid = '1' clockcylce, the counter stops --- when valid = '0'. --- --- Remark: --- Use VHDL coding template from: --- https://support.astron.nl/confluence/display/SBe/VHDL+design+patterns+for+RTL+coding --- The maximum value of the address is determend by g_tech_ddr. - -LIBRARY IEEE, technology_lib, tech_ddr_lib, common_lib, dp_lib; -USE IEEE.std_logic_1164.ALL; -USE IEEE.numeric_std.ALL; -USE technology_lib.technology_pkg.ALL; -USE tech_ddr_lib.tech_ddr_pkg.ALL; -USE common_lib.common_pkg.ALL; -USE common_lib.common_mem_pkg.ALL; -USE dp_lib.dp_stream_pkg.ALL; - - -ENTITY ddrctrl_input_address_counter IS - GENERIC ( - g_tech_ddr : t_c_tech_ddr; -- type of memory - g_sim_model : BOOLEAN := TRUE -- determens if this is a simulation - ); - PORT ( - clk : IN STD_LOGIC; - rst : IN STD_LOGIC; - in_sosi : IN t_dp_sosi; -- input data - in_of : IN NATURAL; - in_bsn_wr : IN STD_LOGIC; - in_bsn_ds : IN NATURAL; - in_bsn : IN STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); - out_sosi : OUT t_dp_sosi := c_dp_sosi_init; -- output data - out_of : OUT NATURAL; - out_adr : OUT NATURAL; - out_bsn_adr : OUT NATURAL; - out_bsn_ds : OUT NATURAL; - out_bsn : OUT STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0) - ); -END ddrctrl_input_address_counter; - - -ARCHITECTURE rtl OF ddrctrl_input_address_counter IS - - -- constants for readability - CONSTANT c_data_w : NATURAL := func_tech_ddr_ctlr_data_w( g_tech_ddr ); -- the with of the input data and output data, 576 - CONSTANT c_adr_w : NATURAL := func_tech_ddr_ctlr_address_w( g_tech_ddr ); -- the lengt of the address vector, for simulation this is smaller, otherwise the simulation would take to long, 27 - CONSTANT c_max_adr : NATURAL := 2**(c_adr_w)-1; -- the maximal address that is possible within the vector length of the address - - -- type for statemachine - TYPE t_state IS (RESET, COUNTING, MAX, IDLE); - - -- record for readability - TYPE t_reg IS RECORD - state : t_state; - out_sosi : t_dp_sosi; - out_of : NATURAL; - out_bsn_adr : NATURAL; - out_bsn_ds : NATURAL; - out_bsn : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); - s_in_sosi : t_dp_sosi; - s_in_of : NATURAL; - s_in_bsn_wr : STD_LOGIC; - s_in_bsn_ds : NATURAL; - s_in_bsn : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); - s_adr : NATURAL; - END RECORD; - - CONSTANT c_t_reg_init : t_reg := (RESET, c_dp_sosi_init, 0, 0, 0, (OTHERS => '0'), c_dp_sosi_init, 0, '0', 0, (OTHERS => '0'), 0); - - - -- signals for readability - SIGNAL d_reg : t_reg := c_t_reg_init; - SIGNAL q_reg : t_reg := c_t_reg_init; - -BEGIN - - q_reg <= d_reg WHEN rising_edge(clk); - - -- Increments the address each time in_sosi.valid = '1', if address = c_max_adr the address is reset to 0. - p_adr : PROCESS(rst, in_sosi, in_of, q_reg) - - VARIABLE v : t_reg; - - BEGIN - v := q_reg; - - -- compensate for delay in ddrctrl_input_address_counter - v.out_sosi.data(c_data_w-1 DOWNTO 0) := q_reg.s_in_sosi.data(c_data_w - 1 DOWNTO 0); - v.out_sosi.valid := q_reg.s_in_sosi.valid; - v.out_of := q_reg.s_in_of; - v.out_bsn_ds := q_reg.s_in_bsn_ds; - v.out_bsn := q_reg.s_in_bsn; - v.s_in_sosi := in_sosi; - v.s_in_of := in_of; - v.s_in_bsn_wr := in_bsn_wr; - v.s_in_bsn_ds := in_bsn_ds; - v.s_in_bsn := in_bsn; - - - CASE q_reg.state IS - WHEN RESET => - v.s_adr := c_max_adr-1; -- when there is a reset the fifo in io_ddr always needs the first out_sosi.valid to stop flushing the data so the first data word always gets lost. if s_adr is set to 0 after a restart the word from s_adr 1 will be put at address 0 in memory. - - IF q_reg.s_in_bsn_wr = '1' THEN - v.out_bsn_adr := v.s_adr; - END IF; - - - WHEN COUNTING => - v.s_adr := q_reg.s_adr+1; - - IF q_reg.s_in_bsn_wr = '1' THEN - v.out_bsn_adr := v.s_adr; - END IF; - - - WHEN MAX => - v.s_adr := 0; - - IF q_reg.s_in_bsn_wr = '1' THEN - v.out_bsn_adr := v.s_adr; - END IF; - - - WHEN IDLE => - - END CASE; - - IF rst = '1' THEN - v.state := RESET; - ELSIF q_reg.s_adr = c_max_adr AND in_sosi.valid = '1' THEN - v.state := MAX; - ELSIF in_sosi.valid = '1' THEN - v.state := COUNTING; - ELSE - v.state := IDLE; - END IF; - - d_reg <= v; - END PROCESS; - - -- fill outputs - out_sosi <= q_reg.out_sosi; - out_of <= q_reg.out_of; - out_adr <= q_reg.s_adr; - out_bsn_adr <= q_reg.out_bsn_adr; - out_bsn_ds <= q_reg.out_bsn_ds; - out_bsn <= q_reg.out_bsn; - -END rtl; +------------------------------------------------------------------------------- +-- +-- Copyright 2022 +-- 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: Job van Wee +-- Purpose: Creates address by counting input valids +-- +-- Description: +-- The counter starts on the first valid = '1' clockcylce, the counter stops +-- when valid = '0'. +-- +-- Remark: +-- Use VHDL coding template from: +-- https://support.astron.nl/confluence/display/SBe/VHDL+design+patterns+for+RTL+coding +-- The maximum value of the address is determend by g_tech_ddr. + +LIBRARY IEEE, technology_lib, tech_ddr_lib, common_lib, dp_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE technology_lib.technology_pkg.ALL; +USE tech_ddr_lib.tech_ddr_pkg.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; + + +ENTITY ddrctrl_input_address_counter IS + GENERIC ( + g_tech_ddr : t_c_tech_ddr; -- type of memory + g_max_adr : NATURAL + ); + PORT ( + clk : IN STD_LOGIC; + rst : IN STD_LOGIC; + in_sosi : IN t_dp_sosi; -- input data + in_bsn_ds : IN NATURAL; + in_data_stopped : IN STD_LOGIC; + out_sosi : OUT t_dp_sosi := c_dp_sosi_init; -- output data + out_adr : OUT NATURAL; + out_bsn_adr : OUT NATURAL; + out_bsn_ds : OUT NATURAL; + out_data_stopped : OUT STD_LOGIC + ); +END ddrctrl_input_address_counter; + + +ARCHITECTURE rtl OF ddrctrl_input_address_counter IS + + -- constants for readability + CONSTANT c_data_w : NATURAL := func_tech_ddr_ctlr_data_w( g_tech_ddr ); -- the with of the input data and output data, 576 + + -- type for statemachine + TYPE t_state IS (RESET, COUNTING, MAX, IDLE); + + -- record for readability + TYPE t_reg IS RECORD + state : t_state; + bsn_passed : STD_LOGIC; + out_sosi : t_dp_sosi; + out_bsn_adr : NATURAL; + out_bsn_ds : NATURAL; + out_data_stopped : STD_LOGIC; + s_in_sosi : t_dp_sosi; + s_in_bsn_ds : NATURAL; + s_in_data_stopped : STD_LOGIC; + s_adr : NATURAL; + END RECORD; + + CONSTANT c_t_reg_init : t_reg := (RESET, '0', c_dp_sosi_init, 0, 0, '0', c_dp_sosi_init, 0, '0', 0); + + + -- signals for readability + SIGNAL d_reg : t_reg := c_t_reg_init; + SIGNAL q_reg : t_reg := c_t_reg_init; + +BEGIN + + q_reg <= d_reg WHEN rising_edge(clk); + + -- Increments the address each time in_sosi.valid = '1', if address = g_max_adr the address is reset to 0. + p_adr : PROCESS(rst, in_sosi, in_bsn_ds, in_data_stopped, q_reg) + + VARIABLE v : t_reg; + + BEGIN + v := q_reg; + + -- compensate for delay in ddrctrl_input_address_counter + v.out_sosi := q_reg.s_in_sosi; + v.out_bsn_ds := q_reg.s_in_bsn_ds; + v.out_data_stopped := q_reg.s_in_data_stopped; + v.s_in_sosi := in_sosi; + v.s_in_bsn_ds := in_bsn_ds; + v.s_in_data_stopped := in_data_stopped; + + + CASE q_reg.state IS + WHEN RESET => + v.s_adr := 0; + + IF q_reg.s_in_sosi.sop = '1' THEN + v.out_bsn_adr := v.s_adr; + END IF; + + + WHEN COUNTING => + v.s_adr := q_reg.s_adr+1; + + IF q_reg.s_in_sosi.sop = '1' THEN + v.out_bsn_adr := v.s_adr; + END IF; + + + WHEN MAX => + v.s_adr := 0; + + IF q_reg.s_in_sosi.sop = '1' THEN + v.out_bsn_adr := v.s_adr; + END IF; + + + WHEN IDLE => + -- after a reset skip the first data block so the ddr memory can initialize. + IF NOT(q_reg.s_in_sosi.bsn(c_dp_stream_bsn_w-1 DOWNTO 0) = in_sosi.bsn(c_dp_stream_bsn_w-1 DOWNTO 0)) THEN + v.bsn_passed := '1'; + END IF; + + + END CASE; + + IF rst = '1' THEN + v.state := RESET; + ELSIF q_reg.s_adr = g_max_adr-1 AND in_sosi.valid = '1' AND q_reg.bsn_passed = '1' THEN + v.state := MAX; + ELSIF in_sosi.valid = '1' AND q_reg.bsn_passed = '1' THEN + v.state := COUNTING; + ELSE + v.state := IDLE; + END IF; + + d_reg <= v; + END PROCESS; + + -- fill outputs + out_sosi <= q_reg.out_sosi; + out_adr <= q_reg.s_adr; + out_bsn_adr <= q_reg.out_bsn_adr; + out_bsn_ds <= q_reg.out_bsn_ds; + out_sosi.bsn <= q_reg.out_sosi.bsn; + out_data_stopped <= q_reg.out_data_stopped; + +END rtl; diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_pack.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_pack.vhd index b7ef245435ff6908561c50f1c807069a0a69c2e6..aab3f9e1be0368c57ad824f1cadda86d83e44197 100644 --- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_pack.vhd +++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_pack.vhd @@ -37,10 +37,8 @@ ENTITY ddrctrl_input_pack IS g_data_w : NATURAL := 14 -- data with of input data vectors ); PORT ( - in_sosi_arr : IN t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); -- input data - out_data : OUT STD_LOGIC_VECTOR((g_nof_streams*g_data_w)-1 DOWNTO 0); -- output data - out_bsn : OUT STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); -- output bsn - out_valid : OUT STD_LOGIC + in_sosi_arr : IN t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); -- input data + out_sosi : OUT t_dp_sosi := c_dp_sosi_init -- output data ); END ddrctrl_input_pack; @@ -51,15 +49,16 @@ BEGIN gen_extract_and_pack_data : FOR I IN 0 TO g_nof_streams-1 GENERATE p_generate : PROCESS(in_sosi_arr) IS BEGIN - out_data(g_data_w*(I+1)-1 DOWNTO g_data_w*I) <= in_sosi_arr(I).data(g_data_w-1 DOWNTO 0); + out_sosi.data(g_data_w*(I+1)-1 DOWNTO g_data_w*I) <= in_sosi_arr(I).data(g_data_w-1 DOWNTO 0); END PROCESS; END GENERATE; -- check if the input data is valid bij doing a and operation on all of them - out_valid <= func_dp_stream_arr_and(in_sosi_arr, "VALID"); - - - out_bsn <= in_sosi_arr(0).bsn(c_dp_stream_bsn_w-1 DOWNTO 0); - + out_sosi.valid <= func_dp_stream_arr_and(in_sosi_arr, "VALID"); + out_sosi.sop <= func_dp_stream_arr_and(in_sosi_arr, "SOP"); + out_sosi.eop <= func_dp_stream_arr_and(in_sosi_arr, "EOP"); + out_sosi.sync <= func_dp_stream_arr_and(in_sosi_arr, "SYNC"); + out_sosi.bsn <= in_sosi_arr(0).bsn; + END rtl; diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_repack.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_repack.vhd index d47b4278c46d4ff79f8948e2a7e8ce29f74b53a1..7b7a3ed0d98c5229929b4d25982b3aa41910a258 100644 --- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_repack.vhd +++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_input_repack.vhd @@ -37,21 +37,20 @@ USE tech_ddr_lib.tech_ddr_pkg.ALL; ENTITY ddrctrl_input_repack IS GENERIC ( g_tech_ddr : t_c_tech_ddr; -- type of memory - g_in_data_w : NATURAL := 168 -- the input data with + g_in_data_w : NATURAL := 168; -- the input data with + g_bim : NATURAL; + g_of_pb : NATURAL; + g_block_size : NATURAL ); PORT ( clk : IN STD_LOGIC; rst : IN STD_LOGIC; - in_data : IN STD_LOGIC_VECTOR(g_in_data_w-1 DOWNTO 0); -- input data - in_bsn : IN STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); -- input bsn + in_sosi : IN t_dp_sosi; -- input data in_stop : IN STD_LOGIC := '0'; - in_adr : IN NATURAL; - in_valid : IN STD_LOGIC; - out_of : OUT NATURAL := 0; -- amount of internal overflow this output out_sosi : OUT t_dp_sosi := c_dp_sosi_init; -- output data out_bsn_ds : OUT NATURAL := 0; - out_bsn : OUT STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); - out_bsn_wr : OUT STD_LOGIC := '0' + out_bsn_wr : OUT STD_LOGIC := '0'; + out_data_stopped : OUT STD_LOGIC := '0' ); END ddrctrl_input_repack; @@ -63,25 +62,26 @@ ARCHITECTURE rtl OF ddrctrl_input_repack IS CONSTANT k_c_v_w : NATURAL := c_out_data_w*2; -- the c_v data with, 2*576=1152 -- type for statemachine - TYPE t_state IS (OVERFLOW_OUTPUT, FILL_VECTOR, FIRST_OUTPUT, RESET, STOP); + TYPE t_state IS (OVERFLOW_OUTPUT, FILL_VECTOR, FIRST_OUTPUT, RESET, STOP, BSN); -- record for readability TYPE t_reg IS RECORD state : t_state; -- the state the process is currently in; c_v : STD_LOGIC_VECTOR(k_c_v_w-1 DOWNTO 0); -- the vector that stores the input data until the data is put into the output data vector c_v_count : NATURAL; -- the amount of times the c_v vector received data from the input since the last time it was filled completely - s_out_bsn_ds : NATURAL; - s_out_bsn : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); - output_passed : STD_LOGIC; -- this signal is to make sure that out_bsn_written only gets low after a write cycle, this is so that ddrctrl_address_counter can save the address at which the data corresponding to the bsn is saved - out_data_count : NATURAL; -- the amount of times the output data vector has been filled since the last time c_v was filled completely - out_bsn_written : STD_LOGIC; -- this signal gets high ones the out_bsn signal is updated, this is so in ddrctrl_input_address_counter the right address can be linked with the out_bsn signal - out_of : NATURAL; -- this is the amount of bits that the first data word(168) is shifted from the first bit in the data word(576) + a_of : NATURAL; -- this is the amount of bits that the first data word(168) is shifted from the first bit in the data word(576) + q_bsn : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); + q_sop : STD_LOGIC; + q_out_bsn_ds : NATURAL; + s_input_cnt : NATURAL; + out_of : NATURAL; + out_data_count : STD_LOGIC; -- the amount of times the output data vector has been filled since the last time c_v was filled completely out_sosi : t_dp_sosi; -- this is the sosi stream that contains the data out_bsn_ds : NATURAL; -- this is the amount of bits that the data corresponding to out_bsn is shifted from the first bit in that data word - out_bsn : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0); -- this is the bsn corresponding to the data in memory + out_data_stopped : STD_LOGIC; -- this signal is '1' when there is no more data comming form ddrctrl_input_pack END RECORD; - CONSTANT c_t_reg_init : t_reg := (RESET, (OTHERS => '0'), 0, 0, (OTHERS => '0'), '0', 0, '0', 0, c_dp_sosi_init, 0, (OTHERS => '0')); + CONSTANT c_t_reg_init : t_reg := (RESET, (OTHERS => '0'), 0, 0, (OTHERS => '0'), '0', 0, 0, 0, '0', c_dp_sosi_init, 0, '0'); -- signals for readability @@ -93,7 +93,7 @@ BEGIN q_reg <= d_reg WHEN rising_edge(clk); -- put the input data into c_v and fill the output vector from c_v - p_state : PROCESS(q_reg, rst,in_data, in_bsn, in_stop, in_adr, in_valid) + p_state : PROCESS(q_reg, rst, in_sosi, in_stop) VARIABLE v : t_reg; @@ -103,116 +103,142 @@ BEGIN CASE q_reg.state IS WHEN FILL_VECTOR => -- if the input data doesn't exceeds the output data vector width - v.c_v(g_in_data_w*(q_reg.c_v_count+1)+q_reg.out_of-1 DOWNTO g_in_data_w*q_reg.c_v_count+q_reg.out_of) := in_data(g_in_data_w-1 DOWNTO 0); -- fill c_v + v.c_v(g_in_data_w*(q_reg.c_v_count+1)+q_reg.out_of-1 DOWNTO g_in_data_w*q_reg.c_v_count+q_reg.out_of) := in_sosi.data(g_in_data_w-1 DOWNTO 0); -- fill c_v v.c_v_count := q_reg.c_v_count+1; -- increase the counter of c_v with 1 v.out_sosi.valid := '0'; -- out_sosi.valid 0 + v.s_input_cnt := q_reg.s_input_cnt+1; + v.out_sosi.sop := '0'; + v.out_sosi.eop := '0'; + v.out_data_stopped := '0'; + - -- BSN_INPUT - IF NOT (in_bsn = q_reg.s_out_bsn) THEN - v.s_out_bsn := in_bsn; -- a bsn number is saved when the bsn changes - IF g_in_data_w*q_reg.c_v_count+q_reg.out_of >= c_out_data_w THEN - v.s_out_bsn_ds := g_in_data_w*q_reg.c_v_count+q_reg.out_of-c_out_data_w; -- the amount of bits between word[0] and data[0] where data is the data with the bsn - ELSE - v.s_out_bsn_ds := g_in_data_w*q_reg.c_v_count+q_reg.out_of; -- the amount of bits between word[0] and data[0] where data is the data with the bsn - END IF; - v.out_bsn_written := '1'; -- a signal which indicates that a bsn is written in this word(576) so the address counter can save the corresponinding address. (there are delay in address counter so in_adr is not the same as the address of the word the data from the bsn is written to) - ELSIF q_reg.output_passed = '1' THEN - v.out_bsn_written := '0'; - v.output_passed := '0'; - END IF; IF rst = '1' THEN v.state := RESET; - ELSIF in_stop = '1' OR in_valid = '0' THEN + ELSIF in_stop = '1' OR in_sosi.valid = '0' THEN v.state := STOP; - ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*(v.out_data_count+1)) AND (v.out_data_count = 0) THEN + ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*1) AND (v.out_data_count = '0') THEN v.state := FIRST_OUTPUT; - ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*(v.out_data_count+1)) AND (v.out_data_count = 1) THEN + ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*2) AND (v.out_data_count = '1') THEN v.state := OVERFLOW_OUTPUT; ELSE v.state := FILL_VECTOR; END IF; + IF NOT (q_reg.q_bsn(c_dp_stream_bsn_w-1 DOWNTO 0) = in_sosi.bsn(c_dp_stream_bsn_w-1 DOWNTO 0)) THEN + v.s_input_cnt := 0; + v.state := BSN; + END IF; + WHEN FIRST_OUTPUT => -- if the input data exceeds output data vector width but not the c_v width - v.c_v(g_in_data_w*(q_reg.c_v_count+1)+q_reg.out_of-1 DOWNTO g_in_data_w*q_reg.c_v_count+q_reg.out_of) := in_data(g_in_data_w-1 DOWNTO 0); -- fill c_v + v.c_v(g_in_data_w*(q_reg.c_v_count+1)+q_reg.out_of-1 DOWNTO g_in_data_w*q_reg.c_v_count+q_reg.out_of) := in_sosi.data(g_in_data_w-1 DOWNTO 0); -- fill c_v v.c_v_count := q_reg.c_v_count+1; -- increase the counter of c_v with 1 v.out_sosi.data(c_out_data_w-1 DOWNTO 0) := v.c_v(c_out_data_w-1 DOWNTO 0); -- fill out_sosi.data with 1st part of c_v v.out_sosi.valid := '1'; -- out_sosi.valid 1 - v.out_data_count := q_reg.out_data_count+1; -- increase the counter of out_sosi.data with 1 + v.out_data_count := '1'; -- increase the counter of out_sosi.data with 1 + v.s_input_cnt := q_reg.s_input_cnt+1; + v.out_sosi.bsn(c_dp_stream_bsn_w-1 DOWNTO 0) := q_reg.q_bsn(c_dp_stream_bsn_w-1 DOWNTO 0); + v.out_bsn_ds := q_reg.q_out_bsn_ds; + v.out_sosi.sop := q_reg.q_sop; + v.out_sosi.eop := '0'; + v.out_data_stopped := '0'; - -- BSN_INPUT - IF NOT (in_bsn = q_reg.s_out_bsn) THEN - v.out_bsn := in_bsn; -- a bsn number is saved when the bsn changes - IF g_in_data_w*q_reg.c_v_count+q_reg.out_of >= c_out_data_w THEN - v.s_out_bsn_ds := g_in_data_w*q_reg.c_v_count+q_reg.out_of-c_out_data_w; -- the amount of bits between word[0] and data[0] where data is the data with the bsn - ELSE - v.s_out_bsn_ds := g_in_data_w*q_reg.c_v_count+q_reg.out_of; -- the amount of bits between word[0] and data[0] where data is the data with the bsn - END IF; - v.out_bsn_written := '1'; -- a signal which indicates that a bsn is written in this word(576) so the address counter can save the corresponinding address. (there are delay in address counter so in_adr is not the same as the address of the word the data from the bsn is written to) - v.output_passed := '1'; - END IF; - v.out_bsn_ds := v.s_out_bsn_ds; - v.out_bsn := v.s_out_bsn; - - IF q_reg.out_bsn_written = '1' THEN - v.output_passed := '1'; - END IF; IF rst = '1' THEN v.state := RESET; - ELSIF in_stop = '1' OR in_valid = '0' THEN + ELSIF in_stop = '1' OR in_sosi.valid = '0' THEN v.state := STOP; - ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*(v.out_data_count+1)) AND (v.out_data_count = 1) THEN + ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*2) THEN v.state := OVERFLOW_OUTPUT; ELSE v.state := FILL_VECTOR; END IF; + IF NOT (q_reg.q_bsn(c_dp_stream_bsn_w-1 DOWNTO 0) = in_sosi.bsn(c_dp_stream_bsn_w-1 DOWNTO 0)) THEN + v.s_input_cnt := 0; + v.state := BSN; + END IF; + WHEN OVERFLOW_OUTPUT => -- if the input data exceeds the output data vector width and the c_v width - v.out_of := q_reg.out_of+(g_in_data_w*(q_reg.c_v_count+1))-(c_out_data_w*(q_reg.out_data_count+1)); -- check how much overflow there is and safe it in out_of - v.c_v(k_c_v_w-1 DOWNTO k_c_v_w-(g_in_data_w-v.out_of)) := in_data(g_in_data_w-v.out_of-1 DOWNTO 0); -- fill the rest of c_v untill the end - v.c_v(v.out_of-1 DOWNTO 0) := in_data(g_in_data_w-1 DOWNTO g_in_data_w-v.out_of); -- fill the start of c_v untill the out_of + v.out_of := q_reg.out_of+(g_in_data_w*(q_reg.c_v_count+1))-(c_out_data_w*2); -- check how much overflow there is and safe it in out_of + v.c_v(k_c_v_w-1 DOWNTO k_c_v_w-(g_in_data_w-v.out_of)) := in_sosi.data(g_in_data_w-v.out_of-1 DOWNTO 0); -- fill the rest of c_v untill the end + v.c_v(v.out_of-1 DOWNTO 0) := in_sosi.data(g_in_data_w-1 DOWNTO g_in_data_w-v.out_of); -- fill the start of c_v untill the out_of v.out_sosi.data(c_out_data_w-1 DOWNTO 0) := v.c_v(k_c_v_w-1 DOWNTO c_out_data_w); -- fill out_sosi.data with 2nd part of c_v v.out_sosi.valid := '1'; -- out_sosi.valid 1 - v.c_v_count := 0; -- reset counter - v.out_data_count := 0; -- reset counter + v.c_v_count := 0; -- reset counter + v.out_data_count := '0'; -- reset counter + v.s_input_cnt := q_reg.s_input_cnt+1; + v.q_sop := '0'; + v.out_sosi.sop := '0'; + v.out_sosi.eop := '0'; + v.out_data_stopped := '0'; - -- BSN_INPUT - IF NOT (in_bsn = q_reg.s_out_bsn) THEN - v.out_bsn := in_bsn; -- a bsn number is saved when the bsn changes - IF g_in_data_w*q_reg.c_v_count+q_reg.out_of >= c_out_data_w THEN - v.s_out_bsn_ds := g_in_data_w*q_reg.c_v_count+q_reg.out_of-c_out_data_w; -- the amount of bits between word[0] and data[0] where data is the data with the bsn - ELSE - v.s_out_bsn_ds := g_in_data_w*q_reg.c_v_count+q_reg.out_of; -- the amount of bits between word[0] and data[0] where data is the data with the bsn - END IF; - v.out_bsn_written := '1'; -- a signal which indicates that a bsn is written in this word(576) so the address counter can save the corresponinding address. (there are delay in address counter so in_adr is not the same as the address of the word the data from the bsn is written to) - v.output_passed := '1'; + + IF rst = '1' THEN + v.state := RESET; + ELSIF in_stop = '1' OR in_sosi.valid = '0' THEN + v.state := STOP; + ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*1) THEN + v.state := FIRST_OUTPUT; + ELSE + v.state := FILL_VECTOR; END IF; - v.out_bsn_ds := v.s_out_bsn_ds; - v.out_bsn := v.s_out_bsn; - IF q_reg.out_bsn_written = '1' THEN - v.output_passed := '1'; + IF NOT (q_reg.q_bsn(c_dp_stream_bsn_w-1 DOWNTO 0) = in_sosi.bsn(c_dp_stream_bsn_w-1 DOWNTO 0)) THEN + v.s_input_cnt := 0; + v.state := BSN; END IF; + + WHEN BSN => + + v.c_v(k_c_v_w-1 DOWNTO ((g_in_data_w*q_reg.c_v_count)+q_reg.out_of)) := (OTHERS =>'0'); + IF ((g_in_data_w*q_reg.c_v_count)+q_reg.out_of < c_out_data_w*1) THEN + v.out_sosi.data(c_out_data_w-1 DOWNTO 0) := v.c_v(c_out_data_w-1 DOWNTO 0); -- fill out_sosi.data with 1st part of c_v + v.out_sosi.valid := '1'; -- out_sosi.valid 1 + ELSE + v.out_sosi.data(c_out_data_w-1 DOWNTO 0) := v.c_v(k_c_v_w-1 DOWNTO c_out_data_w); -- fill out_sosi.data with 2nd part of c_v + v.out_sosi.valid := '1'; -- out_sosi.valid 1 + END IF; + + -- BSN_INPUT + v.q_bsn := in_sosi.bsn; -- a bsn number is saved when the bsn changes + IF g_in_data_w*q_reg.c_v_count+q_reg.out_of >= c_out_data_w THEN + v.q_out_bsn_ds := g_in_data_w*q_reg.c_v_count+q_reg.out_of-c_out_data_w; -- the amount of bits between word[0] and data[0] where data is the data with the bsn + ELSE + v.q_out_bsn_ds := g_in_data_w*q_reg.c_v_count+q_reg.out_of; -- the amount of bits between word[0] and data[0] where data is the data with the bsn + END IF; + v.q_sop := '1'; -- a signal which indicates that a bsn is written in this word(576) so the address counter can save the corresponinding address. (there are delay in address counter so in_adr is not the same as the address of the word the data from the bsn is written to) + v.a_of := 0; + v.c_v(g_in_data_w-1 DOWNTO 0) := in_sosi.data(g_in_data_w-1 DOWNTO 0); -- fill c_v + v.c_v_count := 1; -- increase the counter of c_v with 1 + v.out_data_count := '0'; + v.out_sosi.eop := '1'; + + + IF rst = '1' THEN v.state := RESET; - ELSIF in_stop = '1' OR in_valid = '0' THEN + ELSIF in_stop = '1' OR in_sosi.valid = '0' THEN v.state := STOP; - ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*(v.out_data_count+1)) AND (v.out_data_count = 0) THEN + ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*1) AND (v.out_data_count = '0') THEN v.state := FIRST_OUTPUT; + ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*2) AND (v.out_data_count = '1') THEN + v.state := OVERFLOW_OUTPUT; ELSE v.state := FILL_VECTOR; END IF; + WHEN RESET => v := c_t_reg_init; + v.out_sosi.bsn(c_dp_stream_bsn_w-1 DOWNTO 0) := in_sosi.bsn(c_dp_stream_bsn_w-1 DOWNTO 0); IF rst = '1' THEN v.state := RESET; - ELSIF in_stop = '1' OR in_valid = '0' THEN + ELSIF in_stop = '1' OR in_sosi.valid = '0' THEN v.state := STOP; ELSE v.state := FILL_VECTOR; @@ -220,31 +246,31 @@ BEGIN WHEN STOP => + v.out_sosi.valid := '0'; + v.q_sop := '0'; + v.out_data_stopped := '1'; IF rst = '1' THEN v.state := RESET; - ELSIF in_stop = '1' OR in_valid = '0' THEN + ELSIF in_stop = '1' OR in_sosi.valid = '0' THEN v.state := STOP; - ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*(v.out_data_count+1)) AND (v.out_data_count = 0) THEN + ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*1) AND (v.out_data_count = '0') THEN v.state := FIRST_OUTPUT; - ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*(v.out_data_count+1)) AND (v.out_data_count = 1) THEN + ELSIF ((g_in_data_w*(v.c_v_count+1))+v.out_of >= c_out_data_w*2) AND (v.out_data_count = '1') THEN v.state := OVERFLOW_OUTPUT; ELSE v.state := FILL_VECTOR; END IF; - - END CASE; + d_reg <= v; END PROCESS; -- fill outputs - out_of <= q_reg.out_of; - out_sosi <= q_reg.out_sosi; - out_bsn_ds <= q_reg.out_bsn_ds; - out_bsn <= q_reg.out_bsn; - out_bsn_wr <= q_reg.out_bsn_written; + out_sosi <= q_reg.out_sosi; + out_bsn_ds <= q_reg.out_bsn_ds; + out_data_stopped <= q_reg.out_data_stopped; END rtl; diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output_unpack.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output_unpack.vhd index e9d65b74cac157e2fd16745315559fe73c76d7bc..823f5e3ec6ae6e3ad0d25bafedd34b46b25af57e 100644 --- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output_unpack.vhd +++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_output_unpack.vhd @@ -163,7 +163,6 @@ BEGIN v.out_ready := '0'; v.c_v(g_in_data_w-1 DOWNTO 0) := q_reg.delay_data(g_in_data_w-1 DOWNTO 0); v.dd_fresh := '0'; - v.a_of := in_ds+2+((5)*14); -- will be fixed after in_ds is fixed in ddrctrl_controller. v.out_sosi.data(g_out_data_w-1 DOWNTO 0) := v.c_v(g_out_data_w+v.a_of-1 DOWNTO v.a_of); v.out_sosi.valid := '1'; v.out_sosi.bsn(c_dp_stream_bsn_w-1 DOWNTO 0) := in_bsn(c_dp_stream_bsn_w-1 DOWNTO 0); @@ -242,14 +241,11 @@ BEGIN v.out_ready := '1'; v.delay_data(g_in_data_w-1 DOWNTO 0) := in_sosi.data(g_in_data_w-1 DOWNTO 0); - IF in_sosi.valid = '1' THEN - v.delay_data(g_in_data_w-1 DOWNTO 0) := in_sosi.data(g_in_data_w-1 DOWNTO 0); - v.dd_fresh := '1'; - END IF; - IF in_sosi.valid = '1' THEN v.state := FIRST_READ; + v.delay_data(g_in_data_w-1 DOWNTO 0) := in_sosi.data(g_in_data_w-1 DOWNTO 0); + v.dd_fresh := '1'; ELSE v.state := OFF; END IF; diff --git a/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd b/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd index 445f8d98fd2e6e3f5ff6b5b68e3249e17e4fc2c4..422c72f091f333e4dc5d57da568da322917e21c5 100644 --- a/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd +++ b/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd @@ -37,51 +37,72 @@ USE technology_lib.technology_select_pkg.ALL; ENTITY tb_ddrctrl IS GENERIC ( - g_tech_ddr : t_c_tech_ddr := c_tech_ddr4_8g_1600m; -- type of memory - g_nof_streams : POSITIVE := 12; -- number of input streams - g_data_w : NATURAL := 14; -- data with of input data vectors - g_sim_length : NATURAL := 16500; -- close to the amount of word that gets put into the memory - g_technology : NATURAL := c_tech_select_default; - g_tech_ddr3 : t_c_tech_ddr := c_tech_ddr3_4g_800m_master; - g_tech_ddr4 : t_c_tech_ddr := c_tech_ddr4_4g_1600m; - g_stop_percentage : NATURAL := 80; -- percentage there needs to be already written in the ddr memory when a stop gets triggered - g_block_size : NATURAL := 1024 -- amount of samples that goes into one bsn + g_tech_ddr : t_c_tech_ddr := c_tech_ddr4_8g_1600m; -- type of memory + g_nof_streams : POSITIVE := 12; -- number of input streams + g_data_w : NATURAL := 14; -- data with of input data vectors + g_technology : NATURAL := c_tech_select_default; + g_tech_ddr3 : t_c_tech_ddr := c_tech_ddr3_4g_800m_master; + g_tech_ddr4 : t_c_tech_ddr := c_tech_ddr4_4g_1600m; + g_stop_percentage : NATURAL := 80; -- percentage there needs to be already written in the ddr memory when a stop gets triggered + g_block_size : NATURAL := 1024 -- amount of samples that goes into one bsn ); END tb_ddrctrl; ARCHITECTURE tb OF tb_ddrctrl IS - CONSTANT c_sim_model : BOOLEAN := TRUE; -- determens if this is a simulation + CONSTANT c_sim_model : BOOLEAN := TRUE; -- determens if this is a simulation -- Select DDR3 or DDR4 dependent on the technology and sim model - CONSTANT c_mem_ddr : t_c_tech_ddr := func_tech_sel_ddr(g_technology, g_tech_ddr3, g_tech_ddr4); - CONSTANT c_sim_ddr : t_c_tech_ddr := func_tech_sel_ddr(g_technology, c_tech_ddr3_sim_16k, c_tech_ddr4_sim_16k); - CONSTANT c_tech_ddr : t_c_tech_ddr := func_tech_sel_ddr(c_sim_model, c_sim_ddr, c_mem_ddr); + CONSTANT c_mem_ddr : t_c_tech_ddr := func_tech_sel_ddr(g_technology, g_tech_ddr3, g_tech_ddr4); + CONSTANT c_sim_ddr : t_c_tech_ddr := func_tech_sel_ddr(g_technology, c_tech_ddr3_sim_16k, c_tech_ddr4_sim_16k); + CONSTANT c_tech_ddr : t_c_tech_ddr := func_tech_sel_ddr(c_sim_model, c_sim_ddr, c_mem_ddr); -- constants for readability - CONSTANT c_ctrl_data_w : NATURAL := func_tech_ddr_ctlr_data_w( c_tech_ddr ); -- 576 - CONSTANT c_in_data_w : NATURAL := g_nof_streams * g_data_w; -- output data with, 168 + CONSTANT c_ctrl_data_w : NATURAL := func_tech_ddr_ctlr_data_w(c_tech_ddr); -- 576 + CONSTANT c_in_data_w : NATURAL := g_nof_streams * g_data_w; -- output data with, 168 -- constants for testbench - CONSTANT c_clk_freq : NATURAL := 200; -- clock frequency in MHz - CONSTANT c_clk_period : TIME := (10**6/c_clk_freq)*1 ps; -- clock priod, 5 ns - CONSTANT c_mm_clk_freq : NATURAL := 100; -- mm clock frequency in MHz - CONSTANT c_mm_clk_period : TIME := (10**6/c_mm_clk_freq)*1 ps; -- mm clock period, 10 ns - CONSTANT c_sim_length : NATURAL := (g_sim_length*c_ctrl_data_w)/c_in_data_w; -- amount of input words that get put into the DUT + CONSTANT c_clk_freq : NATURAL := 200; -- clock frequency in MHz + CONSTANT c_clk_period : TIME := (10**6/c_clk_freq)*1 ps; -- clock priod, 5 ns + CONSTANT c_mm_clk_freq : NATURAL := 100; -- mm clock frequency in MHz + CONSTANT c_mm_clk_period : TIME := (10**6/c_mm_clk_freq)*1 ps; -- mm clock period, 10 ns -- constant for checking output data - CONSTANT c_adr_w : NATURAL := func_tech_ddr_ctlr_address_w( c_tech_ddr ); -- the lengt of the address vector, for simulation this is smaller, otherwise the simulation would take to long, 27 - CONSTANT c_max_adr : NATURAL := 2**(c_adr_w)-1; -- the maximal address that is possible within the vector length of the address - CONSTANT c_output_stop_adr : NATURAL := (c_max_adr+1)-((((c_max_adr+1)/64)*g_stop_percentage/100)*64); - CONSTANT c_output_ds : NATURAL := 144; + CONSTANT c_adr_w : NATURAL := func_tech_ddr_ctlr_address_w(c_tech_ddr); -- the lengt of the address vector, for simulation this is smaller, otherwise the simulation would take to long, 27 + CONSTANT c_max_adr : NATURAL := 2**(c_adr_w)-1; -- the maximal address that is possible within the vector length of the address + CONSTANT c_output_stop_adr : NATURAL := (c_max_adr+1)-((((c_max_adr+1)/64)*g_stop_percentage/100)*64); + CONSTANT c_output_ds : NATURAL := 144; + CONSTANT c_bim : NATURAL := (c_max_adr*c_ctrl_data_w)/(g_block_size*g_nof_streams*g_data_w); -- the amount of whole blocks that fit in memory. + CONSTANT c_adr_per_b : NATURAL := ((g_block_size*g_nof_streams*g_data_w)/c_ctrl_data_w)+1; -- rounding error removes the amount of extra addresses. + -- the amount of addresses used + CONSTANT c_nof_adr : NATURAL := (c_bim*g_block_size*g_nof_streams*g_data_w)/c_ctrl_data_w; -- rounding error removes the amount of extra addresses. + + -- the amount of overflow after one block is written + CONSTANT c_of_pb : NATURAL := (g_block_size*g_nof_streams*g_data_w)-(((g_block_size*g_nof_streams*g_data_w)/c_ctrl_data_w)*c_ctrl_data_w); -- amount of overflow after one block is written to memory + + FUNCTION c_of_after_nof_adr_init RETURN NATURAL IS + VARIABLE temp : NATURAL := 0; + BEGIN + FOR I IN 0 TO c_bim-1 LOOP + IF temp+c_of_pb < c_ctrl_data_w THEN + temp := temp+c_of_pb; + ELSE + temp := temp+c_of_pb-c_ctrl_data_w; + END IF; + END LOOP; + RETURN temp; + END FUNCTION c_of_after_nof_adr_init; + + -- the amount of overflow into the address: c_nof_adr NOT YET USED DELETE AFTER L2SDP-706 + CONSTANT c_of_after_nof_adr : NATURAL := c_of_after_nof_adr_init; -- function for making total data vector FUNCTION c_total_vector_init RETURN STD_LOGIC_VECTOR IS - VARIABLE temp : STD_LOGIC_VECTOR(c_in_data_w*c_sim_length-1 DOWNTO 0); - VARIABLE conv : STD_LOGIC_VECTOR(32-1 DOWNTO 0) := (OTHERS => '0'); -- removes a warning + VARIABLE temp : STD_LOGIC_VECTOR(g_data_w*g_nof_streams*c_bim*g_block_size-1 DOWNTO 0); + VARIABLE conv : STD_LOGIC_VECTOR(32-1 DOWNTO 0) := (OTHERS => '0'); -- removes a warning BEGIN - FOR I IN 0 TO c_sim_length-1 LOOP + FOR I IN 0 TO c_bim*g_block_size-1 LOOP conv := TO_UVEC(I, 32); FOR J IN 0 TO g_nof_streams-1 LOOP temp(g_data_w*((I*g_nof_streams)+J+1)-1 DOWNTO g_data_w*((I*g_nof_streams)+j)) := conv(g_data_w-1 DOWNTO 0); @@ -91,11 +112,13 @@ ARCHITECTURE tb OF tb_ddrctrl IS END FUNCTION c_total_vector_init; -- constant for running the test - CONSTANT c_total_vector : STD_LOGIC_VECTOR(c_in_data_w*c_sim_length-1 DOWNTO 0) := c_total_vector_init; -- vector which contains all input data vectors to make it easy to fill ctr_vector + CONSTANT c_total_vector : STD_LOGIC_VECTOR(g_data_w*g_nof_streams*c_bim*g_block_size-1 DOWNTO 0) := c_total_vector_init; -- vector which contains all input data vectors to make it easy to fill ctr_vector + + SIGNAL c_total_vector_length : NATURAL := c_total_vector'length; - CONSTANT c_check : NATURAL := 32; - CONSTANT c_check_bottom : NATURAL := 5; - CONSTANT c_ones : STD_LOGIC_VECTOR(c_check-c_check_bottom-1 DOWNTO 0) := (OTHERS => '1'); + CONSTANT c_check : NATURAL := 32; + CONSTANT c_check_bottom : NATURAL := 5; + CONSTANT c_ones : STD_LOGIC_VECTOR(c_check-c_check_bottom-1 DOWNTO 0) := (OTHERS => '1'); -- input signals for ddrctrl.vhd @@ -114,6 +137,8 @@ ARCHITECTURE tb OF tb_ddrctrl IS -- signals for running test SIGNAL in_data_cnt : NATURAL := 0; -- signal which contains the amount of times there has been input data for ddrctrl_repack.vhd SIGNAL test_running : STD_LOGIC := '0'; -- signal to tell wheter the testing has started + SIGNAL bsn_cnt : NATURAL := 0; + -- signals for checking the output data SIGNAL output_data_cnt : NATURAL := 0; @@ -136,8 +161,8 @@ BEGIN BEGIN -- start the test - tb_end <= '0'; - in_sosi_arr(0).valid <= '0'; + tb_end <= '0'; + in_sosi_arr(0).valid <= '0'; WAIT UNTIL rising_edge(clk); -- align to rising edge WAIT FOR c_clk_period*4; rst <= '1'; @@ -148,17 +173,36 @@ BEGIN test_running <= '1'; WAIT FOR c_clk_period*1; + -- wr fifo has delay of 4 clockcylces after reset -- filling the input data vectors with the corresponding numbers - run_multiple_times : FOR K in 0 TO 4 LOOP - make_data : FOR J IN 0 TO c_sim_length-1 LOOP + run_multiple_times : FOR K in 0 TO 3 LOOP + make_data : FOR J IN 0 TO c_bim*g_block_size-1 LOOP in_data_cnt <= in_data_cnt+1; - fill_in_sosi_arr_0 : FOR I IN 0 TO g_nof_streams-1 LOOP + fill_in_sosi_arr : FOR I IN 0 TO g_nof_streams-1 LOOP in_sosi_arr(I).data(g_data_w-1 DOWNTO 0) <= c_total_vector(g_data_w*(I+1)+J*c_in_data_w-1 DOWNTO g_data_w*I+J*c_in_data_w); in_sosi_arr(I).valid <= '1'; in_sosi_arr(I).bsn(c_dp_stream_bsn_w-1 DOWNTO 0) <= bsn(c_dp_stream_bsn_w-1 DOWNTO 0); + IF bsn_cnt = g_block_size-1 THEN + bsn_cnt <= 0; + FOR I IN 0 TO g_nof_streams-1 LOOP + in_sosi_arr(I).sop <= '1'; + in_sosi_arr(I).eop <= '0'; + END LOOP; + bsn <= INCR_UVEC(bsn, 1); + ELSE + bsn_cnt <= bsn_cnt + 1; + FOR I IN 0 TO g_nof_streams-1 LOOP + in_sosi_arr(I).sop <= '0'; + END LOOP; + END IF; + IF bsn_cnt = g_block_size-2 THEN + FOR I IN 0 TO g_nof_streams-1 LOOP + in_sosi_arr(I).eop <= '1'; + END LOOP; + END IF; END LOOP; - IF K = 1 AND J = 0 THEN + IF K = 1 AND J = c_bim*g_block_size-1 THEN stop_in <= '1'; ELSE stop_in <= '0'; @@ -166,33 +210,18 @@ BEGIN WAIT FOR c_clk_period*1; END LOOP; END LOOP; + + in_sosi_arr(0).valid <= '0'; test_running <= '0'; -- stopping the testbench - WAIT FOR c_clk_period*4; + WAIT FOR c_clk_period*g_block_size; tb_end <= '1'; ASSERT FALSE REPORT "Test: OK" SEVERITY FAILURE; END PROCESS; - p_bsn : PROCESS - VARIABLE bsn_cnt : NATURAL := 0; - BEGIN - bsn(c_check-1 DOWNTO c_check_bottom) <= c_ones(c_check-c_check_bottom-1 DOWNTO 0); - FOR I IN 0 TO (c_sim_length*4)-1 LOOP - WAIT UNTIL rising_edge(clk); - IF in_sosi_arr(0).valid = '1' THEN - IF bsn_cnt = g_block_size-1 THEN - bsn_cnt := 0; - bsn <= INCR_UVEC(bsn, 1); - ELSE - bsn_cnt := bsn_cnt + 1; - END IF; - END IF; - END LOOP; - END PROCESS; - p_checking_output_data : PROCESS -- first do tickets L2SDP-708 and L2SDP-707 before finsishing this is worth time BEGIN WAIT UNTIL rising_edge(clk); diff --git a/libraries/base/common/tb/vhdl/tb_requantize.vhd b/libraries/base/common/tb/vhdl/tb_requantize.vhd index 9f4ca004fa7de0a4f0a9872b00cb1f77fbb09b77..f7317d92b37f830ce63a11eb50bdc40170749fc1 100644 --- a/libraries/base/common/tb/vhdl/tb_requantize.vhd +++ b/libraries/base/common/tb/vhdl/tb_requantize.vhd @@ -34,6 +34,7 @@ USE work.common_pkg.ALL; -- . c_out_dat_w = 3 -- . c_lsb_w = 2 -- . c_lsb_round_clip = TRUE +-- . c_lsb_round_even = FALSE -- . c_msb_clip_symmetric = TRUE -- . Observe reg_dat with respect to the out_s_*_*.dat and out_u_*_*.dat -- . Try also c_lsb_round_clip=FALSE @@ -55,6 +56,7 @@ ARCHITECTURE tb OF tb_requantize IS CONSTANT c_out_dat_w : NATURAL := 3; CONSTANT c_lsb_w : NATURAL := 2; CONSTANT c_lsb_round_clip : BOOLEAN := TRUE; --FALSE; + CONSTANT c_lsb_round_even : BOOLEAN := FALSE; -- golden reference data is for round half away from zero CONSTANT c_msb_clip_symmetric : BOOLEAN := TRUE; --FALSE; -- Stimuli @@ -158,6 +160,7 @@ BEGIN g_lsb_w => c_lsb_w, g_lsb_round => TRUE, g_lsb_round_clip => c_lsb_round_clip, + g_lsb_round_even => c_lsb_round_even, g_msb_clip => TRUE, g_msb_clip_symmetric => c_msb_clip_symmetric, g_pipeline_remove_lsb => g_pipeline_remove_lsb, @@ -178,6 +181,7 @@ BEGIN g_lsb_w => c_lsb_w, g_lsb_round => TRUE, g_lsb_round_clip => c_lsb_round_clip, + g_lsb_round_even => c_lsb_round_even, g_msb_clip => FALSE, g_msb_clip_symmetric => c_msb_clip_symmetric, g_pipeline_remove_lsb => g_pipeline_remove_lsb, @@ -198,6 +202,7 @@ BEGIN g_lsb_w => c_lsb_w, g_lsb_round => FALSE, g_lsb_round_clip => c_lsb_round_clip, + g_lsb_round_even => c_lsb_round_even, g_msb_clip => TRUE, g_msb_clip_symmetric => c_msb_clip_symmetric, g_pipeline_remove_lsb => g_pipeline_remove_lsb, @@ -218,6 +223,7 @@ BEGIN g_lsb_w => c_lsb_w, g_lsb_round => FALSE, g_lsb_round_clip => c_lsb_round_clip, + g_lsb_round_even => c_lsb_round_even, g_msb_clip => FALSE, g_msb_clip_symmetric => c_msb_clip_symmetric, g_pipeline_remove_lsb => g_pipeline_remove_lsb, @@ -239,6 +245,7 @@ BEGIN g_lsb_w => c_lsb_w, g_lsb_round => TRUE, g_lsb_round_clip => c_lsb_round_clip, + g_lsb_round_even => c_lsb_round_even, g_msb_clip => TRUE, g_msb_clip_symmetric => c_msb_clip_symmetric, g_pipeline_remove_lsb => g_pipeline_remove_lsb, @@ -259,6 +266,7 @@ BEGIN g_lsb_w => c_lsb_w, g_lsb_round => TRUE, g_lsb_round_clip => c_lsb_round_clip, + g_lsb_round_even => c_lsb_round_even, g_msb_clip => FALSE, g_msb_clip_symmetric => c_msb_clip_symmetric, g_pipeline_remove_lsb => g_pipeline_remove_lsb, @@ -279,6 +287,7 @@ BEGIN g_lsb_w => c_lsb_w, g_lsb_round => FALSE, g_lsb_round_clip => c_lsb_round_clip, + g_lsb_round_even => c_lsb_round_even, g_msb_clip => TRUE, g_msb_clip_symmetric => c_msb_clip_symmetric, g_pipeline_remove_lsb => g_pipeline_remove_lsb, @@ -299,6 +308,7 @@ BEGIN g_lsb_w => c_lsb_w, g_lsb_round => FALSE, g_lsb_round_clip => c_lsb_round_clip, + g_lsb_round_even => c_lsb_round_even, g_msb_clip => FALSE, g_msb_clip_symmetric => c_msb_clip_symmetric, g_pipeline_remove_lsb => g_pipeline_remove_lsb, diff --git a/libraries/dsp/filter/src/vhdl/fil_ppf_filter.vhd b/libraries/dsp/filter/src/vhdl/fil_ppf_filter.vhd index bf6077f23944998799de18e472ae629af6f8e327..564cc785908f660aeee0aef3e5e8fac077608774 100644 --- a/libraries/dsp/filter/src/vhdl/fil_ppf_filter.vhd +++ b/libraries/dsp/filter/src/vhdl/fil_ppf_filter.vhd @@ -38,7 +38,8 @@ entity fil_ppf_filter is generic ( g_technology : NATURAL := c_tech_select_default; g_fil_ppf : t_fil_ppf; - g_fil_ppf_pipeline : t_fil_ppf_pipeline + g_fil_ppf_pipeline : t_fil_ppf_pipeline; + g_round_even : boolean := true ); port ( clk : in std_logic; @@ -117,12 +118,13 @@ begin sum => adder_out ); - u_requantize_addeer_output : entity common_lib.common_requantize + u_requantize_adder_output : entity common_lib.common_requantize generic map ( g_representation => "SIGNED", g_lsb_w => c_ppf_lsb_w, g_lsb_round => TRUE, g_lsb_round_clip => FALSE, + g_lsb_round_even => g_round_even, g_msb_clip => FALSE, g_msb_clip_symmetric => FALSE, g_pipeline_remove_lsb => g_fil_ppf_pipeline.requant_remove_lsb, diff --git a/libraries/dsp/filter/src/vhdl/fil_ppf_single.vhd b/libraries/dsp/filter/src/vhdl/fil_ppf_single.vhd index 3b1b9dedbaef621133376261144cd64ba3369a49..2351c5f89688fa1c4c3e4fa6022d31a729de3362 100644 --- a/libraries/dsp/filter/src/vhdl/fil_ppf_single.vhd +++ b/libraries/dsp/filter/src/vhdl/fil_ppf_single.vhd @@ -73,7 +73,8 @@ use work.fil_pkg.ALL; entity fil_ppf_single is generic ( g_fil_ppf : t_fil_ppf := c_fil_ppf; - g_fil_ppf_pipeline : t_fil_ppf_pipeline := c_fil_ppf_pipeline; + g_fil_ppf_pipeline : t_fil_ppf_pipeline := c_fil_ppf_pipeline; + g_round_even : boolean := true; g_file_index_arr : t_nat_natural_arr := array_init(0, 128, 1); -- default use the instance index as file index 0, 1, 2, 3, 4 ... g_coefs_file_prefix : string := "hex/coef" -- Relative path to the mif files that contain the initial data for the coefficients memories ); -- The sequence number and ".mif"-extension are added within the entity. @@ -234,7 +235,8 @@ begin u_filter : entity work.fil_ppf_filter generic map ( g_fil_ppf_pipeline => g_fil_ppf_pipeline, - g_fil_ppf => g_fil_ppf + g_fil_ppf => g_fil_ppf, + g_round_even => g_round_even ) port map ( clk => dp_clk, diff --git a/libraries/dsp/filter/src/vhdl/fil_ppf_wide.vhd b/libraries/dsp/filter/src/vhdl/fil_ppf_wide.vhd index 85bdf3c3fcb3d18d31085a6a22789935a2a87a1f..9561d28a3c913925127bc2895dbda95ba4b9670a 100644 --- a/libraries/dsp/filter/src/vhdl/fil_ppf_wide.vhd +++ b/libraries/dsp/filter/src/vhdl/fil_ppf_wide.vhd @@ -121,6 +121,7 @@ entity fil_ppf_wide is g_big_endian_wb_out : boolean := false; g_fil_ppf : t_fil_ppf := c_fil_ppf; g_fil_ppf_pipeline : t_fil_ppf_pipeline := c_fil_ppf_pipeline; + g_round_even : boolean := true; g_coefs_file_prefix : string := "../../data/coef" -- Relative path to the mif files that contain the FIR the coefficients -- The sequence number and ".mif"-extension are added within the entity. ); @@ -235,6 +236,7 @@ begin generic map ( g_fil_ppf => c_fil_ppf_arr(P), g_fil_ppf_pipeline => g_fil_ppf_pipeline, + g_round_even => g_round_even, g_file_index_arr => c_file_index_arr2(P), -- use (g_fil_ppf.wb_factor-1 - P) to try impact of reversed WB FIR coefficients g_coefs_file_prefix => g_coefs_file_prefix ) diff --git a/libraries/dsp/filter/tb/vhdl/tb_fil_ppf_wide_file_data.vhd b/libraries/dsp/filter/tb/vhdl/tb_fil_ppf_wide_file_data.vhd index 103f01b59270e47ad366b88ee4c74a08102d75f9..c56ad139456fca352a11729aafb6b2b6254b18bf 100644 --- a/libraries/dsp/filter/tb/vhdl/tb_fil_ppf_wide_file_data.vhd +++ b/libraries/dsp/filter/tb/vhdl/tb_fil_ppf_wide_file_data.vhd @@ -131,6 +131,7 @@ architecture tb of tb_fil_ppf_wide_file_data is constant c_clk_period : time := 10 ns; constant c_sclk_period : time := c_clk_period / g_fil_ppf.wb_factor; + constant c_round_even : boolean := false; -- golden reference data is for round half away from zero constant c_diff_margin : integer := 0; -- maximum difference between PFIR HDL output and expected output (> 0 to allow minor rounding differences) constant c_nof_channels : natural := 2**g_fil_ppf.nof_chan; @@ -285,6 +286,7 @@ begin g_big_endian_wb_out => g_big_endian_wb_out, g_fil_ppf => g_fil_ppf, g_fil_ppf_pipeline => g_fil_ppf_pipeline, + g_round_even => c_round_even, g_coefs_file_prefix => c_coefs_mif_file_prefix ) port map ( @@ -489,4 +491,4 @@ begin end if; end process; -end tb; \ No newline at end of file +end tb; diff --git a/libraries/dsp/iquv/tb/vhdl/tb_iquv_iab.vhd b/libraries/dsp/iquv/tb/vhdl/tb_iquv_iab.vhd index 89fd455399a8a13a23b200e40e11ab6eb0f6168e..bd45dac37548b18227e72e8041a5547e6784d307 100644 --- a/libraries/dsp/iquv/tb/vhdl/tb_iquv_iab.vhd +++ b/libraries/dsp/iquv/tb/vhdl/tb_iquv_iab.vhd @@ -59,6 +59,11 @@ ARCHITECTURE tb OF tb_iquv_iab IS CONSTANT c_fsd_w : NATURAL := c_iquv_out_w + ceil_log2(g_nof_streams); -- The number of bits fsd after the adder tree CONSTANT c_lsb_w : NATURAL := c_fsd_w - g_out_data_w; -- number of lsbs to remove from the expected result + CONSTANT c_clip : BOOLEAN := TRUE; + CONSTANT c_wrap : BOOLEAN := NOT c_clip; + CONSTANT c_even : BOOLEAN := TRUE; + CONSTANT c_away : BOOLEAN := NOT c_even; + SIGNAL tb_end : STD_LOGIC := '0'; SIGNAL dp_rst : STD_LOGIC := '1'; SIGNAL dp_clk : STD_LOGIC := '0'; @@ -205,19 +210,19 @@ BEGIN IF rising_edge(dp_clk) THEN IF diag_out_valid = '1' THEN IF g_nof_int = 8 THEN - ASSERT TO_UINT(i_out.data) = TO_UINT(u_round(TO_UVEC(i_nint8_exp_arr(v_index),c_fsd_w), c_lsb_w, TRUE)) REPORT "Error: wrong result in I out DUT" SEVERITY ERROR; - --REPORT "I exp = " & integer'image(to_uint(s_round(TO_UVEC(i_nint8_exp_arr(v_index),c_fsd_w), c_lsb_w, TRUE))); - ASSERT TO_SINT(q_out.data) = TO_SINT(s_round(TO_SVEC(q_nint8_exp_arr(v_index),c_word_w), c_lsb_w)) REPORT "Error: wrong result in Q out DUT" SEVERITY ERROR; - ASSERT TO_SINT(u_out.data) = TO_SINT(s_round(TO_SVEC(u_nint8_exp_arr(v_index),c_word_w), c_lsb_w)) REPORT "Error: wrong result in U out DUT" SEVERITY ERROR; - ASSERT TO_SINT(v_out.data) = TO_SINT(s_round(TO_SVEC(v_nint8_exp_arr(v_index),c_word_w), c_lsb_w)) REPORT "Error: wrong result in V out DUT" SEVERITY ERROR; + ASSERT TO_UINT(i_out.data) = TO_UINT(u_round(TO_UVEC(i_nint8_exp_arr(v_index),c_fsd_w), c_lsb_w, c_clip, c_even)) REPORT "Error: wrong result in I out DUT" SEVERITY ERROR; + --REPORT "I exp = " & integer'image(to_uint(s_round(TO_UVEC(i_nint8_exp_arr(v_index),c_fsd_w), c_lsb_w, c_clip))); + ASSERT TO_SINT(q_out.data) = TO_SINT(s_round(TO_SVEC(q_nint8_exp_arr(v_index),c_word_w), c_lsb_w, c_wrap, c_even)) REPORT "Error: wrong result in Q out DUT" SEVERITY ERROR; + ASSERT TO_SINT(u_out.data) = TO_SINT(s_round(TO_SVEC(u_nint8_exp_arr(v_index),c_word_w), c_lsb_w, c_wrap, c_even)) REPORT "Error: wrong result in U out DUT" SEVERITY ERROR; + ASSERT TO_SINT(v_out.data) = TO_SINT(s_round(TO_SVEC(v_nint8_exp_arr(v_index),c_word_w), c_lsb_w, c_wrap, c_even)) REPORT "Error: wrong result in V out DUT" SEVERITY ERROR; ELSIF g_nof_int = 16 THEN - ASSERT TO_UINT(i_out.data) = TO_UINT(u_round(TO_UVEC(i_nint16_exp_arr(v_index),c_fsd_w), c_lsb_w, TRUE)) REPORT "Error: wrong result in I out DUT" SEVERITY ERROR; - --REPORT "I expected = " & integer'image(to_uint(u_round(TO_UVEC(i_nint16_exp_arr(v_index),c_fsd_w), c_lsb_w, TRUE))); - ASSERT TO_SINT(q_out.data) = TO_SINT(s_round(TO_SVEC(q_nint16_exp_arr(v_index),c_word_w), c_lsb_w)) REPORT "Error: wrong result in Q out DUT" SEVERITY ERROR; - --REPORT "Q expected = " & integer'image(to_sint(s_round(TO_SVEC(q_nint16_exp_arr(v_index),c_word_w), c_lsb_w))); - ASSERT TO_SINT(u_out.data) = TO_SINT(s_round(TO_SVEC(u_nint16_exp_arr(v_index),c_word_w), c_lsb_w)) REPORT "Error: wrong result in U out DUT" SEVERITY ERROR; - ASSERT TO_SINT(v_out.data) = TO_SINT(s_round(TO_SVEC(v_nint16_exp_arr(v_index),c_word_w), c_lsb_w)) REPORT "Error: wrong result in V out DUT" SEVERITY ERROR; + ASSERT TO_UINT(i_out.data) = TO_UINT(u_round(TO_UVEC(i_nint16_exp_arr(v_index),c_fsd_w), c_lsb_w, c_clip, c_even)) REPORT "Error: wrong result in I out DUT" SEVERITY ERROR; + --REPORT "I expected = " & integer'image(to_uint(u_round(TO_UVEC(i_nint16_exp_arr(v_index),c_fsd_w), c_lsb_w, c_clip, c_even))); + ASSERT TO_SINT(q_out.data) = TO_SINT(s_round(TO_SVEC(q_nint16_exp_arr(v_index),c_word_w), c_lsb_w, c_wrap, c_even)) REPORT "Error: wrong result in Q out DUT" SEVERITY ERROR; + --REPORT "Q expected = " & integer'image(to_sint(s_round(TO_SVEC(q_nint16_exp_arr(v_index),c_word_w), c_lsb_w, c_wrap, c_even))); + ASSERT TO_SINT(u_out.data) = TO_SINT(s_round(TO_SVEC(u_nint16_exp_arr(v_index),c_word_w), c_lsb_w, c_wrap, c_even)) REPORT "Error: wrong result in U out DUT" SEVERITY ERROR; + ASSERT TO_SINT(v_out.data) = TO_SINT(s_round(TO_SVEC(v_nint16_exp_arr(v_index),c_word_w), c_lsb_w, c_wrap, c_even)) REPORT "Error: wrong result in V out DUT" SEVERITY ERROR; END IF; REPORT "I = " & integer'image(to_uint(i_out.data)) & ", Q = " & integer'image(to_sint(q_out.data)) &