diff --git a/applications/lofar1/pfb2/src/vhdl/wpfb_unit_dev.vhd b/applications/lofar1/pfb2/src/vhdl/wpfb_unit_dev.vhd deleted file mode 100644 index 8ce1683177a1d182ac838b7688556aefcd3723ff..0000000000000000000000000000000000000000 --- a/applications/lofar1/pfb2/src/vhdl/wpfb_unit_dev.vhd +++ /dev/null @@ -1,718 +0,0 @@ --------------------------------------------------------------------------------- --- Author: Harm Jan Pepping : HJP at astron.nl: April 2012 --------------------------------------------------------------------------------- --- --- Copyright (C) 2012 --- 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/>. --- --------------------------------------------------------------------------------- --- Purpose: Wideband polyphase filterbank with subband statistics and streaming interfaces. --- --- Description: --- --- This WPFB unit connects an incoming array of streaming interfaces to the --- wideband pft + fft. --- The output of the wideband fft is connected to a set of subband statistics --- units. The statistics can be read via the memory mapped interface. --- A control unit takes care of the correct composition of the control of the --- output streams regarding sop, eop, sync, bsn, err. --- --- The wpfb unit can handle a wideband factor >= 1 (g_wpfb.wb_factor) or --- a narrowband factor >= 1 (2**g_wpfb.nof_chan). --- . For wb_factor = 1 the wpfb_unit uses fft_r2_pipe --- . For wb_factor > 1 the wpfb_unit uses fft_r2_wide --- . For wb_factor >= 1 the wpfb_unit supports nof_chan >= 0, even though the --- concept of channels is typically not useful when wb_factor > 1. --- . The wpfb_unit does support use_reorder. --- . The wpfb_unit does support use_separate. --- . The wpfb_unit does support input flow control with invalid gaps in the --- input. --- --- . g_coefs_file_prefix: --- The g_coefs_file_prefix points to the location where the files --- with the initial content for the coefficients memories are located and --- is described in fil_ppf_wide.vhd. --- --- . fft_out_gain_w --- For two real input typically fft_out_gain_w = 1 is used to compensate for --- the divide by 2 in the separate function that is done because real input --- frequency bins have norm 0.5. For complex input typically fft_out_gain_w --- = 0, because the complex bins have norm 1. --- --- . g_dont_flip_channels: --- True preserves channel interleaving, set by g_wpfb.nof_chan>0, of the FFT --- output when g_bit_flip=true to reorder the FFT output. --- The g_dont_flip_channels applies for both complex input and two_real --- input FFT. The g_dont_flip_channels is only implemented for the pipelined --- fft_r2_pipe, because for g_wpfb.wb_factor=1 using g_wpfb.nof_chan>0 makes --- sense, while for the fft_r2_wide with g_wpfb.wb_factor>1 using input --- multiplexing via g_wpfb.nof_chan>0 makes less sense. --- --- The reordering to the fil_ppf_wide is done such that the FIR filter --- coefficients are reused. The same filter coefficients are used for all --- streams. The filter has real coefficients, because the filterbank --- channels are symmetrical in frequency. The real part and the imaginary --- part are filtered independently and also use the same real FIR --- coefficients. --- --- Note that: --- . The same P of all streams are grouped the in filter and all P per --- stream are grouped in the FFT. Hence the WPFB input is grouped per --- P for all wideband streams to allow FIR coefficients reuse per P --- for all wideband streams. The WPFB output is grouped per wideband --- stream to have all P together. --- --- . The wideband time index t is big-endian inside the prefilter and --- little-endian inside the FFT. --- When g_big_endian_wb_in=true then the WPFB input must be in big-endian --- format, else in little-endian format. --- For little-endian time index t increments in the same direction as the --- wideband factor index P, so P = 0, 1, 2, 3 --> t0, t1, t2, t3. --- For big-endian the time index t increments in the opposite direction of --- the wideband factor index P, so P = 3, 2, 1, 0 --> t0, t1, t2, t3. --- The WPFB output is fixed little-endian, so with frequency bins in --- incrementing order. However the precise frequency bin order depends --- on the reorder generics. --- --- When wb_factor = 4 and nof_wb_streams = 2 the mapping is as follows using --- the array notation: --- --- . I = array index --- . S = stream index of a wideband stream --- . P = wideband factor index --- . t = time index --- --- parallel serial type --- in_sosi_arr [nof_streams][wb_factor] [t] cint --- --- fil_in_arr [wb_factor][nof_streams][complex] [t] int --- fil_out_arr [wb_factor][nof_streams][complex] [t] int --- --- fil_sosi_arr [nof_streams][wb_factor] [t] cint --- fft_in_re_arr [nof_streams][wb_factor] [t] int --- fft_in_im_arr [nof_streams][wb_factor] [t] int --- fft_out_re_arr [nof_streams][wb_factor] [bin] int --- fft_out_im_arr [nof_streams][wb_factor] [bin] int --- fft_out_sosi_arr [nof_streams][wb_factor] [bin] cint --- pfb_out_sosi_arr [nof_streams][wb_factor] [bin] cint with sync, BSN, sop, eop --- out_sosi_arr [nof_streams][wb_factor] [bin] cint with sync, BSN, sop, eop --- --- in_sosi_arr | fil_in_arr | fft_in_re_arr | fft_out_re_arr --- fil_sosi_arr | fil_out_arr | fft_in_im_arr | fft_out_im_arr --- | | | fft_out_sosi_arr --- | | | pfb_out_sosi_arr --- | | | out_sosi_arr --- | | | --- I S P t | I P S | I S P t | I S P --- 7 1 3 0 | 15 3 1 IM | 7 1 3 3 | 7 1 3 --- 6 1 2 1 | 14 3 1 RE | 6 1 2 2 | 6 1 2 --- 5 1 1 2 | 13 3 0 IM | 5 1 1 1 | 5 1 1 --- 4 1 0 3 | 12 3 0 RE | 4 1 0 0 | 4 1 0 --- 3 0 3 0 | 11 2 1 IM | 3 0 3 3 | 3 0 3 --- 2 0 2 1 | 10 2 1 RE | 2 0 2 2 | 2 0 2 --- 1 0 1 2 | 9 2 0 IM | 1 0 1 1 | 1 0 1 --- 0 0 0 3 | 8 2 0 RE | 0 0 0 0 | 0 0 0 --- | 7 1 1 IM | | --- ^ | 6 1 1 RE | ^ | --- big | 5 1 0 IM | little | --- endian | 4 1 0 RE | endian | --- | 3 0 1 IM | | --- | 2 0 1 RE | | --- | 1 0 0 IM | | --- | 0 0 0 RE | | --- --- The WPFB output are the frequency bins per transformed block: --- . subbands, in case ot two real input or --- . channels, in case of complex input --- --- The order of the WPFB output depends on the g_fft fields: --- . wb_factor --- . use_reorder --- . use_fft_shift --- . use_separate --- --- The frequency bin order at the output is obtained with reg_out_bin --- in the test bench tb_wpfb_unit_dev.vhd. --- --- Output examples: --- --- Frequency bins: --- fs = sample frequency --- Bb = fs/nof_points = bin bandwidth --- --- 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 --- ^ ^ ^ ^ ^ --- <--------- negative bin frequencies ---------> 0 <---------- positive bin frequencies -------> --- -fs/2 -Bb 0 +Bb +fs/2-Bb --- --- I) Wideband wb_factor = 4 --- 1) Two real inputs: --- --- out_sosi_arr: --- I S P bin frequency order . nof_streams = 2 --- 7 1 3 12 12 13 13 14 14 15 15 . wb_factor = 4 --- 6 1 2 8 8 9 9 10 10 11 11 . nof_points = 32 --- 5 1 1 4 4 5 5 6 6 7 7 . use_reorder = true --- 4 1 0 0 0 1 1 2 2 3 3 . use_fft_shift = false --- 3 0 3 12 12 13 13 14 14 15 15 . use_separate = true --- 2 0 2 8 8 9 9 10 10 11 11 - input A via in_sosi_arr().re --- 1 0 1 4 4 5 5 6 6 7 7 - input B via in_sosi_arr().im --- 0 0 0 0 0 1 1 2 2 3 3 --- input A B A B A B A B --- --- when nof_chan=1 then: --- I S P bin frequency order --- 7 1 3 12 12 13 13 14 14 15 15 12 12 13 13 14 14 15 15 --- 6 1 2 8 8 9 9 10 10 11 11 8 8 9 9 10 10 11 11 --- 5 1 1 4 4 5 5 6 6 7 7 4 4 5 5 6 6 7 7 --- 4 1 0 0 0 1 1 2 2 3 3 0 0 1 1 2 2 3 3 --- 3 0 3 12 12 13 13 14 14 15 15 12 12 13 13 14 14 15 15 --- 2 0 2 8 8 9 9 10 10 11 11 8 8 9 9 10 10 11 11 --- 1 0 1 4 4 5 5 6 6 7 7 4 4 5 5 6 6 7 7 --- 0 0 0 0 0 1 1 2 2 3 3 0 0 1 1 2 2 3 3 --- input A B A B A B A B A B A B A B A B --- channel 0....................0 1....................1 --- --- 2a) Complex input with fft_shift: --- --- out_sosi_arr: --- I S P bin frequency order . nof_streams = 2 --- 7 1 3 24 25 26 27 28 29 30 31 . wb_factor = 4 --- 6 1 2 16 17 18 19 20 21 22 23 . nof_points = 32 --- 5 1 1 8 9 10 11 12 13 14 15 . use_reorder = true --- 4 1 0 0 1 2 3 4 5 6 7 . use_fft_shift = true --- 3 0 3 24 25 26 27 28 29 30 31 . use_separate = false --- 2 0 2 16 17 18 19 20 21 22 23 - complex input via in_sosi_arr().re and im --- 1 0 1 8 9 10 11 12 13 14 15 --- 0 0 0 0 1 2 3 4 5 6 7 --- --- when nof_chan=1 then: --- I S P bin frequency order --- 7 1 3 24 25 26 27 28 29 30 31 24 25 26 27 28 29 30 31 --- 6 1 2 16 17 18 19 20 21 22 23 16 17 18 19 20 21 22 23 --- 5 1 1 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15 --- 4 1 0 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 --- 3 0 3 24 25 26 27 28 29 30 31 24 25 26 27 28 29 30 31 --- 2 0 2 16 17 18 19 20 21 22 23 16 17 18 19 20 21 22 23 --- 1 0 1 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15 --- 0 0 0 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 --- channel 0....................0 1....................1 --- --- 2b) Complex input with reorder, but no fft_shift: --- --- out_sosi_arr: --- I S P bin frequency order . nof_streams = 2 --- 7 1 3 8 9 10 11 12 13 14 15 . wb_factor = 4 --- 6 1 2 0 1 2 3 4 5 6 7 . nof_points = 32 --- 5 1 1 24 25 26 27 28 29 30 31 . use_reorder = true --- 4 1 0 16 17 18 19 20 21 22 23 . use_fft_shift = false --- 3 0 3 8 9 10 11 12 13 14 15 . use_separate = false --- 2 0 2 0 1 2 3 4 5 6 7 - complex input via in_sosi_arr().re and im --- 1 0 1 24 25 26 27 28 29 30 31 --- 0 0 0 16 17 18 19 20 21 22 23 --- --- when nof_chan=1 then: --- I S P bin frequency order --- 7 1 3 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15 --- 6 1 2 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 --- 5 1 1 24 25 26 27 28 29 30 31 24 25 26 27 28 29 30 31 --- 4 1 0 16 17 18 19 20 21 22 23 16 17 18 19 20 21 22 23 --- 3 0 3 8 9 10 11 12 13 14 15 8 9 10 11 12 13 14 15 --- 2 0 2 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 --- 1 0 1 24 25 26 27 28 29 30 31 24 25 26 27 28 29 30 31 --- 0 0 0 16 17 18 19 20 21 22 23 16 17 18 19 20 21 22 23 --- channel 0....................0 1....................1 --- --- 2c) Complex input without reorder (so bit flipped): --- --- out_sosi_arr: --- I S P bin frequency order . nof_streams = 2 --- 7 1 3 8 12 10 14 9 13 11 15 . wb_factor = 4 --- 6 1 2 24 28 26 30 25 29 27 31 . nof_points = 32 --- 5 1 1 0 4 2 6 1 5 3 7 . use_reorder = false --- 4 1 0 16 20 18 22 17 21 19 23 . use_fft_shift = false --- 3 0 3 8 12 10 14 9 13 11 15 . use_separate = false --- 2 0 2 24 28 26 30 25 29 27 31 - complex input via in_sosi_arr().re and im --- 1 0 1 0 4 2 6 1 5 3 7 --- 0 0 0 16 20 18 22 17 21 19 23 --- --- when nof_chan=1 then: --- I S P bin frequency order --- 7 1 3 8 8 12 12 10 10 14 14 9 9 13 13 11 11 15 15 --- 6 1 2 24 24 28 28 26 26 30 30 25 25 29 29 27 27 31 31 --- 5 1 1 0 0 4 4 2 2 6 6 1 1 5 5 3 3 7 7 --- 4 1 0 16 16 20 20 18 18 22 22 17 17 21 21 19 19 23 23 --- 3 0 3 8 8 12 12 10 10 14 14 9 9 13 13 11 11 15 15 --- 2 0 2 24 24 28 28 26 26 30 30 25 25 29 29 27 27 31 31 --- 1 0 1 0 0 4 4 2 2 6 6 1 1 5 5 3 3 7 7 --- 0 0 0 16 16 20 20 18 18 22 22 17 17 21 21 19 19 23 23 --- channel 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 --- --- II) Narrowband wb_factor = 1 --- --- 1) Two real inputs: --- --- . nof_streams = 2 --- . nof_chan = 0 --- . wb_factor = 1 --- . nof_points = 32 --- . use_reorder = true --- . use_fft_shift = false --- . use_separate = true --- - input A via in_sosi_arr().re --- - input B via in_sosi_arr().im --- --- out_sosi_arr: --- I S P bin frequency order --- 1 1 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 --- 0 0 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 --- input A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B --- --- when nof_chan=1 then: --- I S P bin frequency order --- 1 1 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 --- 0 0 0 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 --- input A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B A B --- channel: 0............................................................................................0 1............................................................................................1 --- --- 2) Complex input --- . nof_streams = 2 --- . nof_chan = 0 --- . wb_factor = 1 --- . nof_points = 32 --- . use_separate = false --- - complex input via in_sosi_arr().re and im - --- 2a) Complex input with fft_shift (so use_reorder = true, use_fft_shift = true) --- --- out_sosi_arr: --- I S P bin frequency order --- 1 1 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 --- 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 --- --- when nof_chan=1 then: --- I S P bin frequency order --- 1 1 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 --- 0 0 0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 --- channel: 0............................................................................................0 1............................................................................................1 --- --- 2b) Complex input with reorder but no fft_shift (so use_reorder = true, use_fft_shift = false) --- --- out_sosi_arr: --- I S P bin frequency order --- 1 1 0 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 --- 0 0 0 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 --- --- when nof_chan=1 then: --- I S P bin frequency order --- 1 1 0 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 --- 0 0 0 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 --- channel: 0............................................................................................0 1............................................................................................1 --- --- 2c) Complex input without reorder (so use_reorder = false, use_fft_shift = false) --- --- out_sosi_arr: --- I S P bin frequency order --- 1 1 0 16 0 24 8 20 4 28 12 18 2 26 10 22 6 30 14 17 1 25 9 21 5 29 13 19 3 27 11 23 7 31 15 --- 0 0 0 16 0 24 8 20 4 28 12 18 2 26 10 22 6 30 14 17 1 25 9 21 5 29 13 19 3 27 11 23 7 31 15 --- --- when nof_chan=1 then: --- I S P bin frequency order --- 1 1 0 16 16 0 0 24 24 8 8 20 20 4 4 28 28 12 12 18 18 2 2 26 26 10 10 22 22 6 6 30 30 14 14 17 17 1 1 25 25 9 9 21 21 5 5 29 29 13 13 19 19 3 3 27 27 11 11 23 23 7 7 31 31 15 15 --- 0 0 0 16 16 0 0 24 24 8 8 20 20 4 4 28 28 12 12 18 18 2 2 26 26 10 10 22 22 6 6 30 30 14 14 17 17 1 1 25 25 9 9 21 21 5 5 29 29 13 13 19 19 3 3 27 27 11 11 23 23 7 7 31 31 15 15 --- channel: 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 --- --- Remarks: --- . The unit can handle only one sync at a time. Therfor the --- sync interval should be larger than the total pipeline --- stages of the wideband fft. --- - -library ieee, common_lib, dp_lib, rTwoSDF_lib, st_lib, filter_lib, fft_lib, diag_lib; -use IEEE.std_logic_1164.all; -use STD.textio.all; -use common_lib.common_pkg.all; -use common_lib.common_mem_pkg.all; -use dp_lib.dp_stream_pkg.ALL; -use rTwoSDF_lib.rTwoSDFPkg.all; -use st_lib.all; -use filter_lib.all; -use filter_lib.fil_pkg.all; -use fft_lib.all; -use fft_lib.fft_pkg.all; -use work.wpfb_pkg.all; - -entity wpfb_unit_dev is - generic ( - g_big_endian_wb_in : boolean := true; - g_wpfb : t_wpfb; - g_dont_flip_channels: boolean := false; -- True preserves channel interleaving for pipelined FFT - g_use_prefilter : boolean := TRUE; - g_stats_ena : boolean := TRUE; -- Enables the statistics unit - g_use_bg : boolean := FALSE; - g_coefs_file_prefix : string := "data/coefs_wide" -- File prefix for the coefficients files. - ); - port ( - dp_rst : in std_logic := '0'; - dp_clk : in std_logic; - mm_rst : in std_logic; - mm_clk : in std_logic; - ram_fil_coefs_mosi : in t_mem_mosi := c_mem_mosi_rst; - ram_fil_coefs_miso : out t_mem_miso; - ram_st_sst_mosi : in t_mem_mosi := c_mem_mosi_rst; -- Subband statistics registers - ram_st_sst_miso : out t_mem_miso; - reg_bg_ctrl_mosi : in t_mem_mosi := c_mem_mosi_rst; - reg_bg_ctrl_miso : out t_mem_miso; - ram_bg_data_mosi : in t_mem_mosi := c_mem_mosi_rst; - ram_bg_data_miso : out t_mem_miso; - in_sosi_arr : in t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - fil_sosi_arr : out t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - out_sosi_arr : out t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0) - ); -end entity wpfb_unit_dev; - -architecture str of wpfb_unit_dev is - - constant c_nof_channels : natural := 2**g_wpfb.nof_chan; - - constant c_nof_data_per_block : natural := c_nof_channels * g_wpfb.nof_points; - constant c_nof_valid_per_block : natural := c_nof_data_per_block / g_wpfb.wb_factor; - - constant c_nof_stats : natural := c_nof_valid_per_block; - - constant c_fil_ppf : t_fil_ppf := (g_wpfb.wb_factor, - g_wpfb.nof_chan, - g_wpfb.nof_points, - g_wpfb.nof_taps, - c_nof_complex*g_wpfb.nof_wb_streams, -- Complex FFT always requires 2 filter streams: real and imaginary - g_wpfb.fil_backoff_w, - g_wpfb.fil_in_dat_w, - g_wpfb.fil_out_dat_w, - g_wpfb.coef_dat_w); - - constant c_fft : t_fft := (g_wpfb.use_reorder, - g_wpfb.use_fft_shift, - g_wpfb.use_separate, - g_wpfb.nof_chan, - g_wpfb.wb_factor, - 0, - g_wpfb.nof_points, - g_wpfb.fft_in_dat_w, - g_wpfb.fft_out_dat_w, - g_wpfb.fft_out_gain_w, - g_wpfb.stage_dat_w, - g_wpfb.guard_w, - g_wpfb.guard_enable, - g_wpfb.stat_data_w, - g_wpfb.stat_data_sz); - - constant c_fft_r2_check : boolean := fft_r2_parameter_asserts(c_fft); - - constant c_bg_buf_adr_w : natural := ceil_log2(g_wpfb.nof_points/g_wpfb.wb_factor); - constant c_bg_data_file_index_arr : t_nat_natural_arr := array_init(0, g_wpfb.nof_wb_streams*g_wpfb.wb_factor, 1); - constant c_bg_data_file_prefix : string := "UNUSED"; - - signal ram_st_sst_mosi_arr : t_mem_mosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - signal ram_st_sst_miso_arr : t_mem_miso_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0) := (others => c_mem_miso_rst); - - signal fil_in_arr : t_fil_slv_arr(c_nof_complex*g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - signal fil_in_val : std_logic; - signal fil_out_arr : t_fil_slv_arr(c_nof_complex*g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - signal fil_out_val : std_logic; - - signal fft_in_re_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - signal fft_in_im_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - signal fft_in_val : std_logic; - - signal fft_out_re_arr_i : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - signal fft_out_im_arr_i : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - signal fft_out_re_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - signal fft_out_im_arr : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - signal fft_out_re_arr_pipe : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - signal fft_out_im_arr_pipe : t_fft_slv_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - signal fft_out_val_arr : std_logic_vector(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - - signal fft_out_sosi : t_dp_sosi; - signal fft_out_sosi_arr : t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0) := (others => c_dp_sosi_rst); - - signal pfb_out_sosi_arr : t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0) := (others => c_dp_sosi_rst); - - type reg_type is record - in_sosi_arr : t_dp_sosi_arr(g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 downto 0); - end record; - - signal r, rin : reg_type; - -begin - - -- The complete input sosi arry is registered. - comb : process(r, in_sosi_arr) - variable v : reg_type; - begin - v := r; - v.in_sosi_arr := in_sosi_arr; - rin <= v; - end process comb; - - regs : process(dp_clk) - begin - if rising_edge(dp_clk) then - r <= rin; - end if; - end process; - - --------------------------------------------------------------- - -- COMBINE MEMORY MAPPED INTERFACES - --------------------------------------------------------------- - -- Combine the internal array of mm interfaces for the subband - -- statistics to one array that is connected to the port of the - -- fft_wide_unit. - u_mem_mux_sst : entity common_lib.common_mem_mux - generic map ( - g_nof_mosi => g_wpfb.nof_wb_streams*g_wpfb.wb_factor, - g_mult_addr_w => ceil_log2(g_wpfb.stat_data_sz*c_nof_stats) - ) - port map ( - mosi => ram_st_sst_mosi, - miso => ram_st_sst_miso, - mosi_arr => ram_st_sst_mosi_arr, - miso_arr => ram_st_sst_miso_arr - ); - - gen_pfb : if g_use_bg = FALSE generate - --------------------------------------------------------------- - -- REWIRE THE DATA FOR WIDEBAND POLY PHASE FILTER - --------------------------------------------------------------- - - -- Wire in_sosi_arr --> fil_in_arr - wire_fil_in_wideband: for P in 0 to g_wpfb.wb_factor-1 generate - wire_fil_in_streams: for S in 0 to g_wpfb.nof_wb_streams-1 generate - fil_in_arr(P*g_wpfb.nof_wb_streams*c_nof_complex+S*c_nof_complex) <= RESIZE_SVEC_32(r.in_sosi_arr(S*g_wpfb.wb_factor+P).re(g_wpfb.fil_in_dat_w-1 downto 0)); - fil_in_arr(P*g_wpfb.nof_wb_streams*c_nof_complex+S*c_nof_complex+1) <= RESIZE_SVEC_32(r.in_sosi_arr(S*g_wpfb.wb_factor+P).im(g_wpfb.fil_in_dat_w-1 downto 0)); - end generate; - end generate; - fil_in_val <= r.in_sosi_arr(0).valid; - - -- Wire fil_out_arr --> fil_sosi_arr - wire_fil_sosi_streams: for S in 0 to g_wpfb.nof_wb_streams-1 generate - wire_fil_sosi_wideband: for P in 0 to g_wpfb.wb_factor-1 generate - fil_sosi_arr(S*g_wpfb.wb_factor+P).valid <= fil_out_val; - fil_sosi_arr(S*g_wpfb.wb_factor+P).re <= RESIZE_DP_DSP_DATA(fil_out_arr(P*g_wpfb.nof_wb_streams*c_nof_complex+S*c_nof_complex )); - fil_sosi_arr(S*g_wpfb.wb_factor+P).im <= RESIZE_DP_DSP_DATA(fil_out_arr(P*g_wpfb.nof_wb_streams*c_nof_complex+S*c_nof_complex+1)); - end generate; - end generate; - - -- Wire fil_out_arr --> fft_in_re_arr, fft_in_im_arr - wire_fft_in_streams: for S in 0 to g_wpfb.nof_wb_streams-1 generate - wire_fft_in_wideband: for P in 0 to g_wpfb.wb_factor-1 generate - fft_in_re_arr(S*g_wpfb.wb_factor + P) <= fil_out_arr(P*g_wpfb.nof_wb_streams*c_nof_complex+S*c_nof_complex); - fft_in_im_arr(S*g_wpfb.wb_factor + P) <= fil_out_arr(P*g_wpfb.nof_wb_streams*c_nof_complex+S*c_nof_complex+1); - end generate; - end generate; - - --------------------------------------------------------------- - -- THE POLY PHASE FILTER - --------------------------------------------------------------- - gen_prefilter : IF g_use_prefilter = TRUE generate - u_filter : entity filter_lib.fil_ppf_wide - generic map ( - g_big_endian_wb_in => g_big_endian_wb_in, - g_big_endian_wb_out => false, -- reverse wideband order from big-endian [3:0] = [t0,t1,t2,t3] in fil_ppf_wide to little-endian [3:0] = [t3,t2,t1,t0] in fft_r2_wide - g_fil_ppf => c_fil_ppf, - g_fil_ppf_pipeline => g_wpfb.fil_pipeline, - g_coefs_file_prefix => g_coefs_file_prefix - ) - port map ( - dp_clk => dp_clk, - dp_rst => dp_rst, - mm_clk => mm_clk, - mm_rst => mm_rst, - ram_coefs_mosi => ram_fil_coefs_mosi, - ram_coefs_miso => ram_fil_coefs_miso, - in_dat_arr => fil_in_arr, - in_val => fil_in_val, - out_dat_arr => fil_out_arr, - out_val => fil_out_val - ); - end generate; - - -- Bypass filter - no_prefilter : if g_use_prefilter = FALSE generate - fil_out_arr <= fil_in_arr; - fil_out_val <= fil_in_val; - end generate; - - fft_in_val <= fil_out_val; - - --------------------------------------------------------------- - -- THE WIDEBAND FFT - --------------------------------------------------------------- - gen_wideband_fft: if g_wpfb.wb_factor > 1 generate - gen_fft_r2_wide_streams: for S in 0 to g_wpfb.nof_wb_streams-1 generate - u_fft_r2_wide : entity fft_lib.fft_r2_wide - generic map( - g_fft => c_fft, -- generics for the WFFT - g_pft_pipeline => g_wpfb.pft_pipeline, - g_fft_pipeline => g_wpfb.fft_pipeline - ) - port map( - clk => dp_clk, - rst => dp_rst, - in_re_arr => fft_in_re_arr((S+1)*g_wpfb.wb_factor-1 downto S*g_wpfb.wb_factor), - in_im_arr => fft_in_im_arr((S+1)*g_wpfb.wb_factor-1 downto S*g_wpfb.wb_factor), - in_val => fft_in_val, - out_re_arr => fft_out_re_arr((S+1)*g_wpfb.wb_factor-1 downto S*g_wpfb.wb_factor), - out_im_arr => fft_out_im_arr((S+1)*g_wpfb.wb_factor-1 downto S*g_wpfb.wb_factor), - out_val => fft_out_val_arr(S) - ); - end generate; - end generate; - - --------------------------------------------------------------- - -- THE PIPELINED FFT - --------------------------------------------------------------- - gen_pipeline_fft: if g_wpfb.wb_factor = 1 generate - gen_fft_r2_pipe_streams: for S in 0 to g_wpfb.nof_wb_streams-1 generate - u_fft_r2_pipe : entity fft_lib.fft_r2_pipe - generic map( - g_fft => c_fft, - g_dont_flip_channels => g_dont_flip_channels, - g_pipeline => g_wpfb.fft_pipeline - ) - port map( - clk => dp_clk, - rst => dp_rst, - in_re => fft_in_re_arr(S)(c_fft.in_dat_w-1 downto 0), - in_im => fft_in_im_arr(S)(c_fft.in_dat_w-1 downto 0), - in_val => fft_in_val, - out_re => fft_out_re_arr_i(S)(c_fft.out_dat_w-1 downto 0), - out_im => fft_out_im_arr_i(S)(c_fft.out_dat_w-1 downto 0), - out_val => fft_out_val_arr(S) - ); - - fft_out_re_arr(S) <= RESIZE_SVEC_32(fft_out_re_arr_i(S)(c_fft.out_dat_w-1 downto 0)); - fft_out_im_arr(S) <= RESIZE_SVEC_32(fft_out_im_arr_i(S)(c_fft.out_dat_w-1 downto 0)); - end generate; - end generate; - - --------------------------------------------------------------- - -- FFT CONTROL UNIT - --------------------------------------------------------------- - - -- Capture input BSN at input sync and pass the captured input BSN it on to PFB output sync. - -- The FFT output valid defines PFB output sync, sop, eop. - - fft_out_sosi.sync <= r.in_sosi_arr(0).sync; - fft_out_sosi.bsn <= r.in_sosi_arr(0).bsn; - fft_out_sosi.valid <= fft_out_val_arr(0); - - wire_fft_out_sosi_arr : for I in 0 to g_wpfb.nof_wb_streams*g_wpfb.wb_factor-1 generate - fft_out_sosi_arr(I).re <= RESIZE_DP_DSP_DATA(fft_out_re_arr(I)); - fft_out_sosi_arr(I).im <= RESIZE_DP_DSP_DATA(fft_out_im_arr(I)); - fft_out_sosi_arr(I).valid <= fft_out_val_arr(I); - end generate; - - u_dp_block_gen_valid_arr : ENTITY dp_lib.dp_block_gen_valid_arr - GENERIC MAP ( - g_nof_streams => g_wpfb.nof_wb_streams*g_wpfb.wb_factor, - g_nof_data_per_block => c_nof_valid_per_block, - g_nof_blk_per_sync => g_wpfb.nof_blk_per_sync, - g_check_input_sync => false, - g_nof_pages_bsn => 1, - g_restore_global_bsn => true - ) - PORT MAP ( - rst => dp_rst, - clk => dp_clk, - -- Streaming sink - snk_in => fft_out_sosi, - snk_in_arr => fft_out_sosi_arr, - -- Streaming source - src_out_arr => pfb_out_sosi_arr, - -- Control - enable => '1' - ); - end generate; - - ---------------------------------------------------------------------------- - -- Source: block generator - ---------------------------------------------------------------------------- - gen_bg : if g_use_bg = TRUE generate - u_bg : entity diag_lib.mms_diag_block_gen - generic map( - g_nof_streams => g_wpfb.nof_wb_streams*g_wpfb.wb_factor, - g_buf_dat_w => c_nof_complex*g_wpfb.fft_out_dat_w, - g_buf_addr_w => c_bg_buf_adr_w, -- Waveform buffer size 2**g_buf_addr_w nof samples - g_file_index_arr => c_bg_data_file_index_arr, - g_file_name_prefix => c_bg_data_file_prefix - ) - port map( - -- System - mm_rst => mm_rst, - mm_clk => mm_clk, - dp_rst => dp_rst, - dp_clk => dp_clk, - en_sync => '0', - -- MM interface - reg_bg_ctrl_mosi => reg_bg_ctrl_mosi, - reg_bg_ctrl_miso => reg_bg_ctrl_miso, - ram_bg_data_mosi => ram_bg_data_mosi, - ram_bg_data_miso => ram_bg_data_miso, - -- ST interface - out_sosi_arr => pfb_out_sosi_arr - ); - end generate; - - --------------------------------------------------------------- - -- SUBBAND STATISTICS - --------------------------------------------------------------- - -- For all "wb_factor"x"nof_wb_streams" output streams of the - -- wideband FFT a subband statistics unit is placed if the - -- g_stats_ena is TRUE. - -- Since the subband statistics module uses embedded DSP blocks - -- for multiplication, the incoming data cannot be wider - -- than 18 bit. - gen_stats : if g_stats_ena = TRUE generate - gen_stats_streams: for S in 0 to g_wpfb.nof_wb_streams-1 generate - gen_stats_wideband: for P in 0 to g_wpfb.wb_factor-1 generate - u_subband_stats : entity st_lib.st_sst - generic map( - g_nof_stat => c_nof_stats, - g_in_data_w => g_wpfb.fft_out_dat_w, - g_stat_data_w => g_wpfb.stat_data_w, - g_stat_data_sz => g_wpfb.stat_data_sz - ) - port map ( - mm_rst => mm_rst, - mm_clk => mm_clk, - dp_rst => dp_rst, - dp_clk => dp_clk, - in_complex => pfb_out_sosi_arr(S*g_wpfb.wb_factor+P), - ram_st_sst_mosi => ram_st_sst_mosi_arr(S*g_wpfb.wb_factor+P), - ram_st_sst_miso => ram_st_sst_miso_arr(S*g_wpfb.wb_factor+P) - ); - end generate; - end generate; - end generate; - - -- Connect to the outside world - out_sosi_arr <= pfb_out_sosi_arr; - -end str; - - - diff --git a/applications/lofar1/pfs/hdllib.cfg b/applications/lofar1/pfs/hdllib.cfg index 106f0dc0d5e45e9eb0e8462270d04e540f94b86c..1b731b60a2f4c964f65abf55b6f26644635bcf42 100644 --- a/applications/lofar1/pfs/hdllib.cfg +++ b/applications/lofar1/pfs/hdllib.cfg @@ -6,17 +6,10 @@ hdl_lib_technology = synth_files = src/vhdl/pfs_ctrl.vhd - src/vhdl/pfs_ctrl(rtl).vhd src/vhdl/pfs_tapsbuf.vhd src/vhdl/pfs_coefsbuf.vhd src/vhdl/pfs_filter.vhd - src/vhdl/pfs_tapsbuf(rtl).vhd - src/vhdl/pfs_coefsbuf(str).vhd - src/vhdl/pfs_filter(rtl).vhd src/vhdl/pfs.vhd - src/vhdl/pfs(str).vhd - src/vhdl/pfs_top.vhd - src/vhdl/pfs_top(str).vhd test_bench_files = tb/vhdl/tb_pfs.vhd diff --git a/applications/lofar1/pfs/src/vhdl/pfs.vhd b/applications/lofar1/pfs/src/vhdl/pfs.vhd index 67afceb7ab28e5d64326658cf4e7a0855a7ee186..f0efbc4dacba22bfb2395b670b4f99d42e222a63 100644 --- a/applications/lofar1/pfs/src/vhdl/pfs.vhd +++ b/applications/lofar1/pfs/src/vhdl/pfs.vhd @@ -1,6 +1,31 @@ -LIBRARY IEEE; -USE IEEE.STD_LOGIC_1164.ALL; +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. +LIBRARY IEEE, common_lib; +USE IEEE.std_logic_1164.ALL; +USE common_lib.common_pkg.ALL; ENTITY pfs IS GENERIC ( @@ -25,3 +50,127 @@ ENTITY pfs IS ); END pfs; + +ARCHITECTURE str OF pfs IS + + CONSTANT c_nof_bands_w : NATURAL := ceil_log2(g_nof_bands); + CONSTANT c_nof_fir_taps : NATURAL := g_nof_taps / g_nof_bands; + CONSTANT c_nof_fir_taps_w : NATURAL := ceil_log2(c_nof_fir_taps); + + SIGNAL taps_rdaddr : STD_LOGIC_VECTOR(c_nof_bands_w-1 DOWNTO 0); + SIGNAL taps_wraddr : STD_LOGIC_VECTOR(c_nof_bands_w-1 DOWNTO 0); + SIGNAL taps_wren : STD_LOGIC; + SIGNAL taps_in_x : STD_LOGIC_VECTOR(g_in_dat_w*c_nof_fir_taps-1 DOWNTO 0); + SIGNAL taps_in_y : STD_LOGIC_VECTOR(g_in_dat_w*c_nof_fir_taps-1 DOWNTO 0); + SIGNAL taps_out_x : STD_LOGIC_VECTOR(g_in_dat_w*c_nof_fir_taps-1 DOWNTO 0); + SIGNAL taps_out_y : STD_LOGIC_VECTOR(g_in_dat_w*c_nof_fir_taps-1 DOWNTO 0); + SIGNAL coefs : STD_LOGIC_VECTOR(g_coef_dat_w*c_nof_fir_taps-1 DOWNTO 0); + +BEGIN + + ctrl : ENTITY work.pfs_ctrl + GENERIC MAP ( + g_nof_bands_w => c_nof_bands_w, + g_nof_taps => c_nof_fir_taps, + g_nof_taps_w => c_nof_fir_taps_w, + g_taps_w => g_in_dat_w + ) + PORT MAP ( + clk => clk, + rst => rst, + restart => restart, + in_x => in_dat_x, + in_y => in_dat_y, + in_val => in_val, + in_sync => in_sync, + taps_rdaddr => taps_rdaddr, + taps_wraddr => taps_wraddr, + taps_wren => taps_wren, + taps_in_x => taps_in_x, + taps_in_y => taps_in_y, + taps_out_x => taps_out_x, + taps_out_y => taps_out_y, + out_val => out_val, + out_sync => out_sync + ); + + + firx : ENTITY work.pfs_filter + GENERIC MAP ( + g_coef_w => g_coef_dat_w, + g_out_w => g_out_dat_w, + g_taps_w => g_in_dat_w, + g_nof_taps => c_nof_fir_taps + ) + PORT MAP( + clk => clk, + taps => taps_out_x, + coefs => coefs, + result => out_dat_x + ); + + + firy : ENTITY work.pfs_filter + GENERIC MAP ( + g_coef_w => g_coef_dat_w, + g_out_w => g_out_dat_w, + g_taps_w => g_in_dat_w, + g_nof_taps => c_nof_fir_taps + ) + PORT MAP ( + clk => clk, + taps => taps_out_y, + coefs => coefs, + result => out_dat_y + ); + + + tapsbufx : ENTITY work.pfs_tapsbuf + GENERIC MAP ( + g_data_w => g_in_dat_w * c_nof_fir_taps, + g_nof_words => g_nof_bands, + g_addr_w => c_nof_bands_w + ) + PORT MAP ( + wrdata => taps_out_x, + wren => taps_wren, + wraddr => taps_wraddr, + rdaddr => taps_rdaddr, + rddata => taps_in_x, + clk => clk, + rst => rst + ); + + + tapsbufy : ENTITY work.pfs_tapsbuf + GENERIC MAP ( + g_data_w => g_in_dat_w * c_nof_fir_taps, + g_nof_words => g_nof_bands, + g_addr_w => c_nof_bands_w + ) + PORT MAP ( + wrdata => taps_out_y, + wren => taps_wren, + wraddr => taps_wraddr, + rdaddr => taps_rdaddr, + rddata => taps_in_y, + clk => clk, + rst => rst + ); + + + coefsbuf : ENTITY work.pfs_coefsbuf + GENERIC MAP ( + g_data_w => g_coef_dat_w * c_nof_fir_taps, + g_nof_coefs => g_nof_bands, + g_addr_w => c_nof_bands_w + ) + PORT MAP ( + addr => taps_rdaddr, + data => coefs, + clk => clk, + rst => rst + ); + +END str; + diff --git a/applications/lofar1/pfs/src/vhdl/pfs_coefsbuf.vhd b/applications/lofar1/pfs/src/vhdl/pfs_coefsbuf.vhd index 70d2d539561d54ae1ce09373a0b4a2665a6f274b..913cc1d5c07f6371e46d53a36910022267c365af 100644 --- a/applications/lofar1/pfs/src/vhdl/pfs_coefsbuf.vhd +++ b/applications/lofar1/pfs/src/vhdl/pfs_coefsbuf.vhd @@ -1,6 +1,33 @@ -LIBRARY IEEE; +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. + +LIBRARY IEEE, common_lib; USE IEEE.std_logic_1164.ALL; USE IEEE.numeric_std.ALL; +USE common_lib.common_mem_pkg.ALL; + ENTITY pfs_coefsbuf IS GENERIC ( @@ -17,3 +44,27 @@ ENTITY pfs_coefsbuf IS END pfs_coefsbuf; +ARCHITECTURE str OF pfs_coefsbuf IS + + CONSTANT c_coefs_rom : t_c_mem := (latency => 2, + adr_w => g_addr_w, + dat_w => g_data_w, + nof_dat => g_nof_coefs, -- <= 2**g_addr_w + init_sl => '0'); + +BEGIN + + rom : ENTITY common_lib.common_rom + GENERIC MAP ( + g_ram => c_coefs_rom, + g_init_file => "data/pfs_coefsbuf_1024.hex" -- Quartus .hex extension, replaced by .bin in common_rom works for XST + --g_init_file => "data/pfs_coefsbuf_1024.bin" -- Synplify fails on file extension change to .bin in common_rom and requires extra ../ + ) + PORT MAP ( + rst => rst, + clk => clk, + rd_adr => addr, + rd_dat => data + ); + +END str; diff --git a/applications/lofar1/pfs/src/vhdl/pfs_ctrl.vhd b/applications/lofar1/pfs/src/vhdl/pfs_ctrl.vhd index c047c852a42657b366c98efe019075a7b6107183..1ea585a951b1facbb03557c0eefcf172dd715cfb 100644 --- a/applications/lofar1/pfs/src/vhdl/pfs_ctrl.vhd +++ b/applications/lofar1/pfs/src/vhdl/pfs_ctrl.vhd @@ -1,5 +1,31 @@ -LIBRARY ieee; -USE ieee.std_logic_1164.ALL; +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. + +LIBRARY IEEE; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; ENTITY pfs_ctrl IS @@ -29,3 +55,98 @@ ENTITY pfs_ctrl IS ); END pfs_ctrl; + +ARCHITECTURE rtl OF pfs_ctrl IS + + -- The number of cycles that should be waited until the result that comes out + -- of the MAC block is the valid result. The ctrl block will generate a valid + -- pulse. + CONSTANT c_mem_delay : INTEGER := 2; + CONSTANT c_fir_delay : INTEGER := 8; + + TYPE delay_reg IS ARRAY (0 TO c_mem_delay) OF STD_LOGIC_VECTOR(g_taps_w-1 DOWNTO 0); + + SIGNAL in_val_reg : STD_LOGIC; + SIGNAL in_x_reg : delay_reg; + SIGNAL in_y_reg : delay_reg; + SIGNAL i_taps_rdaddr : STD_LOGIC_VECTOR(taps_rdaddr'RANGE); + SIGNAL nxt_taps_rdaddr : STD_LOGIC_VECTOR(taps_rdaddr'RANGE); + SIGNAL rdval : STD_LOGIC_VECTOR(c_fir_delay-1 DOWNTO 0); + SIGNAL sync_reg : STD_LOGIC_VECTOR(c_fir_delay DOWNTO 0); + SIGNAL nxt_rdval : STD_LOGIC_VECTOR(rdval'RANGE); + SIGNAL i_taps_wraddr : STD_LOGIC_VECTOR(taps_wraddr'RANGE); + SIGNAL nxt_taps_wraddr : STD_LOGIC_VECTOR(taps_wraddr'RANGE); + +BEGIN + + -- Output signals. + taps_rdaddr <= i_taps_rdaddr; + taps_wraddr <= i_taps_wraddr; + out_val <= rdval(c_fir_delay-1); + out_sync <= sync_reg(c_fir_delay); + + registers_proc : PROCESS (clk, rst) + BEGIN + IF rst = '1' THEN + -- Input registers. + in_val_reg <= '0'; + in_x_reg <= (OTHERS => (OTHERS => '0')); + in_y_reg <= (OTHERS => (OTHERS => '0')); + -- Output registers. + -- Internal registers. + rdval <= (OTHERS => '0'); + sync_reg <= (OTHERS => '0'); + i_taps_rdaddr <= (OTHERS => '0'); + i_taps_wraddr <= (OTHERS => '0'); + ELSIF rising_edge(clk) THEN + -- Input registers. + in_val_reg <= in_val; + in_x_reg <= in_x & in_x_reg(0 TO in_x_reg'HIGH-1); + in_y_reg <= in_y & in_y_reg(0 TO in_y_reg'HIGH-1); + -- Output registers. + -- Internal registers. + rdval <= nxt_rdval; + sync_reg <= sync_reg(sync_reg'HIGH-1 DOWNTO 0) & in_sync; + i_taps_rdaddr <= nxt_taps_rdaddr; + i_taps_wraddr <= nxt_taps_wraddr; + END IF; + END PROCESS; + + + read_address_gen : PROCESS (restart, i_taps_rdaddr, in_val_reg, rdval) + BEGIN + nxt_taps_rdaddr <= STD_LOGIC_VECTOR(UNSIGNED(i_taps_rdaddr)+1); + IF restart = '1' THEN + nxt_taps_rdaddr <= (OTHERS => '0'); + ELSIF in_val_reg = '0' THEN + nxt_taps_rdaddr <= i_taps_rdaddr; + END IF; + + nxt_rdval <= rdval(rdval'HIGH-1 DOWNTO 0) & '0'; + IF in_val_reg = '1' THEN + nxt_rdval <= rdval(rdval'HIGH-1 DOWNTO 0) & '1'; + END IF; + END PROCESS; + + + write_control : PROCESS (restart, i_taps_wraddr, taps_in_x, taps_in_y, in_x_reg, rdval, + in_y_reg) + BEGIN + nxt_taps_wraddr <= STD_LOGIC_VECTOR(UNSIGNED(i_taps_wraddr)+1); + IF restart = '1' THEN + nxt_taps_wraddr <= (OTHERS => '0'); + ELSIF rdval(c_mem_delay-1) = '0' THEN + nxt_taps_wraddr <= i_taps_wraddr; + END IF; + + taps_out_x <= (OTHERS => '0'); + taps_out_y <= (OTHERS => '0'); + taps_wren <= '0'; + IF rdval(c_mem_delay-1) = '1' THEN + taps_out_x <= taps_in_x(taps_in_x'HIGH-g_taps_w DOWNTO 0) & in_x_reg(c_mem_delay); + taps_out_y <= taps_in_y(taps_in_y'HIGH-g_taps_w DOWNTO 0) & in_y_reg(c_mem_delay); + taps_wren <= '1'; + END IF; + END PROCESS; + +END rtl; diff --git a/applications/lofar1/pfs/src/vhdl/pfs_filter.vhd b/applications/lofar1/pfs/src/vhdl/pfs_filter.vhd index b6044a6682359855e4be68ddab3c91b48861a4aa..8378497351fc288f31c5b0685c7a6f138e0d011a 100644 --- a/applications/lofar1/pfs/src/vhdl/pfs_filter.vhd +++ b/applications/lofar1/pfs/src/vhdl/pfs_filter.vhd @@ -1,6 +1,32 @@ -LIBRARY IEEE; +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. + +LIBRARY IEEE, common_lib, common_mult_lib; USE IEEE.std_logic_1164.ALL; USE IEEE.numeric_std.ALL; +USE common_lib.common_pkg.ALL; ENTITY pfs_filter IS @@ -18,3 +44,64 @@ ENTITY pfs_filter IS ); END pfs_filter; + +ARCHITECTURE rtl OF pfs_filter IS + + type type_res is array (0 to 7) of std_logic_vector(g_coef_w+g_taps_w+1-1 DOWNTO 0); + + SIGNAL res : type_res; + SIGNAL res_0 : STD_LOGIC_VECTOR(g_coef_w+g_taps_w+2-1 DOWNTO 0); + SIGNAL res_1 : STD_LOGIC_VECTOR(g_coef_w+g_taps_w+2-1 DOWNTO 0); + SIGNAL res_2 : STD_LOGIC_VECTOR(g_coef_w+g_taps_w+2-1 DOWNTO 0); + SIGNAL res_3 : STD_LOGIC_VECTOR(g_coef_w+g_taps_w+2-1 DOWNTO 0); + SIGNAL add_a : STD_LOGIC_VECTOR(g_coef_w+g_taps_w+3-1 DOWNTO 0); + SIGNAL add_b : STD_LOGIC_VECTOR(g_coef_w+g_taps_w+3-1 DOWNTO 0); + SIGNAL add_c : STD_LOGIC_VECTOR(g_coef_w+g_taps_w+4-1 DOWNTO 0); + +BEGIN + + registers : PROCESS (clk) + BEGIN + IF rising_edge(clk) THEN + result <= add_c(add_c'HIGH DOWNTO add_c'LENGTH - result'LENGTH); + add_a <= STD_LOGIC_VECTOR(RESIZE(SIGNED(res_0),add_a'LENGTH) + SIGNED(res_1)); + add_b <= STD_LOGIC_VECTOR(RESIZE(SIGNED(res_2),add_b'LENGTH) + SIGNED(res_3)); + END IF; + END PROCESS; + + + add_c <= STD_LOGIC_VECTOR(SHIFT_LEFT((RESIZE(SIGNED(add_a),add_c'LENGTH) + SIGNED(add_b)),4)); +-- nxt_result <= STD_LOGIC_VECTOR(RESIZE(SIGNED(add_c), + + gen : FOR i IN 0 TO 7 GENERATE + --MULT_ADD : ENTITY common_lib.common_mult_add(rtl) + --MULT_ADD : ENTITY common_lib.common_mult_add(virtex) + MULT_ADD : ENTITY common_mult_lib.common_mult_add -- rtl + GENERIC MAP ( + g_in_a_w => g_taps_w, + g_in_b_w => g_coef_w, + g_out_dat_w => g_coef_w+g_taps_w+1, + g_add_sub => "ADD", + g_pipeline => 3 + ) + PORT MAP ( + clk => clk, + in_a0 => taps (g_taps_w*(2*i+1)-1 DOWNTO g_taps_w*2*i), + in_b0 => coefs(g_coef_w*(2*i+1)-1 DOWNTO g_coef_w*2*i), + in_a1 => taps (g_taps_w*(2*i+2)-1 DOWNTO g_taps_w*(2*i+1)), + in_b1 => coefs(g_coef_w*(2*i+2)-1 DOWNTO g_coef_w*(2*i+1)), + out_dat => res(i) + ); + END GENERATE; + + pipe : PROCESS (clk) + BEGIN + IF rising_edge(clk) THEN + res_0 <= STD_LOGIC_VECTOR(RESIZE(SIGNED(res(0)),res_0'LENGTH) + RESIZE(SIGNED(res(1)),res_0'LENGTH)); + res_1 <= STD_LOGIC_VECTOR(RESIZE(SIGNED(res(2)),res_0'LENGTH) + RESIZE(SIGNED(res(3)),res_0'LENGTH)); + res_2 <= STD_LOGIC_VECTOR(RESIZE(SIGNED(res(4)),res_0'LENGTH) + RESIZE(SIGNED(res(5)),res_0'LENGTH)); + res_3 <= STD_LOGIC_VECTOR(RESIZE(SIGNED(res(6)),res_0'LENGTH) + RESIZE(SIGNED(res(7)),res_0'LENGTH)); + END IF; + END PROCESS; + +END rtl; diff --git a/applications/lofar1/pfs/src/vhdl/pfs_tapsbuf.vhd b/applications/lofar1/pfs/src/vhdl/pfs_tapsbuf.vhd index f2af2d1a056c5427f78c33a7b09d995c57c2e3c2..0ddf24038f6a1c34a918079316f4a97e8e3084e3 100644 --- a/applications/lofar1/pfs/src/vhdl/pfs_tapsbuf.vhd +++ b/applications/lofar1/pfs/src/vhdl/pfs_tapsbuf.vhd @@ -1,6 +1,33 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. + LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; USE IEEE.numeric_std.ALL; +USE IEEE.std_logic_unsigned.ALL; + ENTITY pfs_tapsbuf IS GENERIC ( @@ -20,3 +47,26 @@ ENTITY pfs_tapsbuf IS END pfs_tapsbuf; +ARCHITECTURE rtl OF pfs_tapsbuf IS + + type RamType is array(0 to 2**g_addr_w) of std_logic_vector(g_data_w-1 downto 0); + + -- pfs_tapsbuf_1024.hex is empty (all zeros) + signal RAM : RamType := (OTHERS => (OTHERS => '0')); + + signal read_addrb : std_logic_vector(g_addr_w-1 downto 0); + +BEGIN + + process (clk) + begin + if rising_edge(clk) then + if (wren = '1') then + RAM (conv_integer(wraddr)) <= wrdata; + end if; + read_addrb <= rdaddr; + rddata <= RAM(conv_integer(read_addrb)); + end if; + end process; + +END rtl; diff --git a/applications/lofar1/pft2/hdllib.cfg b/applications/lofar1/pft2/hdllib.cfg index 73ad9896125c41cc3b3066ff43671c1be870d409..b26cec4dbdd7005fdf6591d415d3ab0dc9ced680 100644 --- a/applications/lofar1/pft2/hdllib.cfg +++ b/applications/lofar1/pft2/hdllib.cfg @@ -8,28 +8,15 @@ synth_files = src/vhdl/pft_lfsr.vhd src/vhdl/pft_switch.vhd src/vhdl/pft_unswitch.vhd - src/vhdl/pft_switch(rtl).vhd - src/vhdl/pft_unswitch(rtl).vhd - src/vhdl/pft_lfsr(rtl).vhd - src/vhdl/pft(pkg).vhd + src/vhdl/pft_pkg.vhd src/vhdl/pft_bf.vhd - src/vhdl/pft_bf(rtl).vhd src/vhdl/pft_bf_fw.vhd - src/vhdl/pft_bf_fw(rtl).vhd src/vhdl/pft_tmult.vhd - src/vhdl/pft_tmult(rtl).vhd src/vhdl/pft_stage.vhd - src/vhdl/pft_stage(str).vhd src/vhdl/pft_buffer.vhd - src/vhdl/pft_buffer(rtl).vhd src/vhdl/pft_reverse.vhd - src/vhdl/pft_reverse(rtl).vhd src/vhdl/pft_separate.vhd - src/vhdl/pft_separate(rtl).vhd src/vhdl/pft.vhd - src/vhdl/pft(str).vhd - src/vhdl/pft_top.vhd - src/vhdl/pft_top(str).vhd test_bench_files = tb/vhdl/tb_pft2.vhd diff --git a/applications/lofar1/pft2/src/vhdl/pft.vhd b/applications/lofar1/pft2/src/vhdl/pft.vhd index f0ff2003d3520867b19fe59fdda89b71fb854672..0f85ddfef1f7acc3e854c6585539e5a73a730f1d 100644 --- a/applications/lofar1/pft2/src/vhdl/pft.vhd +++ b/applications/lofar1/pft2/src/vhdl/pft.vhd @@ -1,3 +1,28 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. + LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; USE IEEE.numeric_std.ALL; @@ -5,6 +30,7 @@ USE IEEE.numeric_std.ALL; LIBRARY pft2_lib; USE pft2_lib.pft_pkg.ALL; + ENTITY pft IS GENERIC ( g_fft_size_w : NATURAL := 10; @@ -27,3 +53,337 @@ ENTITY pft IS ); END pft; + +ARCHITECTURE str OF pft IS + + FUNCTION pft_dat_w ( output_w : IN NATURAL; mode : IN PFT_MODE_TYPE) RETURN NATURAL IS + VARIABLE dat_w : NATURAL; + BEGIN + IF mode = PFT_MODE_REAL2 THEN + dat_w := output_w; + ELSE + dat_w := output_w; + END IF; + RETURN dat_w; + END; + + CONSTANT c_nof_stages : NATURAL := g_fft_size_w/2; + CONSTANT c_stage_dat_w : NATURAL := c_pft_stage_dat_w; + CONSTANT c_pft_dat_w : NATURAL := pft_dat_w(g_out_dat_w, g_mode); + + TYPE stage_rec IS RECORD + re : STD_LOGIC_VECTOR(c_stage_dat_w-1 DOWNTO 0); + im : STD_LOGIC_VECTOR(c_stage_dat_w-1 DOWNTO 0); + val : STD_LOGIC; + sync : STD_LOGIC; + END RECORD; + + TYPE stage_arr IS ARRAY(c_nof_stages-2 DOWNTO 0) OF stage_rec; + + SIGNAL switch_re : STD_LOGIC_VECTOR(in_re'RANGE); + SIGNAL switch_im : STD_LOGIC_VECTOR(in_im'RANGE); + SIGNAL switch_val : STD_LOGIC; + SIGNAL switch_sync : STD_LOGIC; + + SIGNAL stage : stage_arr; + + SIGNAL pft_re : STD_LOGIC_VECTOR(c_pft_dat_w-1 DOWNTO 0); + SIGNAL pft_im : STD_LOGIC_VECTOR(c_pft_dat_w-1 DOWNTO 0); + SIGNAL pft_val : STD_LOGIC; + SIGNAL pft_sync : STD_LOGIC; + + SIGNAL buf_re : STD_LOGIC_VECTOR(c_pft_dat_w-1 DOWNTO 0); + SIGNAL buf_im : STD_LOGIC_VECTOR(c_pft_dat_w-1 DOWNTO 0); + SIGNAL buf_en : STD_LOGIC; + SIGNAL buf_val : STD_LOGIC; + SIGNAL buf_adr : STD_LOGIC_VECTOR(g_fft_size_w-1 DOWNTO 0); + SIGNAL buf_sync : STD_LOGIC; + SIGNAL buf_rdy : STD_LOGIC; + + SIGNAL sep_re : STD_LOGIC_VECTOR(out_re'RANGE); + SIGNAL sep_im : STD_LOGIC_VECTOR(out_im'RANGE); + SIGNAL sep_val : STD_LOGIC; + SIGNAL sep_sync : STD_LOGIC; + + SIGNAL unswitch_re : STD_LOGIC_VECTOR(out_re'RANGE); + SIGNAL unswitch_im : STD_LOGIC_VECTOR(out_im'RANGE); + SIGNAL unswitch_val : STD_LOGIC; + SIGNAL unswitch_sync : STD_LOGIC; + + + -- synthesis translate_off + SIGNAL bin : STD_LOGIC_VECTOR(g_fft_size_w-1 DOWNTO 0):= (OTHERS => '0'); + SIGNAL band : STD_LOGIC_VECTOR(g_fft_size_w-2 DOWNTO 0); + SIGNAL fft_x_re : STD_LOGIC_VECTOR(out_re'RANGE); + SIGNAL fft_x_im : STD_LOGIC_VECTOR(out_im'RANGE); + SIGNAL fft_y_re : STD_LOGIC_VECTOR(out_re'RANGE); + SIGNAL fft_y_im : STD_LOGIC_VECTOR(out_im'RANGE); + SIGNAL power : STD_LOGIC_VECTOR(2*g_out_dat_w-1 DOWNTO 0); + SIGNAL power_x : STD_LOGIC_VECTOR(2*g_out_dat_w-1 DOWNTO 0); + SIGNAL power_y : STD_LOGIC_VECTOR(2*g_out_dat_w-1 DOWNTO 0); + -- synthesis translate_on + +BEGIN + + -- The pipelined fft is composed of a number of consecutive stages. + -- The output of each stage is used as input for the next stage. + -- NB. The first stage has index c_nof_stages-1, the last stage has index 0. + + + switch: ENTITY pft2_lib.pft_switch + GENERIC MAP ( + g_dat_w => g_in_dat_w, + g_fft_sz_w => g_fft_size_w + ) + PORT MAP ( + rst => rst, + clk => clk, + in_val => in_val, + in_sync => in_sync, + in_re => in_re, + in_im => in_im, + switch_en => switch_en, + out_re => switch_re, + out_im => switch_im, + out_val => switch_val, + out_sync => switch_sync + ); + + first_gen : IF (c_nof_stages>1) GENERATE + first_stage : ENTITY pft2_lib.pft_stage + GENERIC MAP ( + g_index => c_nof_stages-1, + g_in_dat_w => g_in_dat_w, + g_out_dat_w => c_stage_dat_w + ) + PORT MAP ( + in_re => switch_re, + in_im => switch_im, + in_val => switch_val, + in_sync => switch_sync, + out_re => stage(c_nof_stages-2).re, + out_im => stage(c_nof_stages-2).im, + out_val => stage(c_nof_stages-2).val, + out_sync => stage(c_nof_stages-2).sync, + clk => clk, + rst => rst + ); + END GENERATE; + + + middle_gen : FOR i IN c_nof_stages-2 DOWNTO 1 GENERATE + middle_stage : ENTITY pft2_lib.pft_stage + GENERIC MAP ( + g_index => i, + g_in_dat_w => c_stage_dat_w, + g_out_dat_w => c_stage_dat_w + ) + PORT MAP ( + in_re => stage(i).re, + in_im => stage(i).im, + in_val => stage(i).val, + in_sync => stage(i).sync, + out_re => stage(i-1).re, + out_im => stage(i-1).im, + out_val => stage(i-1).val, + out_sync => stage(i-1).sync, + clk => clk, + rst => rst + ); + END GENERATE; + + last_gen : IF c_nof_stages>1 GENERATE + last_stage : ENTITY pft2_lib.pft_stage + GENERIC MAP ( + g_index => 0, + g_in_dat_w => c_stage_dat_w, + g_out_dat_w => c_pft_dat_w + ) + PORT MAP ( + in_re => stage(0).re, + in_im => stage(0).im, + in_val => stage(0).val, + in_sync => stage(0).sync, + out_re => pft_re, + out_im => pft_im, + out_val => pft_val, + out_sync => pft_sync, + clk => clk, + rst => rst + ); + END GENERATE; + + only_gen : IF c_nof_stages=1 GENERATE + only_stage : ENTITY pft2_lib.pft_stage + GENERIC MAP ( + g_index => 0, + g_in_dat_w => g_in_dat_w, + g_out_dat_w => c_pft_dat_w + ) + PORT MAP ( + in_re => in_re, + in_im => in_im, + in_val => in_val, + in_sync => in_sync, + out_re => pft_re, + out_im => pft_im, + out_val => pft_val, + out_sync => pft_sync, + clk => clk, + rst => rst + ); + END GENERATE; + + -- In "BITREV" mode, fft output is in bit reversed order. + none_gen : IF g_mode = PFT_MODE_BITREV GENERATE + sep_re <= pft_re; + sep_im <= pft_im; + sep_val <= pft_val; + sep_sync <= pft_sync; + END GENERATE; + + buf_gen : IF g_mode /= PFT_MODE_BITREV GENERATE + + buf : ENTITY pft2_lib.pft_buffer + GENERIC MAP ( + g_fft_size_w => g_fft_size_w, + g_dat_w => c_pft_dat_w + ) + PORT MAP ( + wr_re => pft_re, + wr_im => pft_im, + wr_val => pft_val, + wr_sync => pft_sync, + rd_re => buf_re, + rd_im => buf_im, + rd_adr => buf_adr, + rd_en => buf_en, + rd_val => buf_val, + rd_sync => buf_sync, + rd_rdy => buf_rdy, + clk => clk, + rst => rst + ); + END GENERATE; + + + reverse_gen : IF g_mode = PFT_MODE_COMPLEX GENERATE + reverse : ENTITY pft2_lib.pft_reverse + GENERIC MAP ( + g_fft_sz => 2**g_fft_size_w, + g_fft_sz_w => g_fft_size_w, + g_data_w => c_pft_dat_w + ) + PORT MAP ( + rddata_re => buf_re, + rddata_im => buf_im, + rdaddr => buf_adr, + rden => buf_en, + rdval => buf_val, + rdsync => buf_sync, + page_rdy => buf_rdy, + out_dat_re => sep_re, + out_dat_im => sep_im, + out_val => sep_val, + out_sync => sep_sync, + clk => clk, + rst => rst + ); + + END GENERATE; + + + separate_gen : IF g_mode = PFT_MODE_REAL2 GENERATE + separate : ENTITY pft2_lib.pft_separate + GENERIC MAP ( + g_fft_sz => 2**g_fft_size_w, + g_fft_sz_w => g_fft_size_w, + g_rd_dat_w => c_pft_dat_w, + g_out_dat_w => g_out_dat_w + ) + PORT MAP ( + rddata_re => buf_re, + rddata_im => buf_im, + rdaddr => buf_adr, + rden => buf_en, + rdval => buf_val, + rdsync => buf_sync, + page_rdy => buf_rdy, + out_dat_re => sep_re, + out_dat_im => sep_im, + out_val => sep_val, + out_sync => sep_sync, + clk => clk, + rst => rst + ); + END GENERATE; + + unswitch: ENTITY pft2_lib.pft_unswitch + GENERIC MAP ( + g_dat_w => g_out_dat_w, + g_fft_sz_w => g_fft_size_w + ) + PORT MAP ( + rst => rst, + clk => clk, + in_val => sep_val, + in_sync => sep_sync, + in_re => sep_re, + in_im => sep_im, + switch_en => switch_en, + out_re => unswitch_re, + out_im => unswitch_im, + out_val => unswitch_val, + out_sync => unswitch_sync + ); + + + -- calculate the power. This is intended to be used in simulations only. + + -- synthesis translate_off + determine_bin : PROCESS (clk) + BEGIN + IF rising_edge(clk) THEN + IF unswitch_val= '1' THEN + bin <= STD_LOGIC_VECTOR(UNSIGNED(bin)+1); + END IF; + END IF; + END PROCESS; + + band <= bin(bin'HIGH DOWNTO 1); + + power <= STD_LOGIC_VECTOR( SIGNED(unswitch_re) * SIGNED(unswitch_re) + + SIGNED(unswitch_im) * SIGNED(unswitch_im) + ) WHEN unswitch_val='1' ELSE (OTHERS => '0'); + + -- Wave window: View fft_re, fft_im in analogue format + -- Wave window: View power in binary format to get a spectrum diagram + + -- power_x <= power WHEN bin(0) = '0' ELSE power_x; + -- power_y <= power WHEN bin(0) = '1' ELSE power_y; + + -- Use clk to avoid limit cycle pulses in power_x and power_y + demux_power : PROCESS(clk) + BEGIN + IF falling_edge(clk) THEN + IF unswitch_val= '1' THEN + IF bin(0) = '0' THEN + fft_x_re <= unswitch_re; + fft_x_im <= unswitch_im; + power_x <= power; + ELSE + fft_y_re <= unswitch_re; + fft_y_im <= unswitch_im; + power_y <= power; + END IF; + END IF; + END IF; + END PROCESS; + -- synthesis translate_on + + out_re <= unswitch_re; + out_im <= unswitch_im; + out_val <= unswitch_val; + out_sync <= unswitch_sync; + +END str; diff --git a/applications/lofar1/pft2/src/vhdl/pft_bf.vhd b/applications/lofar1/pft2/src/vhdl/pft_bf.vhd index 4396f98f1315015b788791f4411077c6504f92bc..0fb8742918d9c84b5f4d8a61f4a1a29f73d50ca7 100644 --- a/applications/lofar1/pft2/src/vhdl/pft_bf.vhd +++ b/applications/lofar1/pft2/src/vhdl/pft_bf.vhd @@ -1,5 +1,33 @@ -LIBRARY ieee; -USE IEEE.std_logic_1164.ALL; +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. + +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +LIBRARY common_lib; ENTITY pft_bf IS @@ -25,3 +53,360 @@ ENTITY pft_bf IS ); END pft_bf; + +ARCHITECTURE rtl OF pft_bf IS + + CONSTANT c_read_pipeline : NATURAL := 1; + CONSTANT c_add_pipeline : NATURAL := 2; + CONSTANT c_write_pipeline : NATURAL := 1; + CONSTANT c_pipeline : NATURAL := c_read_pipeline+c_add_pipeline+c_write_pipeline; + CONSTANT c_cnt_w : NATURAL := g_index+2; + CONSTANT c_regbank_size_w : NATURAL := g_index; + CONSTANT c_regbank_size : NATURAL := 2**c_regbank_size_w; + CONSTANT c_dat_w : NATURAL := g_in_dat_w+1; + + TYPE sig_rec IS RECORD + val : STD_LOGIC; + sync : STD_LOGIC; + s0 : STD_LOGIC; + s1 : STD_LOGIC; + wr_req : STD_LOGIC; + END RECORD; + + TYPE sig_array IS ARRAY (c_pipeline-1 DOWNTO 0) OF sig_rec; + + SUBTYPE fifo_type IS STD_LOGIC_VECTOR(2*c_dat_w-1 DOWNTO 0); + TYPE fifo_arr IS ARRAY(c_regbank_size-c_pipeline DOWNTO 0) OF fifo_type; + + SIGNAL fifo_dat : fifo_arr; + SIGNAL nxt_fifo_dat : fifo_arr; + + SIGNAL sig : sig_array; + SIGNAL nxt_sig : sig_array; + + SIGNAL init : STD_LOGIC; + SIGNAL nxt_init : STD_LOGIC; + + SIGNAL cnt : STD_LOGIC_VECTOR(c_cnt_w-1 DOWNTO 0); + SIGNAL nxt_cnt : STD_LOGIC_VECTOR(cnt'RANGE); + + SIGNAL s0 : STD_LOGIC; + SIGNAL s1 : STD_LOGIC; + SIGNAL sync : STD_LOGIC; + SIGNAl nxt_sync : STD_LOGIC; + + SIGNAL add_ar : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL add_ai : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL add_br : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL add_bi : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL add_cr : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL add_ci : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + + SIGNAL sub_ar : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL sub_ai : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL sub_br : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL sub_bi : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL sub_cr : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL sub_ci : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + + SIGNAL nxt_out_re : STD_LOGIC_VECTOR(out_re'RANGE); + SIGNAL nxt_out_im : STD_LOGIC_VECTOR(out_re'RANGE); + + SIGNAL reg_re : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL nxt_reg_re : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + + SIGNAL reg_im : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL nxt_reg_im : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + + SIGNAL rd_re : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL rd_im : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL rd_req : STD_LOGIC; + + SIGNAL nxt_wr_re : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL nxt_wr_im : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + + SIGNAL wr_req : STD_LOGIC; + + SIGNAL wr_dat : STD_LOGIC_VECTOR(2*c_dat_w -1 DOWNTO 0); + SIGNAL nxt_wr_dat : STD_LOGIC_VECTOR(2*c_dat_w -1 DOWNTO 0); + SIGNAL rd_dat : STD_LOGIC_VECTOR(2*c_dat_w -1 DOWNTO 0); + +BEGIN + + out_val <= sig(0).val; + out_sync <= sig(0).sync; + wr_req <= sig(0).wr_req; + + nxt_wr_dat <= nxt_wr_re & nxt_wr_im; + --wr_re <= wr_dat(wr_dat'HIGH DOWNTO wr_im'LENGTH); + --wr_im <= wr_dat(wr_im'RANGE); + + s0 <= cnt(cnt'HIGH-1); + s1 <= cnt(cnt'HIGH ) WHEN g_bf_name="bf2" ELSE '0'; + + registers : PROCESS (clk, rst) + BEGIN + IF rst = '1' THEN + init <= '0'; + cnt <= (OTHERS => '0'); + sig <= (OTHERS => (OTHERS => '0')); + sync <= '0'; + out_re <= (OTHERS => '0'); + out_im <= (OTHERS => '0'); + wr_dat <= (OTHERS => '0'); + reg_re <= (OTHERS => '0'); + reg_im <= (OTHERS => '0'); + ELSIF RISING_EDGE(clk) THEN + init <= nxt_init; + cnt <= nxt_cnt; + sig <= nxt_sig; + sync <= nxt_sync; + out_re <= nxt_out_re; + out_im <= nxt_out_im; + wr_dat <= nxt_wr_dat; + reg_re <= nxt_reg_re; + reg_im <= nxt_reg_im; + END IF; + END PROCESS; + + sync_proc : PROCESS(cnt, in_sync, sync) + BEGIN + nxt_sync <= sync; + nxt_sig(sig'HIGH).sync <= '0'; + IF in_sync = '1' OR UNSIGNED(cnt)=c_regbank_size-1 THEN + nxt_sync <= in_sync; + nxt_sig(sig'HIGH).sync <= sync; + END IF; + END PROCESS; + + cnt_proc : PROCESS (cnt, in_val, in_sync) + BEGIN + nxt_cnt <= cnt; + IF in_sync = '1' OR SIGNED(cnt)=-1 THEN + nxt_cnt <= (OTHERS => '0'); + ELSIF in_val = '1' THEN + nxt_cnt <= STD_LOGIC_VECTOR(UNSIGNED(cnt) + 1); + END IF; + END PROCESS; + + init_proc : PROCESS(cnt,init,in_val) + BEGIN + nxt_init <= init; + IF UNSIGNED(cnt)=c_regbank_size-1 AND in_val='1' THEN + nxt_init <= '1'; + END IF; + END PROCESS; + + rd_proc : PROCESS(rd_dat,sig) + BEGIN + rd_re <= rd_dat(rd_dat'HIGH DOWNTO rd_im'LENGTH); + rd_im <= rd_dat(rd_im'RANGE); + --synthesis translate off + IF sig(sig'HIGH).val='0' THEN + rd_re <= (OTHERS => '0'); + rd_im <= (OTHERS => '0'); + END IF; + --synthesis translate on + END PROCESS; + + rd_req <= in_val AND init; + + nxt_reg_re <= STD_LOGIC_VECTOR(RESIZE(SIGNED(in_re),c_dat_w)); + nxt_reg_im <= STD_LOGIC_VECTOR(RESIZE(SIGNED(in_im),c_dat_w)); + + nxt_sig(sig'HIGH).val <= rd_req; + nxt_sig(sig'HIGH).s0 <= s0; + nxt_sig(sig'HIGH).s1 <= s1; + nxt_sig(sig'HIGH).wr_req <= in_val; + + nxt_sig(c_pipeline-2 DOWNTO 0) <= sig(c_pipeline-1 DOWNTO 1); + + in_proc : PROCESS (sig, reg_re, reg_im, rd_re, rd_im) + BEGIN + add_ar <= rd_re; + add_ai <= rd_im; + sub_ar <= reg_re; + sub_ai <= reg_im; + add_br <= (OTHERS => '0'); + add_bi <= (OTHERS => '0'); + sub_br <= (OTHERS => '0'); + sub_bi <= (OTHERS => '0'); + IF sig(sig'HIGH).s0='1' THEN + sub_ar <= rd_re; + sub_ai <= rd_im; + add_br <= reg_re; + add_bi <= reg_im; + sub_br <= reg_re; + sub_bi <= reg_im; + IF sig(sig'HIGH).s1='1' THEN + add_br <= reg_im; + add_bi <= reg_re; + sub_br <= reg_im; + sub_bi <= reg_re; + END IF; + END IF; + END PROCESS; + + + out_proc : PROCESS (sig, add_cr,add_ci,sub_cr,sub_ci) + BEGIN + nxt_out_re <= STD_LOGIC_VECTOR(RESIZE(SIGNED(add_cr),g_out_dat_w)); + nxt_out_im <= STD_LOGIC_VECTOR(RESIZE(SIGNED(add_ci),g_out_dat_w)); + nxt_wr_re <= sub_cr; + nxt_wr_im <= sub_ci; + IF sig(1).s0 = '1' AND sig(1).s1 = '1' THEN + nxt_out_re <= STD_LOGIC_VECTOR(RESIZE(SIGNED(add_cr),g_out_dat_w)); + nxt_out_im <= STD_LOGIC_VECTOR(RESIZE(SIGNED(sub_ci),g_out_dat_w)); + nxt_wr_re <= sub_cr; + nxt_wr_im <= add_ci; + END IF; + END PROCESS; + + +-- Adds/ Subs ------------------------------------------------------------------ + +-- Intel Altera lmp_add_sub carry in: +-- ADD: out = a + b + cin => cin = '0' to have out = a + b +-- SUB: out = a - b + cin - 1 => cin = '1' to have out = a - b + + --cadd : ENTITY common_lib.common_caddsub + --GENERIC MAP ( + -- g_in_a_w => c_dat_w, + -- g_in_b_w => c_dat_w, + -- g_out_c_w => c_dat_w, + -- g_pipeline => c_add_pipeline, + -- g_add_sub => "ADD" + --) + --PORT MAP ( + -- in_ar => add_ar, + -- in_ai => add_ai, + -- in_br => add_br, + -- in_bi => add_bi, + -- in_cr => '0', + -- in_ci => '0', + -- out_cr => add_cr, + -- out_ci => add_ci, + -- clk => clk, + -- rst => rst + --); + + cadd : ENTITY common_lib.common_complex_add_sub + GENERIC MAP ( + g_direction => "ADD", + g_representation => "SIGNED", + g_pipeline_input => 0, -- 0 or 1 + g_pipeline_output => c_add_pipeline, -- >= 0 + g_in_dat_w => c_dat_w, + g_out_dat_w => c_dat_w -- only support g_out_dat_w=g_in_dat_w and g_out_dat_w=g_in_dat_w+1 + ) + PORT MAP ( + clk => clk, + in_ar => add_ar, + in_ai => add_ai, + in_br => add_br, + in_bi => add_bi, + out_re => add_cr, + out_im => add_ci + ); + +-- csub : ENTITY common_lib.common_caddsub +-- GENERIC MAP ( +-- g_in_a_w => c_dat_w, +-- g_in_b_w => c_dat_w, +-- g_out_c_w => c_dat_w, +-- g_pipeline => c_add_pipeline, +-- g_add_sub => "SUB" +-- ) +-- PORT MAP ( +-- in_ar => sub_ar, +-- in_ai => sub_ai, +-- in_br => sub_br, +-- in_bi => sub_bi, +-- in_cr => '1', +-- in_ci => '1', +-- out_cr => sub_cr, +-- out_ci => sub_ci, +-- clk => clk, +-- rst => rst +-- ); + + csub : ENTITY common_lib.common_complex_add_sub + GENERIC MAP ( + g_direction => "SUB", + g_representation => "SIGNED", + g_pipeline_input => 0, -- 0 or 1 + g_pipeline_output => c_add_pipeline, -- >= 0 + g_in_dat_w => c_dat_w, + g_out_dat_w => c_dat_w -- only support g_out_dat_w=g_in_dat_w and g_out_dat_w=g_in_dat_w+1 + ) + PORT MAP ( + clk => clk, + in_ar => sub_ar, + in_ai => sub_ai, + in_br => sub_br, + in_bi => sub_bi, + out_re => sub_cr, + out_im => sub_ci + ); + +-- regbank -------------------------------------------------------------------------- + fifo_gen: IF c_regbank_size>8 GENERATE + fifo : ENTITY common_lib.common_fifo_sc + GENERIC MAP ( + g_dat_w => wr_dat'LENGTH, + g_nof_words => c_regbank_size + ) + PORT MAP ( + wr_dat => wr_dat, + wr_req => wr_req, + rd_dat => rd_dat, + rd_req => rd_req, + clk => clk, + rst => rst + ); + END GENERATE fifo_gen; + + + fifo2_gen : IF c_regbank_size>c_pipeline AND c_regbank_size<=8 GENERATE + fifo2_reg : PROCESS (clk, rst) + BEGIN + IF rst = '1' THEN + fifo_dat <= (OTHERS => (OTHERS => '0')); + ELSIF RISING_EDGE(clk) THEN + fifo_dat <= nxt_fifo_dat; + END IF; + END PROCESS; + + fifo2_proc : PROCESS(fifo_dat,wr_req,wr_dat) + BEGIN + nxt_fifo_dat <= fifo_dat; + IF wr_req='1' THEN + nxt_fifo_dat <= wr_dat & fifo_dat(fifo_dat'HIGH DOWNTO 1); + END IF; + rd_dat <= fifo_dat(0); + END PROCESS; + END GENERATE; + + fifo3_gen : IF c_regbank_size=c_pipeline GENERATE + fifo3_reg : PROCESS (clk, rst) + BEGIN + IF rst = '1' THEN + fifo_dat <= (OTHERS => (OTHERS => '0')); + ELSIF RISING_EDGE(clk) THEN + fifo_dat <= nxt_fifo_dat; + END IF; + END PROCESS; + + fifo3_proc : PROCESS(fifo_dat, wr_req, wr_dat) + BEGIN + nxt_fifo_dat <= fifo_dat; + IF wr_req='1' THEN + nxt_fifo_dat(0) <= wr_dat; + END IF; + rd_dat <= fifo_dat(0); + END PROCESS; + END GENERATE; + + ASSERT c_regbank_size>=c_pipeline SEVERITY FAILURE; + +END rtl; diff --git a/applications/lofar1/pft2/src/vhdl/pft_bf_fw.vhd b/applications/lofar1/pft2/src/vhdl/pft_bf_fw.vhd index 72b79634029d9adf395405f716ad8054afdc3ed6..b3920c53f36ac381fcfa4792845463a2e76d6a2a 100644 --- a/applications/lofar1/pft2/src/vhdl/pft_bf_fw.vhd +++ b/applications/lofar1/pft2/src/vhdl/pft_bf_fw.vhd @@ -1,6 +1,33 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. -LIBRARY ieee; -USE IEEE.std_logic_1164.ALL; +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +LIBRARY common_lib; ENTITY pft_bf_fw IS @@ -26,3 +53,239 @@ ENTITY pft_bf_fw IS ); END pft_bf_fw; + +ARCHITECTURE rtl OF pft_bf_fw IS + + CONSTANT c_add_pipeline : NATURAL := 2; + CONSTANT c_dist : NATURAL := 2**g_index; + CONSTANT c_pipeline : NATURAL := c_add_pipeline + c_dist + 2; + CONSTANT c_cnt_w : NATURAL := g_index + 2; + + TYPE reg_arr IS ARRAY (c_dist DOWNTO -c_dist) OF STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0); + TYPE val_arr IS ARRAY (c_dist DOWNTO -c_dist) OF STD_LOGIC; + + SIGNAL xr : reg_arr; + SIGNAL nxt_xr : reg_arr; + + SIGNAL xi : reg_arr; + SIGNAL nxt_xi : reg_arr; + + + SIGNAL pipe_val : STD_LOGIC_VECTOR(c_pipeline-1 DOWNTO 0); + SIGNAL nxt_pipe_val : STD_LOGIC_VECTOR(pipe_val'RANGE); + SIGNAL pipe_sync : STD_LOGIC_VECTOR(c_pipeline-1 DOWNTO 0); + SIGNAL nxt_pipe_sync : STD_LOGIC_VECTOR(pipe_sync'RANGE); + + SIGNAL cnt : STD_LOGIC_VECTOR(c_cnt_w-1 DOWNTO 0); + SIGNAL nxt_cnt : STD_LOGIC_VECTOR(cnt'RANGE); + SIGNAL s0 : STD_LOGIC; + SIGNAL s1 : STD_LOGIC; + + SIGNAL yr_a : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0); + SIGNAL yr_b : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0); + SIGNAL yi_a : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0); + SIGNAL yi_b : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0); + SIGNAL yr_add : STD_LOGIC; + SIGNAL yi_add : STD_LOGIC; + SIGNAL yr_cry : STD_LOGIC; + SIGNAL yi_cry : STD_LOGIC; + + + SIGNAL nxt_yr_a : STD_LOGIC_VECTOR(yr_a'RANGE); + SIGNAL nxt_yr_b : STD_LOGIC_VECTOR(yr_b'RANGE); + SIGNAL nxt_yi_a : STD_LOGIC_VECTOR(yi_a'RANGE); + SIGNAL nxt_yi_b : STD_LOGIC_VECTOR(yi_b'RANGE); + SIGNAL nxt_yr_add : STD_LOGIC; + SIGNAL nxt_yi_add : STD_LOGIC; + + +BEGIN + + nxt_xr <= in_re & xr (xr 'HIGH DOWNTO xr 'LOW+1); + nxt_xi <= in_im & xi (xi 'HIGH DOWNTO xi 'LOW+1); + + nxt_pipe_val <= in_val & pipe_val (pipe_val 'HIGH DOWNTO 1); + nxt_pipe_sync <= in_sync & pipe_sync(pipe_sync'HIGH DOWNTO 1); + + s0 <= cnt(cnt'HIGH-1); + s1 <= cnt(cnt'HIGH ) WHEN g_bf_name="bf2" ELSE '0'; + + out_val <= pipe_val(0); + out_sync <= pipe_sync(0); + + registers : PROCESS (clk, rst) + BEGIN + IF rst = '1' THEN + xr <= (OTHERS => (OTHERS => '0')); + xi <= (OTHERS => (OTHERS => '0')); + pipe_val <= (OTHERS => '0'); + pipe_sync <= (OTHERS => '0'); + cnt <= (OTHERS => '0'); + yr_a <= (OTHERS => '0'); + yr_b <= (OTHERS => '0'); + yi_a <= (OTHERS => '0'); + yi_b <= (OTHERS => '0'); + yr_add <= '0'; + yi_add <= '0'; + ELSIF RISING_EDGE(clk) THEN + xr <= nxt_xr; + xi <= nxt_xi; + pipe_val <= nxt_pipe_val; + pipe_sync <= nxt_pipe_sync; + cnt <= nxt_cnt; + yr_a <= nxt_yr_a; + yr_b <= nxt_yr_b; + yi_a <= nxt_yi_a; + yi_b <= nxt_yi_b; + yr_add <= nxt_yr_add; + yi_add <= nxt_yi_add; + END IF; + END PROCESS; + + + counter : PROCESS (cnt, pipe_val, pipe_sync) + BEGIN + nxt_cnt <= cnt; + IF pipe_sync(pipe_sync'HIGH-c_dist) = '1' THEN + nxt_cnt <= (OTHERS => '0'); + ELSIF pipe_val(pipe_val'HIGH-c_dist) = '1' THEN + nxt_cnt <= STD_LOGIC_VECTOR(UNSIGNED(cnt) + 1); + END IF; + END PROCESS; + + + PROCESS(s0,s1,xr,xi) + VARIABLE state : STD_LOGIC_VECTOR (1 DOWNTO 0); + BEGIN + state := s1 & s0; + CASE state IS + + WHEN "00" => + -- y <= x(n+k) + x(n) + + -- yr <= xr(n+k) + xr(n) + nxt_yr_add <= '1'; + nxt_yr_a <= xr(0); + nxt_yr_b <= xr(c_dist); + -- yi <= xi(n+k) + xi(n); + nxt_yi_add <= '1'; + nxt_yi_a <= xi(0); + nxt_yi_b <= xi(c_dist); + + WHEN "01" => + -- y <= x(n-k) - x(n) + + -- yr <= xr(n-k) - xr(n) + nxt_yr_add <= '0'; + nxt_yr_a <= xr(-c_dist); + nxt_yr_b <= xr(0); + -- yi <= xi(n-k) - xi(n) + nxt_yi_add <= '0'; + nxt_yi_a <= xi(-c_dist); + nxt_yi_b <= xi(0); + + WHEN "10" => + -- y <= x(n) - i*x(n+k) + + -- yr <= xr(n) + xi(n+k) + nxt_yr_add <= '1'; + nxt_yr_a <= xr(0); + nxt_yr_b <= xi(c_dist); + -- yi <= xi(n) - xr(n+k) + nxt_yi_add <= '0'; + nxt_yi_a <= xi(0); + nxt_yi_b <= xr(c_dist); + + WHEN OTHERS => + -- y <= x(n-k) + i*x(n) + -- yr(n) <= xr(n-k) - xi(n); + nxt_yr_add <= '0'; + nxt_yr_a <= xr(-c_dist); + nxt_yr_b <= xi(0); + -- yi(n) <= xi(n-k) + xr(n); + nxt_yi_add <= '1'; + nxt_yi_a <= xi(-c_dist); + nxt_yi_b <= xr(0); + + END CASE; + END PROCESS; + + -- Adds/ Subs ---------------------------------------------------------------- + +-- Intel Altera lmp_add_sub carry in: +-- ADD: out = a + b + cin => cin = '0' to have out = a + b +-- SUB: out = a - b + cin - 1 => cin = '1' to have out = a - b + +-- yr_cry <= NOT yr_add; + +-- yr : ENTITY common_lib.common_addsub +-- GENERIC MAP ( +-- g_in_a_w => g_in_dat_w, +-- g_in_b_w => g_in_dat_w, +-- g_out_c_w => g_out_dat_w, +-- g_pipeline => c_add_pipeline, +-- g_add_sub => "BOTH" +-- ) +-- PORT MAP ( +-- in_a => yr_a, +-- in_b => yr_b, +-- in_cry => yr_cry, +-- add_sub => yr_add, +-- clk => clk, +-- out_c => out_re +-- ); + + yr : ENTITY common_lib.common_add_sub + GENERIC MAP ( + g_direction => "BOTH", + g_representation => "SIGNED", + g_pipeline_input => 0, -- 0 or 1 + g_pipeline_output => c_add_pipeline, -- >= 0 + g_in_dat_w => g_in_dat_w, + g_out_dat_w => g_out_dat_w -- only support g_out_dat_w=g_in_dat_w and g_out_dat_w=g_in_dat_w+1 + ) + PORT MAP ( + clk => clk, + sel_add => yr_add, + in_a => yr_a, + in_b => yr_b, + result => out_re + ); + +-- yi_cry <= NOT yi_add; +-- +-- yi : ENTITY common_lib.common_addsub +-- GENERIC MAP ( +-- g_in_a_w => g_in_dat_w, +-- g_in_b_w => g_in_dat_w, +-- g_out_c_w => g_out_dat_w, +-- g_pipeline => c_add_pipeline, +-- g_add_sub => "BOTH" +-- ) +-- PORT MAP ( +-- in_a => yi_a, +-- in_b => yi_b, +-- in_cry => yi_cry, +-- add_sub => yi_add, +-- clk => clk, +-- out_c => out_im +-- ); + + yi : ENTITY common_lib.common_add_sub + GENERIC MAP ( + g_direction => "BOTH", + g_representation => "SIGNED", + g_pipeline_input => 0, -- 0 or 1 + g_pipeline_output => c_add_pipeline, -- >= 0 + g_in_dat_w => g_in_dat_w, + g_out_dat_w => g_out_dat_w -- only support g_out_dat_w=g_in_dat_w and g_out_dat_w=g_in_dat_w+1 + ) + PORT MAP ( + clk => clk, + sel_add => yi_add, + in_a => yi_a, + in_b => yi_b, + result => out_im + ); + +END rtl; diff --git a/applications/lofar1/pft2/src/vhdl/pft_buffer.vhd b/applications/lofar1/pft2/src/vhdl/pft_buffer.vhd index 754cc0270e5e556e2893132beed1aad2ee18a256..d2112956ad7baa03567862da3426757ed982e9a9 100644 --- a/applications/lofar1/pft2/src/vhdl/pft_buffer.vhd +++ b/applications/lofar1/pft2/src/vhdl/pft_buffer.vhd @@ -1,6 +1,35 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. + LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +LIBRARY common_lib; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; ENTITY pft_buffer IS GENERIC ( @@ -23,3 +52,137 @@ ENTITY pft_buffer IS rst : IN STD_LOGIC ); END pft_buffer; + + +ARCHITECTURE rtl OF pft_buffer IS + + CONSTANT c_latency : NATURAL := 2; + CONSTANT c_adr_w : NATURAL := g_fft_size_w+1; + CONSTANT c_nof_words : NATURAL := 2**c_adr_w; + + CONSTANT c_ram : t_c_mem := (latency => c_latency, + adr_w => c_adr_w, + dat_w => 2*g_dat_w, + nof_dat => c_nof_words, -- <= 2**g_addr_w + init_sl => '0'); + + SIGNAL rd_dat : STD_LOGIC_VECTOR(2*g_dat_w-1 DOWNTO 0); + SIGNAL wr_dat : STD_LOGIC_VECTOR(rd_dat'RANGE); + SIGNAL rd_adr_paged : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0); + SIGNAL wr_adr_paged : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0); + SIGNAL wr_adr : STD_LOGIC_VECTOR(g_fft_size_w-1 DOWNTO 0); + SIGNAL nxt_wr_adr : STD_LOGIC_VECTOR(wr_adr'RANGE); + SIGNAL wr_page : STD_LOGIC; + SIGNAL nxt_wr_page : STD_LOGIC; + SIGNAL rd_page : STD_LOGIC; + SIGNAL nxt_rd_page : STD_LOGIC; + SIGNAL wr_en : STD_LOGIC; + + + SIGNAL pipe_val : STD_LOGIC_VECTOR(c_latency-1 DOWNTO 0); + SIGNAL nxt_pipe_val : STD_LOGIC_VECTOR(pipe_val'RANGE); + + FUNCTION bit_rev(adr : IN STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR IS + VARIABLE result: STD_LOGIC_VECTOR(adr'RANGE); + BEGIN + FOR i IN adr'HIGH DOWNTO 0 LOOP + result(i) := adr(adr'HIGH-i); + END LOOP; + RETURN result; + END FUNCTION; + +BEGIN + + nxt_rd_page <= NOT nxt_wr_page; + rd_adr_paged <= rd_page & rd_adr; + + registers : PROCESS (rst, clk) + BEGIN + IF rst = '1' THEN + pipe_val <= (OTHERS => '0'); + wr_adr <= (OTHERS => '0'); + wr_page <= '0'; + rd_page <= '1'; + ELSIF rising_edge(clk) THEN + pipe_val <= nxt_pipe_val; + wr_adr <= nxt_wr_adr; + wr_page <= nxt_wr_page; + rd_page <= nxt_rd_page; + END IF; + END PROCESS; + + pipe_proc: PROCESS(pipe_val,rd_en) + BEGIN + nxt_pipe_val <= rd_en & pipe_val (pipe_val 'HIGH DOWNTO 1); + rd_val <= pipe_val(0); + END PROCESS; + + wr_adr_proc : PROCESS (wr_adr, wr_en, wr_page, wr_sync) + BEGIN + nxt_wr_adr <= wr_adr; + nxt_wr_page <= wr_page; + rd_rdy <= '0'; + rd_sync <= '0'; + IF wr_en='1' THEN + IF SIGNED(wr_adr) = -1 OR wr_sync='1' THEN + rd_rdy <= '1'; + rd_sync <= wr_sync; + nxt_wr_page <= NOT wr_page; + nxt_wr_adr <= (OTHERS => '0'); + ELSE + nxt_wr_adr <= STD_LOGIC_VECTOR(UNSIGNED(wr_adr) + 1); + END IF; + END IF; + wr_adr_paged <= wr_page & bit_rev(wr_adr); + END PROCESS; + + -- combine real and imaginary to a single data word + rd_proc : PROCESS (rd_dat, pipe_val) + BEGIN + rd_re <= rd_dat(rd_dat'HIGH DOWNTO rd_im'LENGTH); + rd_im <= rd_dat(rd_im'RANGE); + -- synthesis translate off + IF pipe_val(0)='0' THEN + rd_re <= (OTHERS => '0'); + rd_im <= (OTHERS => '0'); + END IF; + --synthesis translate on + END PROCESS; + + wr_dat <= wr_re & wr_im; + wr_en <= wr_val; + +-- -- ram module +-- ram : ENTITY common_lib.common_dpram +-- GENERIC MAP ( +-- g_dat_w => 2*g_dat_w, +-- g_adr_w => c_adr_w, +-- g_nof_words => c_nof_words +-- ) +-- PORT MAP ( +-- rd_dat => rd_dat, +-- rd_adr => rd_adr_paged, +-- rd_en => rd_en, +-- wr_dat => wr_dat, +-- wr_adr => wr_adr_paged, +-- wr_en => wr_en, +-- clk => clk, +-- rst => rst +-- ); + + ram : ENTITY common_lib.common_ram_r_w + GENERIC MAP ( + g_ram => c_ram + ) + PORT MAP ( + rst => rst, + clk => clk, + wr_en => wr_en, + wr_adr => wr_adr_paged, + wr_dat => wr_dat, + rd_en => rd_en, + rd_adr => rd_adr_paged, + rd_dat => rd_dat + ); + +END rtl; diff --git a/applications/lofar1/pft2/src/vhdl/pft_lfsr.vhd b/applications/lofar1/pft2/src/vhdl/pft_lfsr.vhd index 63783fd6fb93b2b933f550f28313c4bc8dc19467..afcb2c4b9c54ed883ce8cb5c32aea6078ddeda49 100644 --- a/applications/lofar1/pft2/src/vhdl/pft_lfsr.vhd +++ b/applications/lofar1/pft2/src/vhdl/pft_lfsr.vhd @@ -1,3 +1,28 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. + LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; @@ -11,3 +36,57 @@ ENTITY pft_lfsr IS ); END pft_lfsr; + +ARCHITECTURE rtl OF pft_lfsr IS + + -- uses preferred pair of pritive trinomials + -- x^41 + x^20 + 1 and x^41 + x^3 + 1 + -- see XAPP217 + + CONSTANT c_max : NATURAL := 41; + CONSTANT c1 : NATURAL := 20; + CONSTANT c2 : NATURAL := 3; + + SIGNAL s1 : STD_LOGIC_VECTOR(c_max-1 DOWNTO 0); + SIGNAL nxt_s1 : STD_LOGIC_VECTOR(c_max-1 DOWNTO 0); + + SIGNAL s2 : STD_LOGIC_VECTOR(c_max-1 DOWNTO 0); + SIGNAL nxt_s2 : STD_LOGIC_VECTOR(c_max-1 DOWNTO 0); + + +BEGIN + regs: PROCESS(rst,clk) + BEGIN + IF rst='1' THEN + s1 <= "01000101011101110101001011111000101100001"; + s2 <= "11011001000101001011011001110101100101100"; + ELSIF rising_edge(clk) THEN + s1 <= nxt_s1; + s2 <= nxt_s2; + END IF; + END PROCESS; + + out_bit1 <= s1(s1'HIGH); + out_bit2 <= s2(s2'HIGH); + + seed_proc: PROCESS(in_en,s1,s2) + BEGIN + nxt_s1 <= s1; + nxt_s2 <= s2; + IF in_en='1' THEN + -- shift + nxt_s1(c_max-1 DOWNTO 1) <= s1(c_max-2 DOWNTO 0); + nxt_s2(c_max-1 DOWNTO 1) <= s2(c_max-2 DOWNTO 0); + + -- feedback 1 + nxt_s1(0) <= s1(c_max-1); + nxt_s2(0) <= s2(c_max-1); + + -- feedback 2 + nxt_s1(c1) <= s1(c_max-1) xor s1(c1-1); + nxt_s2(c2) <= s2(c_max-1) xor s2(c2-1); + END IF; + END PROCESS; + +end rtl; + diff --git a/applications/lofar1/pft2/src/vhdl/pft_pkg.vhd b/applications/lofar1/pft2/src/vhdl/pft_pkg.vhd new file mode 100644 index 0000000000000000000000000000000000000000..d6d92acaa5ee83e7eae38fa60e4369a7f88d56a2 --- /dev/null +++ b/applications/lofar1/pft2/src/vhdl/pft_pkg.vhd @@ -0,0 +1,50 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Copy of pft(pkg).vhd to avoid () in file name. + +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +PACKAGE pft_pkg IS + CONSTANT c_pft_stage_dat_w : NATURAL := 20; + + TYPE pft_mode_type IS ( + PFT_MODE_BITREV, + PFT_MODE_COMPLEX, + PFT_MODE_REAL2 + ); + + TYPE pft_bf_type IS ( + PFT_BF1, + PFT_BF2 + ); + +END pft_pkg; + + +PACKAGE BODY pft_pkg IS +END pft_pkg; + + diff --git a/applications/lofar1/pft2/src/vhdl/pft_reverse.vhd b/applications/lofar1/pft2/src/vhdl/pft_reverse.vhd index 5f42d6600a389dde3a1c90c63ca4177f89cd6d7b..43c1cc8348c149c76387265ee04af7770190a684 100644 --- a/applications/lofar1/pft2/src/vhdl/pft_reverse.vhd +++ b/applications/lofar1/pft2/src/vhdl/pft_reverse.vhd @@ -1,6 +1,31 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. + LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; - +USE IEEE.NUMERIC_STD.ALL; ENTITY pft_reverse IS GENERIC ( @@ -26,3 +51,65 @@ ENTITY pft_reverse IS rst : IN STD_LOGIC ); END pft_reverse; + + +ARCHITECTURE rtl OF pft_reverse IS + + SIGNAL i_rdaddr : STD_LOGIC_VECTOR(rdaddr'RANGE); + SIGNAL nxt_rdaddr : STD_LOGIC_VECTOR(rdaddr'RANGE); + SIGNAL i_rden : STD_LOGIC; + SIGNAL nxt_rden : STD_LOGIC; + SIGNAL rdrdy : STD_LOGIC; + + +BEGIN + + rdaddr <= i_rdaddr; + rden <= i_rden; + page_done <= rdrdy; + + registers : PROCESS (rst, clk) + BEGIN + IF rst = '1' THEN + -- Output signals. + i_rdaddr <= (OTHERS => '0'); + i_rden <= '0'; + -- Internal signals. + ELSIF rising_edge(clk) THEN + -- Output signals. + i_rdaddr <= nxt_rdaddr; + i_rden <= nxt_rden; + -- Internal signals. + END IF; + END PROCESS; + + + read_enable_control : PROCESS (i_rden, page_rdy, rdrdy) + BEGIN + nxt_rden <= i_rden; + IF page_rdy = '1' THEN + nxt_rden <= '1'; + ELSIF rdrdy = '1' THEN + nxt_rden <= '0'; + END IF; + END PROCESS; + + + read_addr_control : PROCESS (i_rdaddr, i_rden) + BEGIN + rdrdy <= '0'; + nxt_rdaddr <= i_rdaddr; + IF UNSIGNED(i_rdaddr) >= g_fft_sz-1 THEN + nxt_rdaddr <= (OTHERS => '0'); + rdrdy <= '1'; + ELSIF i_rden = '1' THEN + nxt_rdaddr <= STD_LOGIC_VECTOR(UNSIGNED(i_rdaddr) + 1); + END IF; + END PROCESS; + + + out_dat_re <= rddata_re WHEN rdval = '1' ELSE (OTHERS => '0'); + out_dat_im <= rddata_im WHEN rdval = '1' ELSE (OTHERS => '0'); + out_val <= '1' WHEN rdval = '1' ELSE '0'; + out_sync <= '1' WHEN rdsync = '1' ELSE '0'; +END rtl; diff --git a/applications/lofar1/pft2/src/vhdl/pft_separate.vhd b/applications/lofar1/pft2/src/vhdl/pft_separate.vhd index c3bd638faa3d6376f5fe0fb4687f110a74c88ec0..f1b6206b2d82a886c7ca0b980ad08d635687f37b 100644 --- a/applications/lofar1/pft2/src/vhdl/pft_separate.vhd +++ b/applications/lofar1/pft2/src/vhdl/pft_separate.vhd @@ -1,6 +1,31 @@ -LIBRARY IEEE; -USE IEEE.STD_LOGIC_1164.ALL; +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. +LIBRARY IEEE, common_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; ENTITY pft_separate IS GENERIC ( @@ -26,3 +51,239 @@ ENTITY pft_separate IS rst : IN STD_LOGIC ); END pft_separate; + + +ARCHITECTURE rtl OF pft_separate IS + + CONSTANT c_reg_delay : NATURAL := 2; + CONSTANT c_add_delay : NATURAL := 2; + CONSTANT c_tot_delay : NATURAL := c_reg_delay + c_add_delay; + + TYPE data_dly_arr IS ARRAY (NATURAL RANGE <>) OF STD_LOGIC_VECTOR(rddata_re'RANGE); + + SIGNAL nxt_rden : STD_LOGIC; + + SIGNAL cnt : STD_LOGIC_VECTOR(rdaddr'HIGH DOWNTO 0); + SIGNAL nxt_cnt : STD_LOGIC_VECTOR(cnt'RANGE); + + SIGNAL rddata_re_dly : data_dly_arr(0 TO c_reg_delay); + SIGNAL rddata_im_dly : data_dly_arr(0 TO c_reg_delay); + + SIGNAL rd_cnt : STD_LOGIC_VECTOR(g_fft_sz_w-1 DOWNTO 0); + SIGNAL nxt_rd_cnt : STD_LOGIC_VECTOR(rd_cnt'RANGE); + + SIGNAL page_rdy_dly : STD_LOGIC_VECTOR( 0 TO c_tot_delay-1); + SIGNAL rdval_dly : STD_LOGIC_VECTOR( 0 TO c_tot_delay-1); + SIGNAL rdsync_dly : STD_LOGIC_VECTOR( 0 TO c_tot_delay+1); + SIGNAL nxt_rdsync_dly : STD_LOGIC_VECTOR(rdsync_dly'RANGE); + SIGNAL rdsync_reg : STD_LOGIC; + SIGNAL nxt_rdsync_reg : STD_LOGIC; + + SIGNAL nxt_out_dat_re : STD_LOGIC_VECTOR(out_dat_re'RANGE); + SIGNAL nxt_out_dat_im : STD_LOGIC_VECTOR(out_dat_im'RANGE); + SIGNAL nxt_out_val : STD_LOGIC; + SIGNAL nxt_out_sync : STD_LOGIC; + + SIGNAL add_out : STD_LOGIC_VECTOR(out_dat_re'RANGE); + SIGNAL add0 : STD_LOGIC_VECTOR(rddata_re'RANGE); + SIGNAL add1 : STD_LOGIC_VECTOR(rddata_re'RANGE); + SIGNAL nxt_add0 : STD_LOGIC_VECTOR(rddata_re'RANGE); + SIGNAL nxt_add1 : STD_LOGIC_VECTOR(rddata_re'RANGE); + SIGNAL sub_out : STD_LOGIC_VECTOR(out_dat_im'RANGE); + SIGNAL sub0 : STD_LOGIC_VECTOR(rddata_re'RANGE); + SIGNAL sub1 : STD_LOGIC_VECTOR(rddata_re'RANGE); + SIGNAL nxt_sub0 : STD_LOGIC_VECTOR(rddata_re'RANGE); + SIGNAL nxt_sub1 : STD_LOGIC_VECTOR(rddata_re'RANGE); + +BEGIN + + + registers : PROCESS (rst, clk) + BEGIN + IF rst = '1' THEN + -- Output signals. + out_dat_re <= (OTHERS => '0'); + out_dat_im <= (OTHERS => '0'); + out_val <= '0'; + out_sync <= '0'; + rden <= '0'; + -- Internal signals. + cnt <= STD_LOGIC_VECTOR(TO_SIGNED(-2,g_fft_sz_w)); + rd_cnt <= (OTHERS => '0'); + page_rdy_dly <= (OTHERS => '0'); + rddata_re_dly <= (OTHERS => (OTHERS => '0')); + rddata_im_dly <= (OTHERS => (OTHERS => '0')); + rdval_dly <= (OTHERS => '0'); + rdsync_dly <= (OTHERS => '0'); + rdsync_reg <= '0'; + add0 <= (OTHERS => '0'); + add1 <= (OTHERS => '0'); + sub0 <= (OTHERS => '0'); + sub1 <= (OTHERS => '0'); + ELSIF rising_edge(clk) THEN + -- Output signals. + out_dat_re <= nxt_out_dat_re; + out_dat_im <= nxt_out_dat_im; + out_val <= nxt_out_val; + out_sync <= nxt_out_sync; + rden <= nxt_rden; + -- Internal signals. + cnt <= nxt_cnt; + rd_cnt <= nxt_rd_cnt; + page_rdy_dly <= page_rdy & page_rdy_dly(0 TO page_rdy_dly'HIGH -1); + rddata_re_dly <= rddata_re & rddata_re_dly(0 TO rddata_re_dly'HIGH-1); + rddata_im_dly <= rddata_im & rddata_im_dly(0 TO rddata_im_dly'HIGH-1); + rdval_dly <= rdval & rdval_dly(0 TO rdval_dly'HIGH-1); + rdsync_dly <= nxt_rdsync_dly; + rdsync_reg <= nxt_rdsync_reg; + add0 <= nxt_add0; + add1 <= nxt_add1; + sub0 <= nxt_sub0; + sub1 <= nxt_sub1; + END IF; + END PROCESS; + + sync_proc : PROCESS(page_rdy, rdsync, rdsync_dly, rdsync_reg) + BEGIN + nxt_rdsync_reg <= rdsync_reg; + nxt_rdsync_dly <= '0' & rdsync_dly(0 TO rdsync_dly'HIGH -1); + IF page_rdy='1' THEN + nxt_rdsync_reg <= rdsync; + nxt_rdsync_dly <= ( 0 => rdsync_reg, OTHERS => '0'); + END IF; + END PROCESS; + + cnt_control : PROCESS (cnt, page_rdy) + BEGIN + nxt_rden <= '0'; + nxt_cnt <= cnt; + IF page_rdy='1' THEN + nxt_cnt <= (OTHERS => '1'); + nxt_rden <= '1'; + ELSIF SIGNED(cnt)/=-2 THEN + nxt_cnt <= STD_LOGIC_VECTOR(UNSIGNED(cnt) + 1); + nxt_rden <= '1'; + END IF; + END PROCESS; + + + addr_gen : PROCESS (cnt) + BEGIN + rdaddr <= (OTHERS => '0'); + IF cnt(0) = '0' THEN + rdaddr <= '0' & cnt(cnt'HIGH DOWNTO 1); + ELSE + rdaddr <= '1' & STD_LOGIC_VECTOR(NOT(UNSIGNED(cnt(cnt'HIGH DOWNTO 1)))); + END IF; + END PROCESS; + + rd_counter : PROCESS (rd_cnt, rdval_dly, page_rdy_dly) + BEGIN + nxt_rd_cnt <= rd_cnt; + IF page_rdy_dly(3) = '1' THEN + nxt_rd_cnt <= (OTHERS => '0'); + ELSIF rdval_dly(1) = '1' THEN + nxt_rd_cnt <= STD_LOGIC_VECTOR(UNSIGNED(rd_cnt) + 1); + END IF; + END PROCESS; + + adder_inputs : PROCESS (rddata_re_dly, rddata_im_dly, rd_cnt) + BEGIN + IF UNSIGNED(rd_cnt)=0 THEN + nxt_add0 <= rddata_re_dly(0); + nxt_add1 <= rddata_re_dly(0); + nxt_sub0 <= rddata_re_dly(1); + nxt_sub1 <= STD_LOGIC_VECTOR(-SIGNED(rddata_re_dly(1))); + ELSIF UNSIGNED(rd_cnt)=1 THEN + nxt_add0 <= rddata_im_dly(1); + nxt_add1 <= rddata_im_dly(1); + nxt_sub0 <= rddata_im_dly(2); + nxt_sub1 <= STD_LOGIC_VECTOR(-SIGNED(rddata_im_dly(2))); + ELSIF rd_cnt(0) = '0' THEN + nxt_add0 <= rddata_re_dly(0); + nxt_add1 <= rddata_re_dly(1); + nxt_sub0 <= rddata_im_dly(0); + nxt_sub1 <= rddata_im_dly(1); + ELSE + nxt_add0 <= rddata_im_dly(2); + nxt_add1 <= rddata_im_dly(1); + nxt_sub0 <= rddata_re_dly(2); + nxt_sub1 <= rddata_re_dly(1); + END IF; + END PROCESS; + + + nxt_out_dat_re <= add_out; + nxt_out_dat_im <= sub_out; + nxt_out_val <= rdval_dly(rdval_dly'HIGH); + nxt_out_sync <= rdsync_dly(rdsync_dly'HIGH); + +-- Intel Altera lmp_add_sub carry in: +-- ADD: out = a + b + cin => cin = '0' to have out = a + b +-- SUB: out = a - b + cin - 1 => cin = '1' to have out = a - b + +-- add : ENTITY common_lib.common_addsub +-- GENERIC MAP ( +-- g_in_a_w => add0'LENGTH, +-- g_in_b_w => add1'LENGTH, +-- g_out_c_w => add_out'LENGTH, +-- g_pipeline => c_add_delay-1, +-- g_add_sub => "ADD" +-- ) +-- PORT MAP ( +-- in_a => add0, +-- in_b => add1, +-- in_cry => '0', +-- out_c => add_out, +-- clk => clk +-- ); + + add : ENTITY common_lib.common_add_sub + GENERIC MAP ( + g_direction => "ADD", + g_representation => "SIGNED", + g_pipeline_input => 0, -- 0 or 1 + g_pipeline_output => c_add_delay-1, -- >= 0 + g_in_dat_w => g_rd_dat_w, + g_out_dat_w => g_out_dat_w -- only support g_out_dat_w=g_in_dat_w and g_out_dat_w=g_in_dat_w+1 + ) + PORT MAP ( + clk => clk, + in_a => add0, + in_b => add1, + result => add_out + ); + +-- sub : ENTITY common_lib.common_addsub +-- GENERIC MAP ( +-- g_in_a_w => sub0'LENGTH, +-- g_in_b_w => sub1'LENGTH, +-- g_out_c_w => sub_out'LENGTH, +-- g_pipeline => c_add_delay-1, +-- g_add_sub => "SUB" +-- ) +-- PORT MAP ( +-- in_a => sub0, +-- in_b => sub1, +-- in_cry => '1', +-- out_c => sub_out, +-- clk => clk +-- ); + + sub : ENTITY common_lib.common_add_sub + GENERIC MAP ( + g_direction => "SUB", + g_representation => "SIGNED", + g_pipeline_input => 0, -- 0 or 1 + g_pipeline_output => c_add_delay-1, -- >= 0 + g_in_dat_w => g_rd_dat_w, + g_out_dat_w => g_out_dat_w -- only support g_out_dat_w=g_in_dat_w and g_out_dat_w=g_in_dat_w+1 + ) + PORT MAP ( + clk => clk, + in_a => sub0, + in_b => sub1, + result => sub_out + ); + +END rtl; diff --git a/applications/lofar1/pft2/src/vhdl/pft_stage.vhd b/applications/lofar1/pft2/src/vhdl/pft_stage.vhd index 558c51bc5ef55eaac5aed20be3389dfd9162d212..14d769a3c4a4169c8b4895478fe2622939328abe 100644 --- a/applications/lofar1/pft2/src/vhdl/pft_stage.vhd +++ b/applications/lofar1/pft2/src/vhdl/pft_stage.vhd @@ -1,6 +1,32 @@ -LIBRARY IEEE; +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. + +LIBRARY IEEE, common_lib; USE IEEE.STD_LOGIC_1164.ALL; + ENTITY pft_stage IS GENERIC ( g_index : NATURAL; @@ -19,4 +45,172 @@ ENTITY pft_stage IS clk : IN STD_LOGIC; rst : IN STD_LOGIC ); -END pft_stage; \ No newline at end of file +END pft_stage; + + +ARCHITECTURE str OF pft_stage IS + + CONSTANT c_round_pipeline_in : NATURAL := 1; + CONSTANT c_round_pipeline_out : NATURAL := 1; + CONSTANT c_round_pipeline : NATURAL := c_round_pipeline_in + c_round_pipeline_out; + + CONSTANT c_bf1_out_w : NATURAL := g_in_dat_w + 1; + CONSTANT c_bf2_out_w : NATURAL := g_in_dat_w + 2; + + SIGNAL bf1_re : STD_LOGIC_VECTOR(c_bf1_out_w-1 DOWNTO 0); + SIGNAL bf1_im : STD_LOGIC_VECTOR(c_bf1_out_w-1 DOWNTO 0); + SIGNAL bf1_val : STD_LOGIC; + SIGNAL bf1_sync : STD_LOGIC; + + SIGNAL bf2_re : STD_LOGIC_VECTOR(c_bf2_out_w-1 DOWNTO 0); + SIGNAL bf2_im : STD_LOGIC_VECTOR(c_bf2_out_w-1 DOWNTO 0); + SIGNAL bf2_val : STD_LOGIC; + SIGNAL bf2_sync : STD_LOGIC; + +BEGIN + + gen_middle: IF g_index>0 GENERATE + + bf1 : ENTITY work.pft_bf + GENERIC MAP ( + g_index => 2*g_index+1, + g_in_dat_w => g_in_dat_w, + g_out_dat_w => c_bf1_out_w, + g_bf_name => "bf1" + ) + PORT MAP ( + in_re => in_re, + in_im => in_im, + in_val => in_val, + in_sync => in_sync, + out_re => bf1_re, + out_im => bf1_im, + out_val => bf1_val, + out_sync => bf1_sync, + clk => clk, + rst => rst + ); + + bf2 : ENTITY work.pft_bf + GENERIC MAP ( + g_index => 2*g_index, + g_in_dat_w => c_bf1_out_w, + g_out_dat_w => c_bf2_out_w, + g_bf_name => "bf2" + ) + PORT MAP ( + in_re => bf1_re, + in_im => bf1_im, + in_val => bf1_val, + in_sync => bf1_sync, + out_re => bf2_re, + out_im => bf2_im, + out_val => bf2_val, + out_sync => bf2_sync, + clk => clk, + rst => rst + ); + + tmult : ENTITY work.pft_tmult + GENERIC MAP ( + g_in_dat_w => c_bf2_out_w, + g_out_dat_w => g_out_dat_w, + g_index => g_index + ) + PORT MAP ( + in_re => bf2_re, + in_im => bf2_im, + in_val => bf2_val, + in_sync => bf2_sync, + out_re => out_re, + out_im => out_im, + out_val => out_val, + out_sync => out_sync, + clk => clk, + rst => rst + ); + END GENERATE; + + gen_last: IF g_index=0 GENERATE + + SIGNAL reg_val : STD_LOGIC; + SIGNAL reg_sync : STD_LOGIC; + + BEGIN + + bf1_fw : ENTITY work.pft_bf_fw + GENERIC MAP ( + g_index => 2*g_index+1, + g_in_dat_w => g_in_dat_w, + g_out_dat_w => c_bf1_out_w, + g_bf_name => "bf1" + ) + PORT MAP ( + in_re => in_re, + in_im => in_im, + in_val => in_val, + in_sync => in_sync, + out_re => bf1_re, + out_im => bf1_im, + out_val => bf1_val, + out_sync => bf1_sync, + clk => clk, + rst => rst + ); + + bf2_fw : ENTITY work.pft_bf_fw + GENERIC MAP ( + g_index => 2*g_index, + g_in_dat_w => c_bf1_out_w, + g_out_dat_w => c_bf2_out_w, + g_bf_name => "bf2" + ) + PORT MAP ( + in_re => bf1_re, + in_im => bf1_im, + in_val => bf1_val, + in_sync => bf1_sync, + out_re => bf2_re, + out_im => bf2_im, + out_val => bf2_val, + out_sync => bf2_sync, + clk => clk, + rst => rst + ); + + u_rnd : ENTITY common_lib.common_complex_round + GENERIC MAP ( + g_representation => "SIGNED", + g_round => TRUE, + g_round_clip => FALSE, + g_pipeline_input => c_round_pipeline_in, + g_pipeline_output => c_round_pipeline_out, + g_in_dat_w => c_bf2_out_w, + g_out_dat_w => g_out_dat_w + ) + PORT MAP ( + in_re => bf2_re, + in_im => bf2_im, + out_re => out_re, + out_im => out_im, + clk => clk + ); + + p_regs: PROCESS(clk,rst) + BEGIN + IF rst='1' THEN + reg_val <= '0'; + reg_sync <= '0'; + out_val <= '0'; + out_sync <= '0'; + ELSIF rising_edge(clk) THEN + out_val <= reg_val; + out_sync <= reg_sync; + reg_val <= bf2_val; + reg_sync <= bf2_sync; + END IF; + END PROCESS; + + END GENERATE; + +END str; diff --git a/applications/lofar1/pft2/src/vhdl/pft_switch.vhd b/applications/lofar1/pft2/src/vhdl/pft_switch.vhd index f8be448d483fd5fa341317147413748d742b14c0..ef05f46339693ec4d35fa08c39f3e24eafea95fa 100644 --- a/applications/lofar1/pft2/src/vhdl/pft_switch.vhd +++ b/applications/lofar1/pft2/src/vhdl/pft_switch.vhd @@ -1,5 +1,32 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. + + LIBRARY IEEE; -USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; ENTITY pft_switch IS GENERIC ( @@ -21,3 +48,86 @@ ENTITY pft_switch IS rst : IN STD_LOGIC ); END pft_switch; + + +ARCHITECTURE rtl OF pft_switch IS + +SIGNAL cnt : STD_LOGIC_VECTOR(g_fft_sz_w DOWNTO 0); +SIGNAL nxt_cnt : STD_LOGIC_VECTOR(cnt'RANGE); + +SIGNAL lfsr_bit1 : STD_LOGIC; +SIGNAL lfsr_bit2 : STD_LOGIC; +SIGNAL lfsr_en : STD_LOGIC; + +SIGNAL nxt_out_val : STD_LOGIC; +SIGNAL nxt_out_sync : STD_LOGIC; +SIGNAL nxt_out_re : STD_LOGIC_VECTOR(in_re'RANGE); +SIGNAL nxt_out_im : STD_LOGIC_VECTOR(in_im'RANGE); + +BEGIN + + registers : PROCESS (rst, clk) + BEGIN + IF rst = '1' THEN + cnt <= (OTHERS => '0'); + out_val <= '0'; + out_sync <= '0'; + out_re <= (OTHERS => '0'); + out_im <= (OTHERS => '0'); + ELSIF rising_edge(clk) THEN + cnt <= nxt_cnt; + out_val <= nxt_out_val; + out_re <= nxt_out_re; + out_im <= nxt_out_im; + out_sync <= nxt_out_sync; + END IF; + END PROCESS; + + counter: PROCESS(cnt, in_val, in_sync) + BEGIN + nxt_cnt <= cnt; + IF in_sync='1' THEN + nxt_cnt <= (OTHERS => '0'); + ELSIF in_val='1' THEN + nxt_cnt <= STD_LOGIC_VECTOR(UNSIGNED(cnt)+1); + END IF; + END PROCESS; + + lfsr_ctrl: PROCESS(cnt,in_val) + BEGIN + if SIGNED(cnt)=-1 AND in_val='1' THEN + lfsr_en <= '1'; + ELSE + lfsr_en <= '0'; + END IF; + END PROCESS; + + proc: PROCESS(cnt, lfsr_bit1, lfsr_bit2, in_im, in_re, in_val, in_sync, switch_en) + BEGIN + nxt_out_val <= in_val; + nxt_out_sync <= in_sync AND in_val; + + IF lfsr_bit1=cnt(cnt'HIGH) AND switch_en='1' THEN + nxt_out_re <= STD_LOGIC_VECTOR(-SIGNED(in_re)); + ELSE + nxt_out_re <= in_re; + END IF; + + IF lfsr_bit2=cnt(cnt'HIGH) AND switch_en='1' THEN + nxt_out_im <= STD_LOGIC_VECTOR(-SIGNED(in_im)); + ELSE + nxt_out_im <= in_im; + END IF; + END PROCESS; + + lfsr: ENTITY work.pft_lfsr + PORT MAP ( + clk => clk, + rst => rst, + in_en => lfsr_en, + out_bit1 => lfsr_bit1, + out_bit2 => lfsr_bit2 + ); + + +END rtl; diff --git a/applications/lofar1/pft2/src/vhdl/pft_tmult.vhd b/applications/lofar1/pft2/src/vhdl/pft_tmult.vhd index dea2aba47e94459a501dbd45a1e6438ff68b088d..313619ba4908798189d8b5618e04dd6764842477 100644 --- a/applications/lofar1/pft2/src/vhdl/pft_tmult.vhd +++ b/applications/lofar1/pft2/src/vhdl/pft_tmult.vhd @@ -1,6 +1,36 @@ -LIBRARY ieee; -USE IEEE.std_logic_1164.ALL; -USE IEEE.numeric_std.ALL; +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. + +LIBRARY IEEE; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +LIBRARY common_mult_lib; +LIBRARY common_lib; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; ENTITY pft_tmult IS @@ -24,3 +54,175 @@ ENTITY pft_tmult IS END pft_tmult; +ARCHITECTURE rtl OF pft_tmult IS + + CONSTANT c_nof_twids : NATURAL := 16 * 2**(2*(g_index-1)); + CONSTANT c_adr_w : NATURAL := 2 + 2*g_index; + + CONSTANT c_mult_in_w : NATURAL := 18; + CONSTANT c_coeff_w : NATURAL := 16; + CONSTANT c_mult_out_w : NATURAL := c_mult_in_w + c_coeff_w-1; + + CONSTANT c_twid_rom : t_c_mem := (latency => 2, + adr_w => c_adr_w, + dat_w => 2*c_coeff_w, -- complex + nof_dat => 3*c_nof_twids/4, -- <= 2**g_addr_w + init_sl => '0'); + + CONSTANT c_twid_file : STRING := + "data/twiddle_" & NATURAL'IMAGE(c_coeff_w) + & "_" & NATURAL'IMAGE(g_index) & ".hex"; -- Quartus .hex extension, replaced by .bin in common_rom works for XST + --CONSTANT c_twid_file : STRING := + -- "../../../../../pft2/src/data/twiddle_" & NATURAL'IMAGE(c_coeff_w) + -- & "_" & NATURAL'IMAGE(g_index) & ".bin"; -- Synplify fails on file extension change to .bin in common_rom and requires extra ../ + + CONSTANT c_read_pipeline : NATURAL := 1; + CONSTANT c_mult_pipeline_input : NATURAL := 1; -- 0 or 1 + CONSTANT c_mult_pipeline_product : NATURAL := 0; -- 0 or 1 + CONSTANT c_mult_pipeline_adder : NATURAL := 1; -- 0 or 1 + CONSTANT c_mult_pipeline_output : NATURAL := 1; -- >= 0 + CONSTANT c_mult_pipeline : NATURAL := c_mult_pipeline_input + c_mult_pipeline_product + c_mult_pipeline_adder + c_mult_pipeline_output; -- = 3 + CONSTANT c_round_pipeline_in : NATURAL := 1; + CONSTANT c_round_pipeline_out : NATURAL := 1; + CONSTANT c_round_pipeline : NATURAL := c_round_pipeline_in + c_round_pipeline_out; + CONSTANT c_pipeline : NATURAL := c_round_pipeline + c_mult_pipeline + c_round_pipeline; + + SIGNAL reg_val : STD_LOGIC_VECTOR(c_pipeline-1 DOWNTO 0); + SIGNAL nxt_reg_val : STD_LOGIC_VECTOR(reg_val'RANGE); + SIGNAL reg_sync : STD_LOGIC_VECTOR(c_pipeline-1 DOWNTO 0); + + SIGNAL nxt_reg_sync : STD_LOGIC_VECTOR(reg_sync'RANGE); + + SIGNAL adr : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0); + SIGNAL nxt_adr : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0); + + SIGNAL cnt : STD_LOGIC_VECTOR(c_adr_w-1 DOWNTO 0); + SIGNAL nxt_cnt : STD_LOGIC_VECTOR(cnt'RANGE); + + SIGNAL mult_in_re : STD_LOGIC_VECTOR(c_mult_in_w-1 DOWNTO 0); + SIGNAL mult_in_im : STD_LOGIC_VECTOR(c_mult_in_w-1 DOWNTO 0); + + SIGNAL mult_out_re : STD_LOGIC_VECTOR(c_mult_out_w-1 DOWNTO 0); + SIGNAL mult_out_im : STD_LOGIC_VECTOR(c_mult_out_w-1 DOWNTO 0); + + SIGNAL coeff_dat : STD_LOGIC_VECTOR(2*c_coeff_w-1 DOWNTO 0); + SIGNAL coeff_re : STD_LOGIC_VECTOR(c_coeff_w-1 DOWNTO 0); + SIGNAL coeff_im : STD_LOGIC_VECTOR(c_coeff_w-1 DOWNTO 0); + +BEGIN + + p_regs : PROCESS (clk, rst) + BEGIN + IF rst = '1' THEN + reg_val <= (OTHERS => '0'); + reg_sync <= (OTHERS => '0'); + cnt <= (OTHERS => '0'); + adr <= (OTHERS => '0'); + coeff_re <= (OTHERS => '0'); + coeff_im <= (OTHERS => '0'); + ELSIF RISING_EDGE(clk) THEN + reg_val <= nxt_reg_val; + reg_sync <= nxt_reg_sync; + cnt <= nxt_cnt; + adr <= nxt_adr; + coeff_re <= coeff_dat(coeff_re'RANGE); + coeff_im <= coeff_dat(coeff_dat'HIGH DOWNTO coeff_re'LENGTH); + END IF; + END PROCESS; + + p_cnt : PROCESS (cnt, in_val, in_sync) + BEGIN + nxt_cnt <= cnt; + IF in_sync = '1' THEN + nxt_cnt <= (OTHERS => '0'); + ELSIF in_val = '1' THEN + nxt_cnt <= STD_LOGIC_VECTOR(UNSIGNED(cnt) + 1); + END IF; + END PROCESS; + + p_adr : PROCESS (adr, cnt, reg_sync) + BEGIN + nxt_adr <= adr; + IF UNSIGNED(adr)=3*c_nof_twids/4-1 OR reg_sync(reg_sync'HIGH)='1' THEN + nxt_adr <= (OTHERS => '0'); + ELSIF UNSIGNED(adr) > 0 OR UNSIGNED(cnt) = c_nof_twids/4-1 THEN + nxt_adr <= STD_LOGIC_VECTOR(UNSIGNED(adr) + 1); + END IF; + END PROCESS; + + nxt_reg_val <= in_val & reg_val(reg_val'HIGH DOWNTO 1); + nxt_reg_sync <= in_sync & reg_sync(reg_sync'HIGH DOWNTO 1); + out_val <= reg_val(0); + out_sync <= reg_sync(0); + + u_coeff : ENTITY common_lib.common_rom + GENERIC MAP ( + g_ram => c_twid_rom, + g_init_file => c_twid_file + ) + PORT MAP ( + rst => rst, + clk => clk, + rd_adr => adr, + rd_dat => coeff_dat + ); + + u_rnd1 : ENTITY common_lib.common_complex_round + GENERIC MAP ( + g_representation => "SIGNED", + g_round => TRUE, + g_round_clip => FALSE, + g_pipeline_input => c_round_pipeline_in, + g_pipeline_output => c_round_pipeline_out, + g_in_dat_w => g_in_dat_w, + g_out_dat_w => c_mult_in_w + ) + PORT MAP ( + in_re => in_re, + in_im => in_im, + out_re => mult_in_re, + out_im => mult_in_im, + clk => clk + ); + + u_cmult : ENTITY common_mult_lib.common_complex_mult + GENERIC MAP ( + g_variant => "IP", + g_in_a_w => c_mult_in_w, + g_in_b_w => c_coeff_w, + g_out_p_w => c_mult_out_w, + g_conjugate_b => FALSE, + g_pipeline_input => c_mult_pipeline_input, -- 0 or 1 + g_pipeline_product => c_mult_pipeline_product, -- 0 or 1 + g_pipeline_adder => c_mult_pipeline_adder, -- 0 or 1 + g_pipeline_output => c_mult_pipeline_output -- >= 0 + ) + PORT MAP ( + in_ar => mult_in_re, + in_ai => mult_in_im, + in_br => coeff_re, + in_bi => coeff_im, + out_pr => mult_out_re, + out_pi => mult_out_im, + clk => clk + ); + + u_rnd2 : ENTITY common_lib.common_complex_round + GENERIC MAP ( + g_representation => "SIGNED", + g_round => TRUE, + g_round_clip => FALSE, + g_pipeline_input => c_round_pipeline_in, + g_pipeline_output => c_round_pipeline_out, + g_in_dat_w => c_mult_out_w, + g_out_dat_w => g_out_dat_w + ) + PORT MAP ( + in_re => mult_out_re, + in_im => mult_out_im, + out_re => out_re, + out_im => out_im, + clk => clk + ); + +END rtl; diff --git a/applications/lofar1/pft2/src/vhdl/pft_unswitch.vhd b/applications/lofar1/pft2/src/vhdl/pft_unswitch.vhd index ded20e91067be5adee421b8d9e665198cbcd2df6..f1aff4542c88de4f86d365eb734a701ac16eea8d 100644 --- a/applications/lofar1/pft2/src/vhdl/pft_unswitch.vhd +++ b/applications/lofar1/pft2/src/vhdl/pft_unswitch.vhd @@ -1,5 +1,32 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- 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, original 2011 by W. Lubberhuizen / W. Poeisz +-- Purpose: Polyphase FIR filter +-- Description: Ported from LOFAR1, see readme_lofar1.txt +-- Remark: Put entity and architecture in same file without () in file name. + LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + ENTITY pft_unswitch IS GENERIC ( @@ -21,3 +48,83 @@ ENTITY pft_unswitch IS rst : IN STD_LOGIC ); END pft_unswitch; + + +ARCHITECTURE rtl OF pft_unswitch IS + +SIGNAL cnt : STD_LOGIC_VECTOR(g_fft_sz_w DOWNTO 0); +SIGNAL nxt_cnt : STD_LOGIC_VECTOR(cnt'RANGE); + +SIGNAL lfsr_bit1 : STD_LOGIC; +SIGNAL lfsr_bit2 : STD_LOGIC; + +SIGNAL lfsr_en : STD_LOGIC; + +SIGNAL nxt_out_val : STD_LOGIC; +SIGNAL nxt_out_sync : STD_LOGIC; +SIGNAL nxt_out_re : STD_LOGIC_VECTOR(in_re'RANGE); +SIGNAL nxt_out_im : STD_LOGIC_VECTOR(in_im'RANGE); + +BEGIN + + registers : PROCESS (rst, clk) + BEGIN + IF rst = '1' THEN + cnt <= (OTHERS => '0'); + out_val <= '0'; + out_sync <= '0'; + out_re <= (OTHERS => '0'); + out_im <= (OTHERS => '0'); + ELSIF rising_edge(clk) THEN + cnt <= nxt_cnt; + out_val <= nxt_out_val; + out_sync <= nxt_out_sync; + out_re <= nxt_out_re; + out_im <= nxt_out_im; + END IF; + END PROCESS; + + counter: PROCESS(cnt, in_val, in_sync) + BEGIN + nxt_cnt <= cnt; + IF in_sync='1' THEN + nxt_cnt <= (OTHERS => '0'); + ELSIF in_val='1' THEN + nxt_cnt <= STD_LOGIC_VECTOR(UNSIGNED(cnt)+1); + END IF; + END PROCESS; + + lfsr_ctrl: PROCESS(cnt,in_val) + BEGIN + if SIGNED(cnt)=-1 AND in_val='1' THEN + lfsr_en <= '1'; + ELSE + lfsr_en <= '0'; + END IF; + END PROCESS; + + proc: PROCESS(in_re, in_im, in_val, in_sync, cnt, lfsr_bit1, lfsr_bit2, switch_en) + BEGIN + nxt_out_val <= in_val; + nxt_out_sync <= in_sync AND in_val; + nxt_out_re <= in_re; + nxt_out_im <= in_im; + IF ((cnt(0)='0' AND cnt(cnt'HIGH)=lfsr_bit1) + OR (cnt(0)='1' AND cnt(cnt'HIGH)=lfsr_bit2)) AND (switch_en='1') THEN + nxt_out_re <= STD_LOGIC_VECTOR(-SIGNED(in_re)); + nxt_out_im <= STD_LOGIC_VECTOR(-SIGNED(in_im)); + END IF; + END PROCESS; + + lfsr: ENTITY work.pft_lfsr + PORT MAP ( + clk => clk, + rst => rst, + in_en => lfsr_en, + out_bit1 => lfsr_bit1, + out_bit2 => lfsr_bit2 + ); + + +END rtl; + diff --git a/applications/lofar1/readme_lofar1.txt b/applications/lofar1/readme_lofar1.txt index 64324e75cfc400b87c2aa9d802f1f1b52ca35611..31e53f11d8ca8602e072b6868f41c96f94717831 100644 --- a/applications/lofar1/readme_lofar1.txt +++ b/applications/lofar1/readme_lofar1.txt @@ -20,7 +20,9 @@ -- -- Author: E. Kooistra -This readme describes how the PFB (= pfs + pft2) code of LOFAR1/RSP was ported to git for LOFAR2 +This readme describes how the PFB (= pfs + pft2) code of LOFAR1 on RSP that +was created in 2011 by W. Lubberhuizen / W. Poiesz, was ported to git for +LOFAR2/SDP on UniBoard2 in 2021 by E. Kooistra. Contents 1) Comparison of LOFAR1 and APERTIF polyphase filterbank (PFB) @@ -29,6 +31,7 @@ Contents b) pft2 c) Simulating tb/vhdl/tb_pft2.vhd 3) Create pfb2_unit.vhd that can replace wpfb_unit_dev.vhd +4) Remove () from filenames References: @@ -59,7 +62,7 @@ a) pfs * src/vhdl/ - pfs_coefsbuf(str).vhd : . use c_coefs_rom : t_c_mem for common_rom from common_lib. - . use g_init_file => "data/pfs_coefsbuf_1024.hex" + . use g_init_file => "data/pfs_coefsbuf_1024.hex" = Coeffs16384Kaiser-quant.dat - pfs_filter(rtl).vhd : use ported common_mult_add.vhd from common_mult_lib * tb/vhdl/tb_pfs.vhd : ==> simulates OK . added usage comment @@ -99,5 +102,10 @@ c) Simulating tb/vhdl/tb_pft2.vhd * pfb2_unit.vhd = multiple instances of pfb2 + sst, similar as wpfb_unit_dev.vhd for wideband factor wb = 1. - +4) Remove () from filenames + * The () in the files names cause the 'mk' command in Modelsim to fail, 'mk compile' can + handle () in file names, but 'mk' is also needed for efficient compilation. + * Put entity and architecture in same file without () in file name. + * Use _pkg instead of (pkg) in package file name to avoid () in file name. + * Keep only the actually used files in the hdllib.cfg