Skip to content
Snippets Groups Projects
Select Git revision
  • 95cb075d279eba65d5b63d78c5bf6f0ae9cab7d5
  • master default protected
  • L2SS-1914-fix_job_dispatch
  • TMSS-3170
  • TMSS-3167
  • TMSS-3161
  • TMSS-3158-Front-End-Only-Allow-Changing-Again
  • TMSS-3133
  • TMSS-3319-Fix-Templates
  • test-fix-deploy
  • TMSS-3134
  • TMSS-2872
  • defer-state
  • add-custom-monitoring-points
  • TMSS-3101-Front-End-Only
  • TMSS-984-choices
  • SDC-1400-Front-End-Only
  • TMSS-3079-PII
  • TMSS-2936
  • check-for-max-244-subbands
  • TMSS-2927---Front-End-Only-PXII
  • Before-Remove-TMSS
  • LOFAR-Release-4_4_318 protected
  • LOFAR-Release-4_4_317 protected
  • LOFAR-Release-4_4_316 protected
  • LOFAR-Release-4_4_315 protected
  • LOFAR-Release-4_4_314 protected
  • LOFAR-Release-4_4_313 protected
  • LOFAR-Release-4_4_312 protected
  • LOFAR-Release-4_4_311 protected
  • LOFAR-Release-4_4_310 protected
  • LOFAR-Release-4_4_309 protected
  • LOFAR-Release-4_4_308 protected
  • LOFAR-Release-4_4_307 protected
  • LOFAR-Release-4_4_306 protected
  • LOFAR-Release-4_4_304 protected
  • LOFAR-Release-4_4_303 protected
  • LOFAR-Release-4_4_302 protected
  • LOFAR-Release-4_4_301 protected
  • LOFAR-Release-4_4_300 protected
  • LOFAR-Release-4_4_299 protected
41 results

gridcontroller.js

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    ddrctrl_controller.vhd 22.29 KiB
    -------------------------------------------------------------------------------
    --
    -- 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: controller for ddrctrl, decides when to write when to read or when to stop writing or reading.
    --
    -- Description:
    --
    -- Remark:
    --  Use VHDL coding template from:
    --  https://support.astron.nl/confluence/display/SBe/VHDL+design+patterns+for+RTL+coding
    --  
    
    LIBRARY IEEE, dp_lib, common_lib, tech_ddr_lib;
    USE IEEE.std_logic_1164.ALL;
    USE IEEE.numeric_std.ALL;
    USE dp_lib.dp_stream_pkg.ALL;
    USE common_lib.common_mem_pkg.ALL;
    USE common_lib.common_pkg.ALL;
    USE tech_ddr_lib.tech_ddr_pkg.ALL;
    
    
    ENTITY ddrctrl_controller IS
      GENERIC (
        g_tech_ddr                : t_c_tech_ddr;
        g_stop_percentage         : NATURAL     := 50;
        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_wr_fifo_uw_w            : NATURAL;    -- 8
        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
        g_bim                     : NATURAL     -- 54
      );
      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_bsn_adr               : IN  NATURAL;
        inp_data_stopped          : IN  STD_LOGIC;
        rst_ddrctrl_input_ac      : OUT STD_LOGIC;
    
        -- io_ddr
        dvr_mosi                  : OUT t_mem_ctlr_mosi;
        dvr_miso                  : IN  t_mem_ctlr_miso;
        wr_sosi                   : OUT t_dp_sosi;
        wr_siso                   : IN  t_dp_siso;
        wr_fifo_usedw             : IN  STD_LOGIC_VECTOR(g_wr_fifo_uw_w-1 DOWNTO 0);
        rd_fifo_usedw             : IN  STD_LOGIC_VECTOR(g_rd_fifo_uw_w-1 DOWNTO 0);
        ctlr_wr_flush_en          : IN  STD_LOGIC;
        flush_state               : IN  STD_LOGIC_VECTOR(1 DOWNTO 0);
    
        -- ddrctrl_output
        outp_bsn                  : OUT STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0)  := (OTHERS => '0');
    
        -- ddrctrl_controller
        stop_in                   : IN  STD_LOGIC;
        stop_out                  : OUT STD_LOGIC;
        ddrctrl_ctrl_state        : OUT STD_LOGIC_VECTOR(32-1 DOWNTO 0)                 := (OTHERS => '0')
      );
    END ddrctrl_controller;
    
    ARCHITECTURE rtl OF ddrctrl_controller IS
    
      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                                     := ((NATURAL((REAL(g_max_adr)*(100.0-REAL(g_stop_percentage)))/100.0)/g_adr_per_b)*g_adr_per_b);  --percentage of max address.
    
      CONSTANT  c_zeros           : STD_LOGIC_VECTOR(c_bitshift_w-1 DOWNTO 0)   := (OTHERS => '0');
      CONSTANT  c_stop_adr_zeros  : STD_LOGIC_VECTOR(c_adr_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_io_ddr_data_w   : NATURAL                                     := func_tech_ddr_ctlr_data_w(g_tech_ddr);         -- 576
    
      -- constant for debugging
      CONSTANT  c_always_one_ndx  : NATURAL := 0;
      CONSTANT  c_rst_ndx         : NATURAL := 1;
      CONSTANT  c_low_state_ndx   : NATURAL := 2;
      CONSTANT  c_high_state_ndx  : NATURAL := 5;
      CONSTANT  c_state_ndx_w     : NATURAL := c_high_state_ndx-c_low_state_ndx+1;
      CONSTANT  c_low_bsn_ndx     : NATURAL := 16;
      CONSTANT  c_high_bsn_ndx    : NATURAL := 25;
      CONSTANT  c_bsn_ndx_w       : NATURAL := c_high_bsn_ndx-c_low_bsn_ndx+1;
      CONSTANT  c_start_bsn       : NATURAL := 14;
      CONSTANT  c_low_adr_ndx     : NATURAL := c_high_bsn_ndx+1;
      CONSTANT  c_high_adr_ndx    : NATURAL := 32-1;
      CONSTANT  c_adr_ndx_w       : NATURAL := c_high_adr_ndx-c_low_adr_ndx+1;
      CONSTANT  c_done_ndx        : NATURAL := 8;
      CONSTANT  c_bb_ndx          : NATURAL := 9;
      CONSTANT  c_ben_ndx         : NATURAL := 10;
      CONSTANT  c_das_ndx         : NATURAL := 11;
      CONSTANT  c_low_bre_ndx     : NATURAL := 12;
      CONSTANT  c_high_bre_ndx    : NATURAL := 15;
      CONSTANT  c_bre_ndx_w       : NATURAL := c_high_bre_ndx-c_low_bre_ndx+1;
    
      -- type for statemachine
      TYPE t_state IS (RESET, STOP_FLUSH, STOP_READING, WAIT_FOR_SOP, WRITING, SET_STOP, STOP_WRITING, LAST_WRITE_BURST, START_READING, READING);
    
      -- record for readability
      TYPE t_reg IS RECORD
      -- state of program
      state                       : t_state;
      started                     : STD_LOGIC;
    
      -- stopping flush
      timer                       : NATURAL;
    
      -- 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_ac        : STD_LOGIC;
    
      -- writing signals
      wr_burst_en                 : STD_LOGIC;
      wr_bursts_ready             : NATURAL;
    
      -- reading signals
      outp_bsn                    : STD_LOGIC_VECTOR(c_dp_stream_bsn_w-1 DOWNTO 0);
      read_adr                    : NATURAL;
      rd_burst_en                 : STD_LOGIC;
    
      -- output
      dvr_mosi                    : t_mem_ctlr_mosi;
      wr_sosi                     : t_dp_sosi;
      ddrctrl_ctrl_state          : STD_LOGIC_VECTOR(32-1 DOWNTO 0);
      END RECORD;
    
      CONSTANT c_t_reg_init       : t_reg         := (RESET, '0', 4, '0', TO_UVEC(g_max_adr, c_adr_w), (OTHERS => '0'), 0, '1', '1', '0', 0, (OTHERS => '0'), 0, '1', c_mem_ctlr_mosi_rst, c_dp_sosi_init, (OTHERS => '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);
    
      -- 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_bsn_adr, inp_data_stopped, dvr_miso, rd_fifo_usedw, wr_fifo_usedw, stop_in)
    
        VARIABLE v                : t_reg         := c_t_reg_init;
    
      BEGIN
    
        v         := q_reg;
        v.wr_sosi := inp_sosi;
        --v.ddrctrl_ctrl_state(c_high_bsn_ndx DOWNTO c_low_bsn_ndx)       := inp_sosi.bsn(c_start_bsn+c_bsn_ndx_w-1 DOWNTO c_start_bsn); 
        --v.ddrctrl_ctrl_state(c_high_adr_ndx DOWNTO c_low_adr_ndx)       := TO_UVEC(inp_adr, 32)(c_adr_ndx_w-1 DOWNTO 0);
    
        CASE q_reg.state IS
        WHEN RESET =>
          v                                                             := c_t_reg_init;
          v.ddrctrl_ctrl_state(c_high_state_ndx DOWNTO c_low_state_ndx) := TO_UVEC(0, c_state_ndx_w);
    
          IF rst = '0' AND wr_siso.ready = '1' THEN
            v.state := STOP_FLUSH;
            v.timer := 0;
          END IF;
    
    
        WHEN STOP_FLUSH =>
          v.ddrctrl_ctrl_state(c_high_state_ndx DOWNTO c_low_state_ndx)   := TO_UVEC(1, c_state_ndx_w);
          v.wr_sosi.valid                                                 := '0';
          IF flush_state = "10" THEN
            v.dvr_mosi.burstbegin                                         := '1';
            v.dvr_mosi.burstsize(dvr_mosi.burstsize'length-1 DOWNTO 0)    := (OTHERS => '0');
            v.dvr_mosi.wr                                                 := '1';
          ELSIF flush_state = "11" AND q_reg.timer = 0 THEN
            v.wr_sosi.valid                                               := '1';
            v.timer := 127;
          END IF;
    
          IF q_reg.timer > 0 AND rst = '0' THEN
            v.timer := q_reg.timer-1;
          END IF;
    
          IF flush_state = "01" THEN
            v.state   := WAIT_FOR_SOP;
            v.stopped := '0';
          END IF;
    
    
        WHEN STOP_READING =>
          v.ddrctrl_ctrl_state(c_high_state_ndx DOWNTO c_low_state_ndx) := TO_UVEC(2, c_state_ndx_w);
          -- this is the last read burst, this make sure every data containing word in the memory has been read.
          IF TO_UINT(rd_fifo_usedw) <= g_burstsize AND dvr_miso.done = '1' AND q_reg.rd_burst_en = '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.stopped               := '0';
            v.wr_sosi.valid         := '1';
            v.state                 := WAIT_FOR_SOP;
            v.wr_burst_en           := '1';
            v.rst_ddrctrl_input_ac  := '1';
          ELSE
            v.dvr_mosi.burstbegin   := '0';
          END IF;
          v.dvr_mosi.wr             := '0';
          v.dvr_mosi.rd             := '1';
    
          IF dvr_miso.done = '0' THEN
            v.rd_burst_en := '1';
          END IF;
    
    
        WHEN WAIT_FOR_SOP =>
          v.ddrctrl_ctrl_state(c_high_state_ndx DOWNTO c_low_state_ndx) := TO_UVEC(3, c_state_ndx_w);
          v.dvr_mosi.burstbegin                                         := '0';
          v.dvr_mosi.burstsize(dvr_mosi.burstsize'length-1 DOWNTO 0)    := (OTHERS => '0');
          v.dvr_mosi.wr                                                 := '1';
          v.dvr_mosi.rd                                                 := '0';
          v.rst_ddrctrl_input_ac  := '0';
          IF q_reg.started = '0' AND inp_sosi.eop = '1' THEN
            v.wr_sosi.valid       := '0';
          ELSIF inp_sosi.sop = '1' THEN
            v.state               := WRITING;
          ELSE
            v.wr_sosi.valid       := '0';
          END IF;
    
    
        WHEN WRITING =>
          v.ddrctrl_ctrl_state(c_high_state_ndx DOWNTO c_low_state_ndx) := TO_UVEC(4, c_state_ndx_w);
          -- this state generates the rest of the write bursts, it also checks if there is a stop signal or if it needs to stop writing.
          v.wr_bursts_ready         := TO_UINT(wr_fifo_usedw(g_wr_fifo_uw_w-1 DOWNTO c_bitshift_w));
          IF q_reg.wr_bursts_ready >= 1 AND dvr_miso.done = '1' AND q_reg.wr_burst_en = '1' AND q_reg.dvr_mosi.burstbegin = '0' THEN
            v.dvr_mosi.burstbegin   := '1';
            v.wr_burst_en           := '0';
            IF inp_adr < (g_burstsize*q_reg.wr_bursts_ready)-1 THEN
              v.dvr_mosi.address    := TO_UVEC(g_max_adr-g_last_burstsize-(g_burstsize*(q_reg.wr_bursts_ready-1)), 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*q_reg.wr_bursts_ready), 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';
    
          IF NOT (q_reg.wr_bursts_ready = 0) AND q_reg.dvr_mosi.burstbegin = '0'THEN
            v.wr_burst_en           := '1';
          ELSIF q_reg.wr_bursts_ready = 0 THEN
            v.wr_burst_en           := '0';
          END IF;
    
          IF stop_in = '1' THEN
            v.ready_for_set_stop := '1';
          END IF;
    
          IF q_reg.ready_for_set_stop = '1' AND inp_sosi.eop = '1' AND stop_in = '0' THEN
            v.state := SET_STOP;
          ELSIF q_reg.stop_adr = TO_UVEC(inp_adr, c_adr_w) THEN
            v.state := STOP_WRITING;        
          END IF;
    
    
        WHEN SET_STOP =>
          v.ddrctrl_ctrl_state(c_high_state_ndx DOWNTO c_low_state_ndx) := TO_UVEC(5, c_state_ndx_w);
          -- this state sets a stop address dependend on the g_stop_percentage.
          IF inp_adr-c_pof_ma >= 0 THEN
            v.stop_adr(c_adr_w-1 DOWNTO 0) := TO_UVEC(inp_adr-c_pof_ma, c_adr_w);
          ELSE
            v.stop_adr(c_adr_w-1 DOWNTO 0) := TO_UVEC(inp_adr+g_max_adr-c_pof_ma, c_adr_w);
          END IF;
          v.ready_for_set_stop                                        := '0';
          IF v.stop_adr(c_adr_w-1 DOWNTO 0) = c_stop_adr_zeros(c_adr_w-1 DOWNTO 0) THEN
            v.last_adr_to_write_to(c_adr_w-1 DOWNTO 0)                := TO_UVEC(g_max_adr-g_last_burstsize, c_adr_w);
          ELSE
            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);
          END IF;
          v.last_adr_to_write_to(c_bitshift_w-1 DOWNTO 0)             := (OTHERS => '0');
          v.stop_burstsize                                            := TO_UINT(INCR_UVEC(INCR_UVEC(v.stop_adr(c_adr_w-1 DOWNTO 0),-1*TO_UINT(v.last_adr_to_write_to)),1));
    
          -- still a write cyle
          -- if adr mod g_burstsize = 0
          -- this makes sure that only ones every 64 writes a writeburst is started.
          v.wr_bursts_ready         := TO_UINT(wr_fifo_usedw(g_wr_fifo_uw_w-1 DOWNTO c_bitshift_w));
          IF NOT (q_reg.wr_bursts_ready = 0) AND q_reg.dvr_mosi.burstbegin = '0'THEN
            v.wr_burst_en            := '1';
          ELSIF q_reg.wr_bursts_ready = 0 THEN
            v.wr_burst_en           := '0';
          END IF;
          IF dvr_miso.done = '1' AND q_reg.wr_burst_en = '1' THEN
            v.dvr_mosi.burstbegin   := '1';
            v.wr_burst_en            := '0';
            IF inp_adr < (g_burstsize*q_reg.wr_bursts_ready)-1 THEN
              v.dvr_mosi.address    := TO_UVEC(g_max_adr-g_last_burstsize-(g_burstsize*(q_reg.wr_bursts_ready-1)), 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*q_reg.wr_bursts_ready), 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';
    
          IF q_reg.stop_adr = TO_UVEC(inp_adr, c_adr_w) THEN
            v.state := STOP_WRITING;        
          ELSE
            v.state := WRITING;
          END IF;
    
    
        WHEN STOP_WRITING =>
          v.ddrctrl_ctrl_state(c_high_state_ndx DOWNTO c_low_state_ndx) := TO_UVEC(6, c_state_ndx_w);
          -- this state stops the writing by generating one last whole write burst which almost empties wr_fifo.
          v.wr_sosi.valid       := '0';
          v.dvr_mosi.burstbegin := '0';
          v.stopped             := '1';
          v.stop_adr            := TO_UVEC(g_max_adr, c_adr_w);
    
          -- still receiving write data.
          v.wr_bursts_ready         := TO_UINT(INCR_UVEC(wr_fifo_usedw, 2)(g_wr_fifo_uw_w-1 DOWNTO c_bitshift_w));
          IF NOT (q_reg.wr_bursts_ready = 0) AND q_reg.dvr_mosi.burstbegin = '0'THEN
            v.wr_burst_en            := '1';
          ELSIF q_reg.wr_bursts_ready = 0 THEN
            v.wr_burst_en           := '0';
          END IF;
          IF dvr_miso.done = '1' AND q_reg.wr_burst_en = '1' THEN
            v.dvr_mosi.burstbegin   := '1';
            v.wr_burst_en           := '0';
            IF inp_adr < (g_burstsize*q_reg.wr_bursts_ready)-1 THEN
              v.dvr_mosi.address    := TO_UVEC(g_max_adr-g_last_burstsize-(g_burstsize*q_reg.wr_bursts_ready-1), 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*q_reg.wr_bursts_ready), 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';
    
          IF dvr_miso.done = '1' AND q_reg.dvr_mosi.burstbegin = '0' AND q_reg.wr_burst_en = '0' AND q_reg.wr_bursts_ready = 0 AND inp_data_stopped = '1' AND TO_UINT(wr_fifo_usedw) <= q_reg.stop_burstsize THEN
            v.state := LAST_WRITE_BURST;
          END IF;
    
    
        WHEN LAST_WRITE_BURST =>
          v.ddrctrl_ctrl_state(c_high_state_ndx DOWNTO c_low_state_ndx) := TO_UVEC(7, c_state_ndx_w);
          -- this state stops the writing by generatign one last write burst which empties wr_fifo.
          v.wr_sosi.valid           := '0';
          IF dvr_miso.done = '1' THEN
            IF TO_UINT(q_reg.last_adr_to_write_to(c_adr_w-1 DOWNTO 0)) >= g_max_adr THEN
              v.dvr_mosi.address(c_adr_w-1 DOWNTO 0)  := TO_UVEC(0, c_adr_w);
              v.dvr_mosi.burstsize    :=  TO_UVEC(g_burstsize, dvr_mosi.burstsize'length);
            ELSE
              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);
            END IF;
            v.dvr_mosi.burstbegin   := '1';
            v.state                 := START_READING;
            v.rd_burst_en           := '1';
          ELSE
            v.dvr_mosi.burstbegin   := '0';
          END IF;
          v.dvr_mosi.wr             := '1';
          v.dvr_mosi.rd             := '0';
    
    
        WHEN START_READING =>
          v.ddrctrl_ctrl_state(c_high_state_ndx DOWNTO c_low_state_ndx) := TO_UVEC(8, c_state_ndx_w);
          -- this state generates the first read burst, the size of this burst is dependend on the size of the last write burst.
          v.dvr_mosi.burstbegin     := '0';
          v.outp_bsn                := INCR_UVEC(inp_sosi.bsn,-1*g_bim);
          v.wr_sosi.valid           := '0';
    
          IF dvr_miso.done = '1' AND v.rd_burst_en = '1' AND q_reg.dvr_mosi.burstbegin = '0' THEN
            IF TO_UINT(q_reg.last_adr_to_write_to(c_adr_w-1 DOWNTO 0))+q_reg.stop_burstsize >= g_max_adr THEN
              v.dvr_mosi.burstsize(dvr_mosi.burstsize'length-1 DOWNTO 0) := TO_UVEC(g_burstsize, dvr_mosi.burstsize'length);
              v.dvr_mosi.address(c_adr_w-1 DOWNTO 0)  := TO_UVEC(0, c_adr_w);
              v.read_adr            := g_burstsize;
            ELSE
              v.dvr_mosi.burstsize(dvr_mosi.burstsize'length-1 DOWNTO 0) := TO_UVEC(g_burstsize-q_reg.stop_burstsize, dvr_mosi.burstsize'length);
              v.dvr_mosi.address(c_adr_w-1 DOWNTO 0)  := INCR_UVEC(q_reg.last_adr_to_write_to(c_adr_w-1 DOWNTO 0), q_reg.stop_burstsize);
              v.read_adr            := TO_UINT(q_reg.last_adr_to_write_to(c_adr_w-1 DOWNTO 0))+g_burstsize;
            END IF;
            v.dvr_mosi.burstbegin   := '1';
            v.dvr_mosi.wr           := '0';
            v.dvr_mosi.rd           := '1';
            v.rd_burst_en           := '0';
          END IF;
    
          -- makes sure the fifo is filled before asking for another rd request. to prevent 4 rd burst to happend directly after one another.
          IF dvr_miso.done = '0' AND q_reg.rd_burst_en = '0' THEN
            v.rd_burst_en := '1';
            v.state       := READING;
          END IF;
    
    
        WHEN READING =>
          v.ddrctrl_ctrl_state(c_high_state_ndx DOWNTO c_low_state_ndx) := TO_UVEC(9, c_state_ndx_w);
          v.wr_sosi.valid         := '0';
          -- 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) <= g_burstsize AND dvr_miso.done = '1' AND q_reg.rd_burst_en = '1' THEN
            v.dvr_mosi.wr         := '0';
            v.dvr_mosi.rd         := '1';
            v.dvr_mosi.burstbegin := '1';
            v.rd_burst_en         := '0';
            IF q_reg.read_adr > g_max_adr-g_burstsize THEN
              v.dvr_mosi.address    := TO_UVEC(q_reg.read_adr, dvr_mosi.address'length);
              v.dvr_mosi.burstsize  := TO_UVEC(g_last_burstsize, dvr_mosi.burstsize'length);
              v.read_adr            := 0;
            ELSE
              v.dvr_mosi.address    := TO_UVEC(q_reg.read_adr, dvr_mosi.address'length);
              v.dvr_mosi.burstsize  := TO_UVEC(g_burstsize, dvr_mosi.burstsize'length);
              v.read_adr            := q_reg.read_adr+g_burstsize;
            END IF;
          ELSE
            v.dvr_mosi.burstbegin := '0';
          END IF;
    
          -- makes sure the fifo is filled before asking for another rd request. to prevent 4 rd burst to happend directly after one another.
          IF dvr_miso.done = '0' THEN
            v.rd_burst_en := '1';
          END IF;
    
          -- goes to STOP_reading when this read burst was from the burstblock before q_reg.stop_adr
          IF q_reg.last_adr_to_write_to(c_adr_w-1 DOWNTO 0) = TO_UVEC(q_reg.read_adr, c_adr_w) THEN
            v.state := STOP_READING;
          END IF;
    
    
        END CASE;
    
    
        IF rst = '1' THEN
          v.state := RESET;
        END IF;
    
        IF inp_sosi.eop = '1' THEN
          v.started := '1';
        END IF;
    
        v.ddrctrl_ctrl_state(c_always_one_ndx)  := '1';
        v.ddrctrl_ctrl_state(c_rst_ndx)         := rst;
        v.ddrctrl_ctrl_state(c_done_ndx)        := dvr_miso.done;
        v.ddrctrl_ctrl_state(c_bb_ndx)          := q_reg.dvr_mosi.burstbegin;
        v.ddrctrl_ctrl_state(c_ben_ndx)         := q_reg.wr_burst_en;
        v.ddrctrl_ctrl_state(c_das_ndx)         := inp_data_stopped;
        v.ddrctrl_ctrl_state(c_high_bre_ndx DOWNTO c_low_bre_ndx) := TO_UVEC(q_reg.wr_bursts_ready, 32)(c_bre_ndx_w-1 DOWNTO 0);
    
        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;
      rst_ddrctrl_input_ac  <= q_reg.rst_ddrctrl_input_ac OR rst;
      ddrctrl_ctrl_state    <= q_reg.ddrctrl_ctrl_state;
    
    
    END rtl;