diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd index e802791e80385d64d2cdfbcd960fa1e5f9a91e3e..0ec78eaec6201c1867a46565d0e61ebb04a02dab 100644 --- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd +++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl.vhd @@ -266,7 +266,8 @@ BEGIN 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_last_burstsize => c_last_burstsize, + g_adr_per_b => c_adr_per_b ) PORT MAP( clk => clk, diff --git a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd index df90236414b18368ced333370d4287aca3246515..66348762b0e082bbdf10f42746ce2256317222f1 100644 --- a/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd +++ b/applications/lofar2/libraries/ddrctrl/src/vhdl/ddrctrl_controller.vhd @@ -40,16 +40,17 @@ 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_max_adr : NATURAL; - g_burstsize : NATURAL; - g_last_burstsize : 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; @@ -81,18 +82,23 @@ END ddrctrl_controller; ARCHITECTURE rtl OF ddrctrl_controller IS - CONSTANT c_bitshift_adr : NATURAL := ceil_log2(g_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_pof_ma : NATURAL := (g_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 := (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 @@ -101,7 +107,10 @@ ARCHITECTURE rtl OF ddrctrl_controller IS started : STD_LOGIC; -- stopping signals + ready_for_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; cooling_down : NATURAL; @@ -120,7 +129,7 @@ ARCHITECTURE rtl OF ddrctrl_controller IS wr_sosi : t_dp_sosi; END RECORD; - CONSTANT c_t_reg_init : t_reg := (RESET, '0', TO_UVEC(g_max_adr, c_adr_w), '1', '1', 8, '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', c_proportion, '0', 0, (OTHERS => '0'), 0, '0', c_mem_ctlr_mosi_rst, c_dp_sosi_init); -- signals for readability @@ -153,7 +162,7 @@ BEGIN WHEN WRITING => -- 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 AND q_reg.dvr_mosi.burstbegin = '0'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 @@ -164,7 +173,7 @@ BEGIN 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_adr-1 DOWNTO 0) := c_zeros(c_bitshift_adr-1 DOWNTO 0); -- makes sure that a burst is only started on a multiple of g_burstsize + 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 @@ -178,17 +187,21 @@ BEGIN WHEN SET_STOP => --setting a stop address dependend on the g_stop_percentage IF inp_adr+c_pof_ma >= g_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); + 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.cooling_down := 8; + v.ready_for_stop := '0'; + v.cooling_down := c_proportion; + 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 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 AND q_reg.dvr_mosi.burstbegin = '0'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 @@ -199,7 +212,7 @@ BEGIN 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_adr-1 DOWNTO 0) := c_zeros(c_bitshift_adr-1 DOWNTO 0); -- makes sure that a burst is only started on a multiple of g_burstsize + 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 @@ -211,23 +224,26 @@ BEGIN WHEN STOP_WRITING => - v.dvr_mosi.burstbegin := '0'; + v.stopped := '1'; -- wait until the write burst is finished IF NOT (q_reg.cooling_down = 0) THEN v.cooling_down := q_reg.cooling_down-1; v.state := STOP_WRITING; - ELSIF dvr_miso.done = '1' AND q_reg.dvr_mosi.burstbegin = '0' THEN - v.stopped := '1'; + ELSIF dvr_miso.done = '1' AND q_reg.need_burst = '0' THEN v.wr_sosi.valid := '0'; - v.state := START_READING; + v.state := LAST_WRITE_BURST; ELSE v.state := STOP_WRITING; END IF; + IF inp_sosi.valid = '1' THEN + v.cooling_down := c_proportion; + 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_adr-1 DOWNTO 0) = c_zeros AND q_reg.dvr_mosi.burstbegin = '0'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 @@ -238,7 +254,7 @@ BEGIN 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_adr-1 DOWNTO 0) := c_zeros(c_bitshift_adr-1 DOWNTO 0); -- makes sure that a burst is only started on a multiple of g_burstsize + 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 @@ -249,11 +265,27 @@ BEGIN 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+(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 @@ -269,6 +301,11 @@ BEGIN 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 + 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 @@ -319,8 +356,10 @@ 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_stop := '1'; + ELSIF q_reg.ready_for_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 = '0' AND inp_sosi.valid = '1' AND q_reg.started = '1' THEN v.state := WRITING; 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 fb535d7ad956b2600e5a2a5e545cd2aeebdeda85..422c72f091f333e4dc5d57da568da322917e21c5 100644 --- a/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd +++ b/applications/lofar2/libraries/ddrctrl/tb/vhdl/tb_ddrctrl.vhd @@ -40,7 +40,6 @@ ENTITY tb_ddrctrl IS 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; @@ -67,7 +66,6 @@ ARCHITECTURE tb OF tb_ddrctrl IS 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 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 @@ -116,6 +114,8 @@ ARCHITECTURE tb OF tb_ddrctrl IS -- constant for running the test 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'); @@ -161,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'; @@ -176,7 +176,7 @@ BEGIN -- 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 + 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 : FOR I IN 0 TO g_nof_streams-1 LOOP @@ -202,7 +202,7 @@ BEGIN END LOOP; END IF; END LOOP; - IF K = 2 AND J = c_bim*g_block_size-1 THEN + IF K = 1 AND J = c_bim*g_block_size-1 THEN stop_in <= '1'; ELSE stop_in <= '0';