Newer
Older
-------------------------------------------------------------------------------
--
-- Copyright (C) 2011
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-------------------------------------------------------------------------------
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use common_lib.common_pkg.all;
use common_lib.common_mem_pkg.all;
package reorder_pkg is
type t_reorder_seq is record
wr_chunksize : positive; -- := 64;
rd_chunksize : positive; -- := 16;
rd_nof_chunks : positive; -- := 4;
rd_interval : positive; -- := 1;
gapsize : natural; -- := 0;
nof_blocks : positive; -- := 5;
end record;
constant c_reorder_seq : t_reorder_seq := (64, 16, 4, 1, 0, 5);
constant c_reorder_seq_same : t_reorder_seq := (64, 64, 1, 1, 0, 4);
type t_reorder_table is array(integer range 0 to 31, integer range 0 to 31) of natural;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
constant c_reorder_table: t_reorder_table :=
(
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
-----------------------------------------------------------------------------
-- Reorder transpose
--
-- There are several functions that yield the same transpose, but for
-- different purposes.
-- . func_reorder_transpose_indices() and
-- func_reorder_transpose_indices_impl() calculate a lookup table of all
-- indices in advance using loops.
-- . func_reorder_transpose_packet() applies func_reorder_transpose_indices()
-- on a packet list of octet values, for in a test bench.
-- . func_reorder_transpose() and func_reorder_transpose_look_up()
-- sequentially calculate the next index per clock cycle and use
-- t_reorder_transpose, for in a synthesis component.
-----------------------------------------------------------------------------
-- Block and data counters to derive select_copi.address for transpose

Eric Kooistra
committed
-- 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;

Eric Kooistra
committed
blk_offset : natural;
dat_cnt : natural;
dat_offset : natural;
word_cnt : natural;

Eric Kooistra
committed
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

Eric Kooistra
committed
-- 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;

Eric Kooistra
committed
-- Transpose function that operates on a packet
function func_reorder_transpose_packet(nof_blocks_per_packet : natural;
nof_data_per_block : natural;
nof_words_per_data : natural;
packet_list : t_slv_8_arr) return t_slv_8_arr;

Eric Kooistra
committed
-- 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;
-- 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)
return t_reorder_transpose;

Eric Kooistra
committed
-- 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;
-----------------------------------------------------------------------------
-- Reorder identity
-- . so no reordering, same out as in, but delayed due to dual page
-- buffering of reorder
-----------------------------------------------------------------------------
-- Pass on input to output in same order.
type t_reorder_identity is record
select_copi : t_mem_copi;
addr : natural;
end record;
constant c_reorder_identity_rst : t_reorder_identity := (c_mem_copi_rst, 0);

Eric Kooistra
committed
-- 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;
end reorder_pkg;
package body reorder_pkg is

Eric Kooistra
committed
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
-- Determine transpose index for input packet_index
-- . 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;

Eric Kooistra
committed
-- Apply func_reorder_transpose_indices() on a packet
function func_reorder_transpose_packet(nof_blocks_per_packet : natural;
nof_data_per_block : natural;
nof_words_per_data : natural;
packet_list : t_slv_8_arr) return t_slv_8_arr 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_list : t_slv_8_arr(packet_list'range);
begin
assert c_nof_ch = packet_list'length report "Wrong packet_list length" severity error;
for ch in 0 to c_nof_ch - 1 loop
v_list(ch) := packet_list(c_look_up_list(ch));
end loop;
return v_list;
end func_reorder_transpose_packet;
-- 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

Eric Kooistra
committed
-- . g_nof_words_per_data = 1
-- the p_comb_transpose selects:
--
-- v.blk_cnt: 0 1 2

Eric Kooistra
committed
-- 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
-- 1 4 7 10 13
-- 2 5 8 11 14
-- v.addr 0 3 6 9 12 1 4 7 10 13 2 5 8 11 14
-- data_out 0 3 6 9 12 1 4 7 10 13 2 5 8 11 14 -- transposed_sosi
--
-- and then with swapped parameter values, to get untransposed
-- output back (= original input order):
-- . g_nof_blocks_per_packet = 5 and
-- . g_nof_data_per_block = 3
-- the p_comb_undo_transpose selects:
--
-- v.blk_cnt: 0 1 2 3 4

Eric Kooistra
committed
-- 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
-- 3 4 5
-- 6 7 8
-- 9 10 11
-- 12 13 14
-- v.addr: 0 5 10 1 6 11 2 7 12 3 8 13 4 9 14
-- data_out: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 -- out_sosi
--
-- to restore the original order.
function func_reorder_transpose(nof_blocks_per_packet : natural;
nof_data_per_block : natural;

Eric Kooistra
committed
nof_words_per_data : natural;
transpose : t_reorder_transpose)
return t_reorder_transpose is

Eric Kooistra
committed
constant c_nof_words_per_block : natural := nof_words_per_data * nof_data_per_block;
variable v : t_reorder_transpose;
begin

Eric Kooistra
committed
-- 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.

Eric Kooistra
committed
-- Read at current address
v.select_copi.address := TO_MEM_ADDRESS(v.addr);
v.select_copi.rd := '1';

Eric Kooistra
committed
-- 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
-- . 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;

Eric Kooistra
committed
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;

Eric Kooistra
committed
end if;
v.addr := v.blk_offset + v.dat_offset + 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;

Eric Kooistra
committed
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;

Eric Kooistra
committed
v.word_cnt := 0;

Eric Kooistra
committed
v.addr := c_look_up_list(v.word_cnt);
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;

Eric Kooistra
committed
-- Read at current address
v.select_copi.address := TO_MEM_ADDRESS(v.addr);
v.select_copi.rd := '1';

Eric Kooistra
committed
-- Prepare next read address
if v.addr < nof_ch_per_packet - 1 then
v.addr := v.addr + 1;
else
v.addr := 0;
end if;
return v;
end;