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

Remove () from file names, because Modelsim mk command cannot make these. Only...

Remove () from file names, because Modelsim mk command cannot make these. Only keep actually used vhd files in hdllib.cfg.
parent 05b728ce
No related branches found
No related tags found
1 merge request!100Removed text for XSub that is now written in Confluence Subband correlator...
Showing
with 2750 additions and 43 deletions
......@@ -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
......
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;
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;
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;
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;
-------------------------------------------------------------------------------
--
-- 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;
......@@ -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
......
-------------------------------------------------------------------------------
--
-- 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;
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;
-------------------------------------------------------------------------------
--
-- 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;
-------------------------------------------------------------------------------
--
-- 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;
-------------------------------------------------------------------------------
--
-- 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;
-------------------------------------------------------------------------------
--
-- 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;
-------------------------------------------------------------------------------
--
-- 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;
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;
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;
......@@ -20,3 +46,171 @@ ENTITY pft_stage IS
rst : IN STD_LOGIC
);
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;
-------------------------------------------------------------------------------
--
-- 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;
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;
-------------------------------------------------------------------------------
--
-- 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;
......@@ -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
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment