Skip to content
Snippets Groups Projects
Commit 7bbeb9b4 authored by Job van Wee's avatar Job van Wee
Browse files

Stop flushing on hardware.

parent 5de47ef0
No related branches found
No related tags found
1 merge request!260Resolve L2SDP-756
Pipeline #31409 failed
-------------------------------------------------------------------------------
--
-- 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_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);
-- 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 := (((g_max_adr*(100-g_stop_percentage))/100)/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 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_io_ddr_data_w : NATURAL := func_tech_ddr_ctlr_data_w(g_tech_ddr); -- 576
-- type for statemachine
TYPE t_state IS (RESET, 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 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', '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;
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';
v.wr_sosi.valid := '1';
IF rst = '0' THEN
v.state := STOP_READING;
END IF;
WHEN STOP_READING =>
v.ddrctrl_ctrl_state(32-1 DOWNTO 0) := TO_UVEC(1, 32);
-- 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 := '0';
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(32-1 DOWNTO 0) := TO_UVEC(2, 32);
v.dvr_mosi.burstbegin := '0';
v.rst_ddrctrl_input_ac := '0';
IF q_reg.started = '0' AND inp_sosi.eop = '1' THEN
v.wr_sosi.valid := '1';
ELSIF inp_sosi.sop = '1' THEN
v.state := WRITING;
ELSE
v.wr_sosi.valid := '0';
END IF;
WHEN WRITING =>
v.ddrctrl_ctrl_state(32-1 DOWNTO 0) := TO_UVEC(3, 32);
-- 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(32-1 DOWNTO 0) := TO_UVEC(4, 32);
-- 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 TO_UINT(v.stop_adr(c_adr_w-1 DOWNTO 0)) = 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(v.stop_adr(c_adr_w-1 DOWNTO 0))-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(32-1 DOWNTO 0) := TO_UVEC(5, 32);
-- 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(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 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 THEN
v.state := LAST_WRITE_BURST;
END IF;
WHEN LAST_WRITE_BURST =>
v.ddrctrl_ctrl_state(32-1 DOWNTO 0) := TO_UVEC(6, 32);
-- 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(32-1 DOWNTO 0) := TO_UVEC(7, 32);
-- 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 := TO_UVEC(TO_UINT(inp_sosi.bsn)-g_bim, c_dp_stream_bsn_w);
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) := TO_UVEC(TO_UINT(q_reg.last_adr_to_write_to(c_adr_w-1 DOWNTO 0))+q_reg.stop_burstsize, c_adr_w);
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(32-1 DOWNTO 0) := TO_UVEC(8, 32);
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;
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;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment