Skip to content
Snippets Groups Projects
Commit efa4129e authored by Eric Kooistra's avatar Eric Kooistra
Browse files

Corrected r.dp_sosi.

parent 71eb1cd3
No related branches found
No related tags found
1 merge request!156Added first version of dp_bsn_align_v2.vhd with mmp and tb. This was...
......@@ -26,11 +26,12 @@
-- input stream that is ahead of the other remote input streams. After a
-- certain number of blocks on input 0, the same block on all remote
-- inputs should also have arrived. If not then they are replaced by
-- filler data. The output streams are paced by the block rate of input 0.
-- replacement data. The output streams are paced by the block rate of input 0.
-- The user has to read the block within the block period.
--
-- Features:
-- . uses filler flag and data to replace lost input blocks
-- . uses lost_data flag and replacement data to replace lost input blocks
-- . uses replacement data to replace disabled input streams
-- . output block can be read in arbitrary order
--
-- For more detailed description see:
......@@ -38,7 +39,7 @@
--
-- Remarks:
-- . This dp_bsn_align_v2.vhd replaces the dp_bsn_align.vhd that was used in
-- APERTIF. Mian differences are that the old component uses FIFO buffers,
-- APERTIF. Main differences are that the old component uses FIFO buffers,
-- timeouts and states, and v2 does not, which makes v2 simpler and more
-- robust.
......@@ -54,13 +55,11 @@ ENTITY dp_bsn_align_v2 IS
GENERIC (
g_nof_streams : NATURAL; -- number of input and output streams
g_bsn_latency_max : NATURAL; -- Maximum travel latency of a remote block in number of block periods T_blk
g_bsn_latency_use_node_index : BOOLEAN := FALSE; -- FALSE for align at end node, TRUE for align at every intermediate node
g_node_index_max : NATURAL := 31; -- limit to functional 5 bit range, instead of full 31 bit NATURAL range
g_nof_aligners_max : POSITIVE := 1; -- 1 when only align at last node, > 1 when align at every intermediate node
g_block_size : NATURAL := 32; -- > 1, g_block_size=1 is not supported
g_buffer_nof_blocks : NATURAL; -- circular buffer size per input, choose ceil_pow2(1 + g_bsn_latency_max)
g_bsn_w : NATURAL := c_dp_stream_bsn_w; -- number of bits in sosi BSN
g_data_w : NATURAL; -- number of bits in sosi data
g_filler_value : INTEGER := 0; -- output sosi data value for missing input blocks
g_replacement_value : INTEGER := 0; -- output sosi data value for missing input blocks
g_use_mm_output : BOOLEAN := FALSE; -- output via MM or via streaming DP
g_pipeline_input : NATURAL := 0; -- >= 0, choose 0 for wires, choose 1 to ease timing closure
g_rd_latency : NATURAL := 1 -- 1 or 2, choose 2 to ease timing closure
......@@ -69,7 +68,7 @@ ENTITY dp_bsn_align_v2 IS
dp_rst : IN STD_LOGIC;
dp_clk : IN STD_LOGIC;
node_index : IN NATURAL RANGE 0 TO g_node_index_max := 0; -- only used when g_bsn_latency_use_node_index is TRUE
node_index : IN NATURAL RANGE 0 TO g_nof_aligners_max := 0; -- only used when g_nof_aligners_max > 1
-- MM control
stream_en_arr : IN STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0) := (OTHERS=>'1');
......@@ -91,7 +90,9 @@ END dp_bsn_align_v2;
ARCHITECTURE rtl OF dp_bsn_align_v2 IS
-- Circular buffer per stream
CONSTANT c_ram_size : NATURAL := g_buffer_nof_blocks * g_block_size;
CONSTANT c_buffer_nof_blocks : NATURAL := ceil_pow2(1 + g_nof_aligners_max * g_bsn_latency_max);
CONSTANT c_ram_size : NATURAL := c_buffer_nof_blocks * g_block_size;
CONSTANT c_ram_buf : t_c_mem := (latency => 1,
adr_w => ceil_log2(c_ram_size),
dat_w => g_data_w,
......@@ -100,7 +101,7 @@ ARCHITECTURE rtl OF dp_bsn_align_v2 IS
CONSTANT c_block_size_w : NATURAL := ceil_log2(g_block_size);
CONSTANT c_block_size_slv : STD_LOGIC_VECTOR(c_block_size_w-1 DOWNTO 0) := TO_UVEC(g_block_size, c_block_size_w);
CONSTANT c_blk_pointer_w : NATURAL := ceil_log2(g_buffer_nof_blocks);
CONSTANT c_blk_pointer_w : NATURAL := ceil_log2(c_buffer_nof_blocks);
-- Use fixed slv width instead of using naturals for address calculation, to
-- avoid that synthesis may infer a too larger multiplier
......@@ -108,7 +109,7 @@ ARCHITECTURE rtl OF dp_bsn_align_v2 IS
TYPE t_bsn_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0);
TYPE t_adr_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_mem_ram.adr_w-1 DOWNTO 0);
TYPE t_filled_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(g_buffer_nof_blocks-1 DOWNTO 0);
TYPE t_filled_arr IS ARRAY (INTEGER RANGE <>) OF STD_LOGIC_VECTOR(c_buffer_nof_blocks-1 DOWNTO 0);
TYPE t_reg IS RECORD
-- p_write_arr
......@@ -116,16 +117,17 @@ ARCHITECTURE rtl OF dp_bsn_align_v2 IS
wr_copi_arr : t_mem_copi_arr(g_nof_streams-1 DOWNTO 0);
-- all streams
filled_arr : t_filled_arr(g_nof_streams-1 DOWNTO 0);
use_filler_data : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
use_replacement_data : STD_LOGIC_VECTOR(g_nof_streams-1 DOWNTO 0);
-- local reference
sync_arr : STD_LOGIC_VECTOR(g_buffer_nof_blocks-1 DOWNTO 0);
bsn_arr : t_bsn_arr(g_buffer_nof_blocks-1 DOWNTO 0);
sync_arr : STD_LOGIC_VECTOR(c_buffer_nof_blocks-1 DOWNTO 0);
bsn_arr : t_bsn_arr(c_buffer_nof_blocks-1 DOWNTO 0);
mm_sosi : t_dp_sosi;
dp_sosi : t_dp_sosi;
-- p_read
rd_pointer : INTEGER; -- use integer to detect need to wrap to natural
rd_offset : STD_LOGIC_VECTOR(c_mem_ram.adr_w-1 DOWNTO 0);
rd_copi : t_mem_copi;
fill_cipo_arr : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0); -- used combinatorial to contain rd_cipo_arr from buffer or filler data
fill_cipo_arr : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0); -- used combinatorial to contain rd_cipo_arr from buffer or replacement data
out_bsn : STD_LOGIC_VECTOR(g_bsn_w-1 DOWNTO 0); -- hold BSN for streaming output
END RECORD;
......@@ -136,6 +138,7 @@ ARCHITECTURE rtl OF dp_bsn_align_v2 IS
(OTHERS=>'0'),
(OTHERS=>(OTHERS=>'0')),
c_dp_sosi_rst,
c_dp_sosi_rst,
0,
(OTHERS=>'0'),
c_mem_copi_rst,
......@@ -152,13 +155,26 @@ ARCHITECTURE rtl OF dp_bsn_align_v2 IS
SIGNAL dp_copi : t_mem_copi;
SIGNAL dp_copi_arr : t_mem_copi_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL dp_sosi : t_dp_sosi;
SIGNAL rd_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL rd_cipo_arr : t_mem_cipo_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=>c_mem_cipo_rst);
-- Pipeline registers
SIGNAL in_sosi_arr_p : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
SIGNAL rd_copi_p : t_mem_copi;
SIGNAL rd_copi : t_mem_copi;
-- Debug signals
SIGNAL dbg_nof_streams : NATURAL := g_nof_streams;
SIGNAL dbg_bsn_latency_max : NATURAL := g_bsn_latency_max;
SIGNAL dbg_nof_aligners_max : NATURAL := g_nof_aligners_max;
SIGNAL dbg_block_size : NATURAL := g_block_size;
SIGNAL dbg_bsn_w : NATURAL := g_bsn_w;
SIGNAL dbg_data_w : NATURAL := g_data_w;
SIGNAL dbg_replacement_value : INTEGER := g_replacement_value;
SIGNAL dbg_use_mm_output : BOOLEAN := g_use_mm_output;
SIGNAL dbg_pipeline_input : NATURAL := g_pipeline_input;
SIGNAL dbg_rd_latency : NATURAL := g_rd_latency;
SIGNAL dbg_c_buffer_nof_blocks : NATURAL := c_buffer_nof_blocks;
SIGNAL dbg_c_product_w : NATURAL := c_product_w;
BEGIN
......@@ -173,14 +189,14 @@ BEGIN
END IF;
END PROCESS;
p_comb : PROCESS(r, in_sosi_arr_p, mm_copi, rd_cipo_arr, rd_sosi_arr)
p_comb : PROCESS(r, in_sosi_arr_p, mm_copi, dp_copi, rd_cipo_arr, rd_sosi_arr)
-- State variable
VARIABLE v : t_reg;
-- Auxiliary variables / local wires / no memory
VARIABLE v_ref_sosi : t_dp_sosi;
VARIABLE v_pointer_slv : STD_LOGIC_VECTOR(c_blk_pointer_w-1 DOWNTO 0);
VARIABLE v_product_slv : STD_LOGIC_VECTOR(c_product_w-1 DOWNTO 0);
VARIABLE v_filler_flag : STD_LOGIC;
VARIABLE v_lost_data_flag : STD_LOGIC;
VARIABLE v_out_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0);
BEGIN
v := r;
......@@ -221,13 +237,13 @@ BEGIN
v.bsn_arr(v.wr_pointer) := v_ref_sosi.bsn(g_bsn_w-1 DOWNTO 0);
-- . update read block pointer at g_bsn_latency_max blocks behind the reference write pointer
IF g_bsn_latency_use_node_index = FALSE THEN
IF g_nof_aligners_max = 1 THEN
v.rd_pointer := v.wr_pointer - g_bsn_latency_max;
ELSE
v.rd_pointer := v.wr_pointer - g_bsn_latency_max * node_index;
END IF;
IF v.rd_pointer < 0 THEN
v.rd_pointer := v.rd_pointer + g_buffer_nof_blocks;
v.rd_pointer := v.rd_pointer + c_buffer_nof_blocks;
END IF;
-- . update read address of read block pointer
......@@ -243,16 +259,16 @@ BEGIN
-- . pass on timestamp information
v.mm_sosi.sync := v.sync_arr(v.rd_pointer);
v.mm_sosi.bsn := RESIZE_DP_BSN(v.bsn_arr(v.rd_pointer));
-- . pass on filled flags for enabled streams via channel field, and
-- determine whether the ouput has to insert filler data
-- . pass on lost data flags for enabled streams via channel field, and
-- determine whether the ouput has to insert replacement data
v.mm_sosi.channel := (OTHERS=>'0');
FOR I IN 0 TO g_nof_streams-1 LOOP
v_filler_flag := NOT v.filled_arr(I)(v.rd_pointer);
v_lost_data_flag := NOT v.filled_arr(I)(v.rd_pointer);
IF stream_en_arr(I) = '1' THEN -- use MM bit at sop
v.use_filler_data(I) := v_filler_flag; -- enabled stream
v.mm_sosi.channel(I) := v_filler_flag;
v.use_replacement_data(I) := v_lost_data_flag; -- enabled stream, so replace if data was lost
v.mm_sosi.channel(I) := v_lost_data_flag;
ELSE
v.use_filler_data(I) := '1'; -- disabled stream
v.use_replacement_data(I) := '1'; -- disabled stream, so replace data
END IF;
END LOOP;
END IF;
......@@ -267,13 +283,13 @@ BEGIN
-- p_read
----------------------------------------------------------------------------
-- Read the data from the buffer, or replace a block by filler data
-- Read the data from the buffer, or replace a block by replacement data
-- . default use input data from the circular buffer
v.fill_cipo_arr := rd_cipo_arr;
-- . if necessary, replace a stream by filler data
-- . if necessary, replace a stream by replacement data
FOR I IN 0 TO g_nof_streams-1 LOOP
IF r.use_filler_data(I) = '1' THEN
v.fill_cipo_arr(I).rddata := TO_MEM_SDATA(g_filler_value);
IF r.use_replacement_data(I) = '1' THEN
v.fill_cipo_arr(I).rddata := TO_MEM_SDATA(g_replacement_value);
END IF;
END LOOP;
......@@ -282,8 +298,9 @@ BEGIN
-- Do the output via the MM interface
--------------------------------------------------------------------------
-- . adjust the rd address to the current buffer output block
-- sum yields c_mem_ram.adr_w bits, because left operand in ADD_UVECdetermines width
v.rd_copi := mm_copi;
v.rd_copi.address := RESIZE_MEM_ADDRESS(ADD_UVEC(r.rd_offset, mm_copi.address)); -- sum yields c_mem_ram.adr_w bits, because left operand determines width
v.rd_copi.address := RESIZE_MEM_ADDRESS(ADD_UVEC(r.rd_offset, mm_copi.address));
-- . output via MM interface
mm_cipo_arr <= v.fill_cipo_arr;
......@@ -292,20 +309,22 @@ BEGIN
-- Do the output via the DP streaming interface
--------------------------------------------------------------------------
-- . adjust the rd address
-- sum yields c_mem_ram.adr_w bits, because left operand in ADD_UVECdetermines width
v.rd_copi := dp_copi;
v.rd_copi.address := RESIZE_MEM_ADDRESS(ADD_UVEC(r.rd_offset, dp_copi.address)); -- sum yields c_mem_ram.adr_w bits, because left operand determines width
v.rd_copi.address := RESIZE_MEM_ADDRESS(ADD_UVEC(r.rd_offset, dp_copi.address));
-- . hold mm_sosi.sync, bsn
IF r.mm_sosi.sop = '1' THEN
dp_sosi <= r.mm_sosi;
v.dp_sosi := r.mm_sosi;
END IF;
-- apply mm_sosi.sync and bsn at sop to all streams in out_sosi_arr
v_out_sosi_arr := rd_sosi_arr; -- the input data from the buffer or filler data (= v.fill_cipo_arr in streaming format)
v_out_sosi_arr := rd_sosi_arr; -- = v.fill_cipo_arr in streaming format, contains the
-- input data from the buffer or replacement data
IF rd_sosi_arr(0).sop = '1' THEN
v_out_sosi_arr := func_dp_stream_arr_set(v_out_sosi_arr, dp_sosi.sync, "SYNC");
v_out_sosi_arr := func_dp_stream_arr_set(v_out_sosi_arr, dp_sosi.bsn, "BSN");
v.out_bsn := dp_sosi.bsn(g_bsn_w-1 DOWNTO 0); -- hold BSN until next sop, to ease view in wave window
v_out_sosi_arr := func_dp_stream_arr_set(v_out_sosi_arr, r.dp_sosi.sync, "SYNC");
v_out_sosi_arr := func_dp_stream_arr_set(v_out_sosi_arr, r.dp_sosi.bsn, "BSN");
v.out_bsn := r.dp_sosi.bsn(g_bsn_w-1 DOWNTO 0); -- hold BSN until next sop, to ease view in wave window
ELSE
-- hold BSN until next sop, to ease view in wave window
v_out_sosi_arr := func_dp_stream_arr_set(v_out_sosi_arr, r.out_bsn, "BSN");
......@@ -336,8 +355,8 @@ BEGIN
wr_en => r.wr_copi_arr(I).wr,
wr_adr => r.wr_copi_arr(I).address(c_ram_buf.adr_w-1 DOWNTO 0),
wr_dat => r.wr_copi_arr(I).wrdata(c_ram_buf.dat_w-1 DOWNTO 0),
rd_en => rd_copi_p.rd,
rd_adr => rd_copi_p.address(c_ram_buf.adr_w-1 DOWNTO 0),
rd_en => rd_copi.rd,
rd_adr => rd_copi.address(c_ram_buf.adr_w-1 DOWNTO 0),
rd_dat => rd_cipo_arr(I).rddata(c_ram_buf.dat_w-1 DOWNTO 0),
rd_val => rd_cipo_arr(I).rdval
);
......@@ -348,9 +367,6 @@ BEGIN
------------------------------------------------------------------------------
gen_streaming_output : IF NOT g_use_mm_output GENERATE
dp_copi <= dp_copi_arr(0);
dp_done <= dp_done_arr(0); -- for viewing only
gen_mm_to_dp : FOR I IN 0 TO g_nof_streams-1 GENERATE
u_mm_to_dp: ENTITY work.dp_block_from_mm
GENERIC MAP (
......@@ -373,6 +389,10 @@ BEGIN
out_siso => c_dp_siso_rdy
);
END GENERATE;
-- Use dp_copi_arr(0) to read same addresses in parallel for all streams
dp_copi <= dp_copi_arr(0);
dp_done <= dp_done_arr(0); -- for viewing only
END GENERATE;
......@@ -396,6 +416,6 @@ BEGIN
);
-- . read RAM
rd_copi_p <= nxt_r.rd_copi WHEN g_rd_latency = 1 ELSE r.rd_copi;
rd_copi <= nxt_r.rd_copi WHEN g_rd_latency = 1 ELSE r.rd_copi;
END rtl;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment