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

Improve func_reorder_transpose() and add package test bench reorder_pkg_test.vhd.

parent c3801ebe
No related branches found
No related tags found
1 merge request!348Use use_bdo_transpose = true in c_bf revision. Test use_bdo_transpose = false...
......@@ -82,21 +82,54 @@ package reorder_pkg is
-----------------------------------------------------------------------------
-- Block and data counters to derive select_copi.address for transpose
-- reording between nof_blocks_per_packet and nof_data_per_block.
-- reordering between nof_blocks_per_packet and nof_data_per_block.
-- Optionally the data can consist of multiple words at consecutive
-- addresses. If data is one word, then word_cnt record field is not used.
type t_reorder_transpose is record
select_copi : t_mem_copi;
addr : natural;
blk_cnt : natural;
data_cnt : natural;
blk_offset : natural;
dat_cnt : natural;
dat_offset : natural;
word_cnt : natural;
end record;
constant c_reorder_transpose_rst : t_reorder_transpose := (c_mem_copi_rst, 0, 0, 0);
constant c_reorder_transpose_rst : t_reorder_transpose := (c_mem_copi_rst, 0, 0, 0, 0, 0, 0);
-- Input packet has nof_ch = nof_data_per_block * nof_blocks_per_packet of
-- data per packet.
-- The transpose.select_copi.address order will yield transposed output,
-- data per packet. The order of the words per nof_words_per_data is
-- preserved.
-- Transpose functions that operate on list of data indices
function func_reorder_transpose_indices(nof_blocks_per_packet : natural;
nof_data_per_block : natural;
nof_words_per_data : natural) return t_natural_arr;
function func_reorder_transpose_indices_impl(nof_blocks_per_packet : natural;
nof_data_per_block : natural;
nof_words_per_data : natural) return t_natural_arr;
-- Transpose functions that operate sequentially to determine the read
-- transpose.select_copi.address
-- . The transpose.select_copi.address order will yield transposed output,
-- with nof_blocks_per_packet data per block, and with nof_data_per_block
-- number of blocks per packet.
function func_reorder_transpose(nof_blocks_per_packet : natural;
nof_data_per_block : natural;
nof_words_per_data : natural;
transpose : t_reorder_transpose)
return t_reorder_transpose;
-- Alternative implementation using a look up list:
-- func_reorder_transpose_look_up() = func_reorder_transpose()
function func_reorder_transpose_look_up(nof_blocks_per_packet : natural;
nof_data_per_block : natural;
nof_words_per_data : natural;
transpose : t_reorder_transpose)
return t_reorder_transpose;
-- Variant with nof_words_per_data = 1
function func_reorder_transpose(nof_blocks_per_packet : natural;
nof_data_per_block : natural;
transpose : t_reorder_transpose)
......@@ -116,6 +149,8 @@ package reorder_pkg is
constant c_reorder_identity_rst : t_reorder_identity := (c_mem_copi_rst, 0);
-- Identity function that operates sequentially to determine the read
-- identity.select_copi.address, which is an incrementing address range.
function func_reorder_identity(nof_ch_per_packet : natural;
identity : t_reorder_identity)
return t_reorder_identity;
......@@ -124,15 +159,99 @@ end reorder_pkg;
package body reorder_pkg is
-- Determine transpose index for input packet_index
-- . Similar function as func_sdp_bdo_transpose_packet() in tb_sdp_pkg.vhd.
-- . The transpose is between nof_blocks_per_packet and nof_data_per_block.
-- Doing transpose again with swapped nof_blocks_per_packet and
-- nof_data_per_block, yields original order.
-- . The order of the words per nof_words_per_data is preserved.
-- Example for:
-- . blk in range(nof_blocks_per_packet = 4)
-- . dat in range(nof_data_per_block = 488)
-- . wi in range(nof_words_per_data = 2)
-- input packet_index v_in:
-- . blk 0, 1, 2, 3
-- . dat 0, ... 487, 0, ... 487, 0, ... 487, 0, ... 487
-- . wi 0,1, ... 0,1, 0,1, ... 0,1, 0,1, ... 0,1, 0,1, ... 0,1
-- . v_in 0, ... 975, 976, ...1951,1952, ...2927,2928, ...3903
-- return index v_out:
-- . wi 0,1,0,1,0,1,0,1, ..., 0,1,0,1,0,1,0,1
-- . blk 0, 1, 2, 3, ..., 0, 1, 2, 3
-- . dat 0, ..., 487
-- . v_out 0,1, 976, 977, 1952,1953, 2928,2929,
-- 2,3, 978, 979, 1954,1955, 2930,2931,
-- ..., ..., ..., ...,
-- 972,973, 1948,1949, 2924,2925, 3900,3901,
-- 974,775, 1950,1951, 2926,2927, 3902,3903
function func_reorder_transpose_indices(nof_blocks_per_packet : natural;
nof_data_per_block : natural;
nof_words_per_data : natural) return t_natural_arr is
constant c_nof_ch : natural := nof_blocks_per_packet * nof_data_per_block * nof_words_per_data;
variable v_arr : t_natural_arr(0 to c_nof_ch - 1);
variable v_in : natural;
variable v_out : natural;
variable v_ch : natural := 0;
begin
-- Use outer loop blk and inner loop dat to have v_in = v_ch.
-- Use outer loop dat and inner loop blk to have v_out = v_ch.
-- For the return v_arr it does not matter which loop is the outer loop
-- or the inner loop. Choose to have v_out = v_ch, because then the
-- values in v_arr are calculated in output order, similar as if they
-- are output sequentially by reorder_col_select.
for dat in 0 to nof_data_per_block - 1 loop
for blk in 0 to nof_blocks_per_packet - 1 loop
for wi in 0 to nof_words_per_data - 1 loop
-- v_out is the transpose index for index v_in, so output value at
-- index v_out becomes input value at index v_in
v_in := (blk * nof_data_per_block + dat) * nof_words_per_data + wi;
v_out := (dat * nof_blocks_per_packet + blk) * nof_words_per_data + wi;
assert v_out = v_ch report "Wrong index in func_reorder_transpose_indices()" severity failure;
v_arr(v_out) := v_in;
v_ch := v_ch + 1;
end loop;
end loop;
end loop;
return v_arr;
end;
-- The func_reorder_transpose_indices_impl() yields the same as
-- func_reorder_transpose_indices(), except that it uses only
-- additions to calculate the indices, so no multiplications in
-- the loops.
function func_reorder_transpose_indices_impl(nof_blocks_per_packet : natural;
nof_data_per_block : natural;
nof_words_per_data : natural) return t_natural_arr is
constant c_nof_ch : natural := nof_blocks_per_packet * nof_data_per_block * nof_words_per_data;
constant c_nof_words_per_block : natural := nof_words_per_data * nof_data_per_block;
variable v_blk_offset : natural := 0;
variable v_dat_offset : natural := 0;
variable v_arr : t_natural_arr(0 to c_nof_ch - 1);
variable v_ch : natural := 0;
begin
for dat in 0 to nof_data_per_block - 1 loop
for blk in 0 to nof_blocks_per_packet - 1 loop
for wi in 0 to nof_words_per_data - 1 loop
v_arr(v_ch) := v_blk_offset + v_dat_offset + wi;
v_ch := v_ch + 1;
end loop;
v_blk_offset := v_blk_offset + c_nof_words_per_block;
end loop;
v_blk_offset := 0;
v_dat_offset := v_dat_offset + nof_words_per_data;
end loop;
return v_arr;
end;
-- A transpose process and an undo transpose process can both use
-- func_reorder_transpose(), by swapping the transpose dimensions.
-- For example, to get transposed output with:
-- . g_nof_blocks_per_packet = 3 and
-- . g_nof_data_per_block = 5
-- . g_nof_words_per_data = 1
-- the p_comb_transpose selects:
--
-- v.blk_cnt: 0 1 2
-- v.data_cnt: 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
-- v.dat_cnt: 0 1 2 3 4 0 1 2 3 4 0 1 2 3 4
-- ch: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
-- data_in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 -- in_sosi
-- transpose: 0 3 6 9 12
......@@ -148,7 +267,7 @@ package body reorder_pkg is
-- the p_comb_undo_transpose selects:
--
-- v.blk_cnt: 0 1 2 3 4
-- v.data_cnt: 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2
-- v.dat_cnt: 0 1 2 0 1 2 0 1 2 0 1 2 0 1 2
-- ch: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
-- data_in 0 3 6 9 12 1 4 7 10 13 2 5 8 11 14 -- transposed_sosi
-- undo_transpose: 0 1 2
......@@ -162,45 +281,102 @@ package body reorder_pkg is
-- to restore the original order.
function func_reorder_transpose(nof_blocks_per_packet : natural;
nof_data_per_block : natural;
nof_words_per_data : natural;
transpose : t_reorder_transpose)
return t_reorder_transpose is
constant c_nof_words_per_block : natural := nof_words_per_data * nof_data_per_block;
variable v : t_reorder_transpose;
begin
-- Implementation derived from func_reorder_transpose_indices_impl().
-- Instead of using incrementing v_ch and for-loops to return list of all
-- read indices, use sequential calls of this func_reorder_transpose()
-- to return next read address.
v := transpose;
-- read at current address
-- Read at current address
v.select_copi.address := TO_MEM_ADDRESS(v.addr);
v.select_copi.rd := '1';
-- prepare next read address
if v.blk_cnt <= nof_blocks_per_packet - 1 then
if v.data_cnt < nof_data_per_block - 1 then
v.data_cnt := v.data_cnt + 1;
v.addr := v.addr + nof_blocks_per_packet;
-- Prepare next read address
-- . loop word_cnt
if v.word_cnt < nof_words_per_data - 1 then
v.word_cnt := v.word_cnt + 1;
else
v.data_cnt := 0;
-- . end loop word_cnt
v.word_cnt := 0;
-- . loop blk_cnt
if v.blk_cnt < nof_blocks_per_packet - 1 then
v.blk_cnt := v.blk_cnt + 1;
if v.blk_cnt = nof_blocks_per_packet then
v.blk_offset := v.blk_offset + c_nof_words_per_block;
else
-- . end loop blk_cnt
v.blk_cnt := 0;
v.blk_offset := 0;
-- . loop dat_cnt
if v.dat_cnt < nof_data_per_block - 1 then
v.dat_cnt := v.dat_cnt + 1;
v.dat_offset := v.dat_offset + nof_words_per_data;
else
-- . end loop dat_cnt
v.dat_cnt := 0;
v.dat_offset := 0;
end if;
end if;
v.addr := v.blk_cnt;
end if;
v.addr := v.blk_offset + v.dat_offset + v.word_cnt;
return v;
end;
function func_reorder_transpose_look_up(nof_blocks_per_packet : natural;
nof_data_per_block : natural;
nof_words_per_data : natural;
transpose : t_reorder_transpose)
return t_reorder_transpose is
constant c_nof_ch : natural := nof_blocks_per_packet * nof_data_per_block * nof_words_per_data;
constant c_look_up_list : t_natural_arr(0 to c_nof_ch - 1) :=
func_reorder_transpose_indices(nof_blocks_per_packet,
nof_data_per_block,
nof_words_per_data);
variable v : t_reorder_transpose;
begin
-- Equivalent implementation, so func_reorder_transpose_look_up() =
-- func_reorder_transpose()
v := transpose;
-- Read at current address
v.select_copi.address := TO_MEM_ADDRESS(v.addr);
v.select_copi.rd := '1';
-- Prepare next read address
-- . use word_cnt as incrementing ch index to count the sequential calls
-- of this func_reorder_transpose() to return next read address
if v.word_cnt < c_nof_ch - 1 then
v.word_cnt := v.word_cnt + 1;
else
v.data_cnt := 0;
v.blk_cnt := 0;
v.addr := 0;
v.word_cnt := 0;
end if;
v.addr := c_look_up_list(v.word_cnt);
return v;
end;
function func_reorder_transpose(nof_blocks_per_packet : natural;
nof_data_per_block : natural;
transpose : t_reorder_transpose)
return t_reorder_transpose is
begin
return func_reorder_transpose(nof_blocks_per_packet,
nof_data_per_block,
1,
transpose);
end;
function func_reorder_identity(nof_ch_per_packet : natural;
identity : t_reorder_identity)
return t_reorder_identity is
variable v : t_reorder_identity;
begin
v := identity;
-- read at current address
-- Read at current address
v.select_copi.address := TO_MEM_ADDRESS(v.addr);
v.select_copi.rd := '1';
-- prepare next read address
-- Prepare next read address
if v.addr < nof_ch_per_packet - 1 then
v.addr := v.addr + 1;
else
......
-------------------------------------------------------------------------------
--
-- Copyright 2023
-- 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 : E. Kooistra
-- Purpose:
-- Test bench to verify functions in reorder_pkg.vhd.
-- Description:
--
-- Usage:
-- > as 3
-- > run -all
-- * The tb is self stopping and self checking, tb_end will stop the simulation
-- by stopping the clk and thus all toggling.
library IEEE, common_lib, dp_lib;
use IEEE.std_logic_1164.all;
use common_lib.common_pkg.all;
use common_lib.common_mem_pkg.all;
use common_lib.tb_common_pkg.all;
use dp_lib.dp_stream_pkg.all;
use work.reorder_pkg.all;
entity reorder_pkg_test is
generic(
g_nof_blocks_per_packet : natural := 4;
g_nof_data_per_block : natural := 488;
g_nof_words_per_data : natural := 1
);
end reorder_pkg_test;
architecture tb of reorder_pkg_test is
constant c_clk_period : time := 10 ns;
constant c_nof_data : natural := g_nof_blocks_per_packet * g_nof_data_per_block;
signal rst : std_logic;
signal clk : std_logic := '1';
signal tb_end : std_logic := '0';
-- Verify default and alternative (lu = look up) implementation of r_transpose
signal r_transpose : t_reorder_transpose := c_reorder_transpose_rst;
signal r_transpose_lu : t_reorder_transpose := c_reorder_transpose_rst;
signal in_address : natural := 0;
signal in_val : std_logic := '0';
signal out_address : natural;
signal out_address_lu : natural;
signal out_val : std_logic;
signal exp_address : natural;
constant c_exp_addresses_arr : t_natural_arr := func_reorder_transpose_indices(g_nof_blocks_per_packet,
g_nof_data_per_block,
g_nof_words_per_data);
constant c_impl_addresses_arr : t_natural_arr := func_reorder_transpose_indices_impl(g_nof_blocks_per_packet,
g_nof_data_per_block,
g_nof_words_per_data);
begin
assert c_exp_addresses_arr = c_impl_addresses_arr report "Wrong func_reorder_transpose_indices_impl()" severity failure;
clk <= (not clk) or tb_end after c_clk_period / 2;
rst <= '1', '0' after c_clk_period * 7;
p_stimuli : process
begin
proc_common_wait_until_low(clk, rst);
proc_common_wait_some_cycles(clk, 5);
for I in 0 to c_nof_data - 1 loop
in_val <= '1';
in_address <= I;
r_transpose <= func_reorder_transpose(
g_nof_blocks_per_packet, g_nof_data_per_block, g_nof_words_per_data, r_transpose);
r_transpose_lu <= func_reorder_transpose_look_up(
g_nof_blocks_per_packet, g_nof_data_per_block, g_nof_words_per_data, r_transpose_lu);
proc_common_wait_some_cycles(clk, 1);
end loop;
in_val <= '0';
r_transpose <= c_reorder_transpose_rst;
r_transpose_lu <= c_reorder_transpose_rst;
proc_common_wait_some_cycles(clk, 5);
tb_end <= '1';
wait;
end process;
out_address <= TO_UINT(r_transpose.select_copi.address);
out_address_lu <= TO_UINT(r_transpose_lu.select_copi.address);
out_val <= r_transpose.select_copi.rd;
exp_address <= c_exp_addresses_arr(in_address);
p_verify : process(clk)
begin
if rising_edge(clk) then
if in_val = '1' then
-- Only when valid expect that out_address = exp_address
assert out_address = exp_address report "Wrong transpose address" severity error;
end if;
-- Always expect that out_address_lu = out_address
assert out_address_lu = out_address report "Wrong transpose_lu address" severity error;
end if;
end process;
end tb;
-------------------------------------------------------------------------------
--
-- Copyright 2023
-- 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 : E. Kooistra
-- Purpose:
-- Multi test bench to verify functions in reorder_pkg.vhd using instances
-- of reorder_pkg_test.vhd.
-- Description:
--
-- Usage:
-- > as 3
-- > run -all
-- * The tb is self stopping and self checking, tb_end will stop the simulation
-- by stopping the clk and thus all toggling.
library IEEE;
use IEEE.std_logic_1164.all;
entity reorder_pkg_test_test is
end reorder_pkg_test_test;
architecture tb of reorder_pkg_test_test is
signal tb_end : std_logic := '0'; -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end'
begin
-- g_nof_blocks_per_packet : natural := 4;
-- g_nof_data_per_block : natural := 488;
-- g_nof_words_per_data : natural := 1
u_4_488_1 : entity work.reorder_pkg_test generic map (4, 488, 1);
u_4_488_2 : entity work.reorder_pkg_test generic map (4, 488, 2);
end tb;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment