├── doc └── blackman-harris coef.jpg ├── hls ├── cordic │ ├── cordic.h │ ├── cordic_test.cpp │ └── cordic.cpp └── windows │ ├── win_function.h │ ├── window_test.cpp │ └── win_function.cpp ├── README.md ├── src ├── int_multNxN_dsp48.vhd ├── win_selector.vhd ├── mults │ ├── mlt35x27_dsp48e2.vhd │ └── mlt35x25_dsp48e1.vhd ├── hamming_win.vhd ├── taylor_sincos.vhd ├── cordic_atan2.vhd ├── bh_win_4term.vhd ├── bh_win_3term.vhd ├── cordic_dds48.vhd ├── cordic_dds.vhd ├── cordic_dds_scaled.vhd ├── bh_win_5term.vhd ├── tb │ └── tb_windows.vhd └── bh_win_7term.vhd ├── math ├── cordic_test.m ├── window_test.m └── cordic_main.m └── cpp └── cordic_sincos.cpp /doc/blackman-harris coef.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hukenovs/blackman_harris_win/HEAD/doc/blackman-harris coef.jpg -------------------------------------------------------------------------------- /hls/cordic/cordic.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | -- 3 | -- Title : CORDIC.h 4 | -- Design : CORDIC HLS 5 | -- Author : Kapitanov 6 | -- Company : insys.ru 7 | -- 8 | ------------------------------------------------------------------------------- 9 | -- 10 | -- Version 1.0 01.10.2018 11 | -- 12 | ------------------------------------------------------------------------------- 13 | -- 14 | -- Description : CORDIC mode for sine and cosine calculation 15 | -- 16 | ------------------------------------------------------------------------------- 17 | ------------------------------------------------------------------------------- 18 | -- 19 | -- GNU GENERAL PUBLIC LICENSE 20 | -- Version 3, 29 June 2007 21 | -- 22 | -- Copyright (c) 2018 Kapitanov Alexander 23 | -- 24 | -- This program is free software: you can redistribute it and/or modify 25 | -- it under the terms of the GNU General Public License as published by 26 | -- the Free Software Foundation, either version 3 of the License, or 27 | -- (at your option) any later version. 28 | -- 29 | -- You should have received a copy of the GNU General Public License 30 | -- along with this program. If not, see . 31 | -- 32 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 33 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 34 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 35 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 36 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 37 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 38 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 39 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 40 | -- 41 | *******************************************************************************/ 42 | 43 | // #include "ap_fixed.h" 44 | #include "ap_int.h" 45 | 46 | /* ---- Constants --- */ 47 | #define NPHASE 10 48 | #define NWIDTH 16 49 | 50 | /* ---- Data types --- */ 51 | typedef ap_uint<2> dbl_t; 52 | 53 | typedef ap_int phi_t; 54 | typedef ap_int dat_t; 55 | typedef ap_int out_t; 56 | 57 | /* ---- Top level function --- */ 58 | void cordic ( 59 | phi_t phi_int, 60 | out_t *out_cos, 61 | out_t *out_sin 62 | ); 63 | 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Blackman-Harris windows 2 | Blackman-Harris Window functions (3-, 4-, 5-, 7-term etc.) from 16 to 64M points based only on LUTs and DSP48s FPGA resources. 3 | Main core for sine and cosine generator - CORDIC. Also for some window functions you can use Taylor series sine generator (1-order Taylor series is a good solution). Project contains Hann, Hamming, Blackman, Flat-top, Nuttal, Blackman–Nuttall, Blackman-Harris w/ N-term windows. 4 | 5 | Please use maximum possible data width for correct calculation. 6 | Note that 1 digital bit equals 6dB of generated signal. For example if you use Blackman-Harris 4-term (-92dB) you should use at least 16 bits plus one sign bit. Total optimal bit width = 17. 7 | 8 | License: GNU GPL 3.0. 9 | 10 | ### Description: 11 | 12 | **Integer** data type and weight constants. 13 | **Code language** - VHDL. 14 | **Vendor**: Xilinx, 6/7-series, Ultrascale, Ultrascale+; 15 | **Target frequency**: up to 400 MHz (tested on Kintex-Ultrascale XCKU040-2). 16 | 17 | ### Info: 18 | 19 | | **Title** | Universal window functions | 20 | | -- | -- | 21 | | **Author** | Alexander Kapitanov | 22 | | **Contact** | | 23 | | **Project lang** | VHDL | 24 | | **Vendor** | Xilinx: 6/7-series, Ultrascale, US+ | 25 | | **Release Date** | 20 Sep 2018 | 26 | | **Version** | 1.0 | 27 | 28 | ### List of components: 29 | 30 | | **Component name** | Function | Side lobe lvl (dB) | 31 | | -- | -- | -- | 32 | | **hamming_win** | Hamming (Hann) | -43 | 33 | | **hamming_win** | Hann | -32 | 34 | | **bh_win_3term** | Blackman | -58 | 35 | | **bh_win_3term** | Blackman-Harris | -71 | 36 | | **bh_win_4term** | Nuttall | -93 | 37 | | **bh_win_4term** | Blackman-Harris | -92 | 38 | | **bh_win_4term** | Blackman-Nuttall | -98 | 39 | | **bh_win_5term** | Flat-top | -69 | 40 | | **bh_win_5term** | Blackman-Harris | -124 | 41 | | **bh_win_7term** | Blackman-Harris 7-term | -180 | 42 | 43 | ### Example: 7-term Blackman-Harris window coefficients 44 | 45 | * _a0 = 0.27105140069342_ 46 | * _a1 = −0.43329793923448_ 47 | * _a2 = 0.21812299954311_ 48 | * _a3 = −0.06592544638803_ 49 | * _a4 = 0.01081174209837_ 50 | * _a5 = −0.00077658482522_ 51 | * _a6 = 0.00001388721735_ 52 | 53 | it gives you up to 180 dB side lobe level. 54 | 55 | For more information see: https://habr.com/users/capitanov/topics/ 56 | -------------------------------------------------------------------------------- /hls/windows/win_function.h: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | -- 3 | -- Title : win_function.h 4 | -- Design : Window functions by HLS 5 | -- Author : Kapitanov Alexander 6 | -- Company : insys.ru 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | ------------------------------------------------------------------------------- 10 | -- 11 | -- Version 1.0 01.10.2018 12 | -- 13 | ------------------------------------------------------------------------------- 14 | -- 15 | -- Description : Some window functions in HLS 16 | -- 17 | ------------------------------------------------------------------------------- 18 | ------------------------------------------------------------------------------- 19 | -- 20 | -- GNU GENERAL PUBLIC LICENSE 21 | -- Version 3, 29 June 2007 22 | -- 23 | -- Copyright (c) 2018 Kapitanov Alexander 24 | -- 25 | -- This program is free software: you can redistribute it and/or modify 26 | -- it under the terms of the GNU General Public License as published by 27 | -- the Free Software Foundation, either version 3 of the License, or 28 | -- (at your option) any later version. 29 | -- 30 | -- You should have received a copy of the GNU General Public License 31 | -- along with this program. If not, see . 32 | -- 33 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 34 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 35 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 36 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 37 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 38 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 39 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 40 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 41 | -- 42 | *******************************************************************************/ 43 | 44 | // #include "ap_fixed.h" 45 | #include "ap_int.h" 46 | 47 | /* ---- Constants --- */ 48 | #define Wintype "Blackman-Harris-5" 49 | 50 | /* ---- Output data width and input phase (counter) width --- */ 51 | #define NPHASE 10 52 | #define NWIDTH 24 53 | 54 | #define NSAMPLES (int)pow(2, NPHASE) 55 | 56 | /* ---- Define data types for c-functions ---- */ 57 | typedef ap_int win_t; 58 | typedef ap_int phi_t; 59 | 60 | typedef ap_int<2*NWIDTH+1> dbl_t; 61 | typedef ap_int<2+NWIDTH> dat_t; 62 | typedef ap_uint<2> duo_t; 63 | 64 | /* ---- Top level function --- */ 65 | void win_function ( 66 | const char win_type, 67 | phi_t i, 68 | win_t* out_win 69 | ); 70 | 71 | -------------------------------------------------------------------------------- /hls/cordic/cordic_test.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | -- 3 | -- Title : cordic_test.c 4 | -- Design : CORDIC Testbench 5 | -- Author : Kapitanov 6 | -- Company : insys.ru 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | ------------------------------------------------------------------------------- 10 | -- 11 | -- Version 1.0 11.09.2018 12 | -- 13 | ------------------------------------------------------------------------------- 14 | -- 15 | -- Description : Simple model for calculating CORDIC sine and cosine 16 | -- 17 | ------------------------------------------------------------------------------- 18 | ------------------------------------------------------------------------------- 19 | -- 20 | -- GNU GENERAL PUBLIC LICENSE 21 | -- Version 3, 29 June 2007 22 | -- 23 | -- Copyright (c) 2018 Kapitanov Alexander 24 | -- 25 | -- This program is free software: you can redistribute it and/or modify 26 | -- it under the terms of the GNU General Public License as published by 27 | -- the Free Software Foundation, either version 3 of the License, or 28 | -- (at your option) any later version. 29 | -- 30 | -- You should have received a copy of the GNU General Public License 31 | -- along with this program. If not, see . 32 | -- 33 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 34 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 35 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 36 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 37 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 38 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 39 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 40 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 41 | -- 42 | *******************************************************************************/ 43 | #include 44 | #include 45 | #include "cordic.h" 46 | 47 | int main () { 48 | 49 | int const NSAMPLES = pow(2.0, NPHASE); 50 | 51 | out_t s, c; 52 | out_t ts, tc; 53 | 54 | printf("Phase = %d, Data = %d, Result: \n", NPHASE, NWIDTH); 55 | 56 | int acc_s = 0x0; 57 | int acc_c = 0x0; 58 | 59 | //int res = out_t.length; 60 | 61 | FILE *fout; 62 | FILE *fgld; 63 | fout = fopen("..\\..\\..\\..\\math\\dout.dat", "w"); 64 | fgld = fopen("..\\..\\..\\..\\math\\golden_dat.dat", "w"); 65 | 66 | int i = 0x0; 67 | for (i = 0; i < NSAMPLES; i++) 68 | { 69 | cordic(i, &c, &s); 70 | ts = round( (pow(2.0, NWIDTH-2)) * sin((2 * i * M_PI) / NSAMPLES) ); 71 | tc = round( (pow(2.0, NWIDTH-2)) * cos((2 * i * M_PI) / NSAMPLES) ); 72 | 73 | acc_s += sqrt(pow(abs(s - ts), 2)); 74 | acc_c += sqrt(pow(abs(c - tc), 2)); 75 | 76 | fprintf(fout, "%d \t %d \n", s, c); 77 | fprintf(fgld, "%d \t %d \n", ts, tc); 78 | 79 | if ((i > NSAMPLES/2 - 8) && (i < NSAMPLES/2 + 8)) 80 | { 81 | printf("%08X %08X \t %08X %08X, \t Err s/c = %d %d\n", s, ts, c, tc, acc_s, acc_c); 82 | } 83 | 84 | } 85 | acc_s /= NSAMPLES; 86 | acc_c /= NSAMPLES; 87 | 88 | fclose(fout); 89 | fclose(fout); 90 | 91 | printf("\n Err_sin = %d, Err_cos = %d \n", acc_s, acc_c); 92 | 93 | if ((acc_s < 10) && (acc_c < 10)) { 94 | printf ("PASS: Data matches the golden output!\n"); 95 | return 0; 96 | } else { 97 | printf ("FAIL: Data DOES NOT match the golden output\n"); 98 | return 1; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/int_multNxN_dsp48.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : int_multiplier_dsp48 4 | -- Design : FFTK 5 | -- Author : Kapitanov 6 | -- Company : 7 | -- 8 | -- Description : Integer multiplier based on DSP48 block 9 | -- 10 | ------------------------------------------------------------------------------- 11 | -- 12 | -- Version 1.0: 11.09.2018 13 | -- 14 | -- Description: Simple multiplier by DSP48 unit 15 | -- 16 | -- Math: 17 | -- 18 | -- Out: In: 19 | -- DO_DAT = DI_DAT * DQ_DAT; 20 | -- 21 | -- Input variables: 22 | -- 1. DTW - DSP48 input width (from 8 to 48): data width 23 | -- 3. XSER - Xilinx series: 24 | -- "NEW" - DSP48E2 (Ultrascale), 25 | -- "OLD" - DSP48E1 (6/7-series). 26 | -- 27 | -- DSP48 data signals: 28 | -- A port - In B data (MSB part), 29 | -- B port - In B data (LSB part), 30 | -- C port - In A data, 31 | -- P port - Output data: P = C +/- A*B 32 | -- 33 | -- IF (DTW < 19) 34 | -- use single DSP48 for mult operation* 35 | -- ELSE IF (DTW > 18) and (DTW < 25) 36 | -- use double DSP48 for mult operation 37 | -- ELSE 38 | -- use triple DSP48 for mult operation (35x35) 39 | -- 40 | -- * - 25 bit for DSP48E1, 27 bit for DSP48E2, 41 | -- 42 | ------------------------------------------------------------------------------- 43 | ------------------------------------------------------------------------------- 44 | -- 45 | -- GNU GENERAL PUBLIC LICENSE 46 | -- Version 3, 29 June 2007 47 | -- 48 | -- Copyright (c) 2018 Kapitanov Alexander 49 | -- 50 | -- This program is free software: you can redistribute it and/or modify 51 | -- it under the terms of the GNU General Public License as published by 52 | -- the Free Software Foundation, either version 3 of the License, or 53 | -- (at your option) any later version. 54 | -- 55 | -- You should have received a copy of the GNU General Public License 56 | -- along with this program. If not, see . 57 | -- 58 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 59 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 60 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 61 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 62 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 63 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 64 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 65 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 66 | -- 67 | ------------------------------------------------------------------------------- 68 | ------------------------------------------------------------------------------- 69 | 70 | library ieee; 71 | use ieee.std_logic_1164.all; 72 | use ieee.std_logic_signed.all; 73 | use ieee.std_logic_arith.all; 74 | 75 | entity int_multNxN_dsp48 is 76 | generic ( 77 | DTW : natural:=24 --! Input data width 78 | ); 79 | port ( 80 | DAT_A : in std_logic_vector(DTW-1 downto 0); --! A port 81 | DAT_B : in std_logic_vector(DTW-1 downto 0); --! B port 82 | DAT_Q : out std_logic_vector(2*DTW-1 downto 0); --! Output data: Q = A * B 83 | RST : in std_logic; --! Global reset 84 | CLK : in std_logic --! Math clock 85 | ); 86 | end int_multNxN_dsp48; 87 | 88 | architecture int_multNxN_dsp48 of int_multNxN_dsp48 is 89 | 90 | signal sig_a, sig_b : std_logic_vector(DTW-1 downto 0); 91 | 92 | attribute USE_DSP : string; 93 | attribute USE_DSP of DAT_Q : signal is "YES"; 94 | 95 | begin 96 | 97 | pr_psp: process(clk) is 98 | begin 99 | if (rising_edge(clk)) then 100 | sig_a <= DAT_A; -- Make Input delay A port 101 | sig_b <= DAT_B; -- Make Input delay B port 102 | if (rst = '1') then 103 | DAT_Q <= (others=>'0'); 104 | else 105 | DAT_Q <= SIGNED(sig_a) * SIGNED(sig_b); 106 | end if; 107 | end if; 108 | end process; 109 | 110 | end int_multNxN_dsp48; -------------------------------------------------------------------------------- /math/cordic_test.m: -------------------------------------------------------------------------------- 1 | clear all; close all; 2 | clc 3 | 4 | n = 12; % number of iterations 5 | N = 14; 6 | 7 | theta = 0; % initial angle 8 | 9 | %NOUT = 16; 10 | %NPHI = 10; 11 | %Angle(:,1) = round(atan(2.^(-(0:(NOUT-1)))) .* (2^(NPHI-0)/pi)); 12 | % 13 | %Angle_Int = int32(Angle); 14 | %Angle_Hex = dec2hex(Angle_Int); 15 | %disp(Angle_Hex); 16 | 17 | % Run CORDIC algorith in rotation mode 18 | function [x_out, y_out, angle] = cordic(theta, n, N) 19 | z = theta*8; 20 | rot = 0; % Indicates if a rotation occured. 0: no rotation 1: rotation by -pi 2: rotation by +pi 21 | 22 | if (z > 2^(N-0)/2) && (z <= 2^(N-0)) 23 | z = z - 2^(N-0); 24 | rot = 1; 25 | end 26 | if (z < -2^(N-0)/2) && (z >= -2^(N-0)) 27 | z = z + 2^(N-0); 28 | rot = 1; 29 | end 30 | 31 | 32 | % Set x to 1 and y to 0 33 | x = 2^(n-1); 34 | y = 0; 35 | 36 | 37 | for w = 0:n 38 | % z 39 | 40 | if z < 0 41 | x_next = x + round(y * 2^-w); 42 | y_next = y - round(x * 2^-w); 43 | z = z + round((2^(N)*atan(2^-w)/pi)); 44 | else 45 | x_next = x - round(y * 2^-w); 46 | y_next = y + round(x * 2^-w); 47 | z = z - round((2^(N)*atan(2^-w)/pi)); 48 | end 49 | x = x_next; 50 | y = y_next; 51 | end 52 | 53 | if rot == 0 54 | x_out = x; 55 | y_out = y; 56 | else 57 | x_out = -x; 58 | y_out = -y; 59 | 60 | end 61 | 62 | x_out = round(x_out / 1.6467); 63 | y_out = round(y_out / 1.6467); 64 | 65 | angle = z; 66 | end 67 | 68 | 69 | for w = 0:n 70 | Zz(w+1,1) = (2^(N-3)*atan(2^-w)/pi); 71 | end 72 | 73 | for w = 0:n 74 | Zx(w+1,1) = round((2^(N) * atan(2^-w)/pi)); 75 | end 76 | Angle_Int = int32(Zx); 77 | Angle_Hex2 = dec2hex(Angle_Int); 78 | 79 | 80 | q = 1; 81 | %for theta = -pi : pi/2^(N-3) :pi-pi/2^(N-3) 82 | for theta = -2^(N-3) : 1 : 2^(N-3)-1 83 | [x_out(q), y_out(q), angle(q)] = cordic(theta, n, N); 84 | q = q + 1; 85 | end 86 | 87 | th(:, 1) = (0 : 2^(N-2)-1); 88 | Id_sin(:,1) = round(2^(n-1) * sin(th(:,1) .* (2*pi) ./ (2^N/4) ) ); 89 | Id_cos(:,1) = round(2^(n-1) * cos(th(:,1) .* (2*pi) ./ (2^N/4) ) ); 90 | 91 | Id_cmps = abs(Id_sin + y_out'); 92 | Id_cmpc = abs(Id_cos + x_out'); 93 | 94 | 95 | %x_new = x_out + 1/2^(n) * randn(size(x_out)); 96 | %y_new = y_out + 1/2^(n) * randn(size(y_out)); 97 | X_new = x_out; 98 | Y_new = y_out; 99 | max(Y_new) 100 | %Win = blackmanharris(length(x_out)); 101 | %Win = kaiser(length(x_out), 9); 102 | %Dat_X = filter2(Win, y_out); 103 | %Dat_Y = filter2(Win, x_out); 104 | Dat_X = X_new + 1/(2^(n)) * randn(size(y_out)); 105 | Dat_Y = Y_new + 1/(2^(n)) * randn(size(y_out)); 106 | 107 | Spec_Re = fft(Dat_X, length(Dat_X)); 108 | Spec_Im = fft(Dat_Y, length(Dat_X)); 109 | Spec_Re = Spec_Re .* conj(Spec_Re); 110 | Spec_Im = Spec_Im .* conj(Spec_Im); 111 | 112 | Spec_Re = fftshift(Spec_Re); 113 | Spec_Im = fftshift(Spec_Im); 114 | 115 | Spec_Re = Spec_Re / max(Spec_Re); 116 | Spec_Im = Spec_Im / max(Spec_Im); 117 | 118 | Slog_Re = 10*log10(Spec_Re); 119 | Slog_Im = 10*log10(Spec_Im); 120 | 121 | figure(1) % Plot loaded data in Freq Domain 122 | subplot(3,1,1) 123 | plot(X_new, '-', 'LineWidth', 1, 'Color',[1 0 0]) 124 | grid on; hold on; axis tight; 125 | plot(Y_new, '-', 'LineWidth', 1, 'Color',[0 0 1]) 126 | grid on; hold on; axis tight; 127 | title(['CORDIC SINE / COSINE:']) 128 | 129 | subplot(3,1,2) 130 | plot(Slog_Re, '-', 'LineWidth', 1, 'Color',[1 0 0]) 131 | grid on; hold on; axis ([0, length(Slog_Re), -160, 0]); 132 | plot(Slog_Im, '-', 'LineWidth', 1, 'Color',[0 0 1]) 133 | grid on; hold on; axis ([0, length(Slog_Re), -160, 0]); 134 | title(['REAL / IMAG SPECTRUM:']) 135 | 136 | subplot(3,1,3) 137 | plot(Id_cmps, '-', 'LineWidth', 1, 'Color',[1 0 0]) 138 | grid on; hold on; axis ([0, length(Id_cmps), -1, 7]); 139 | plot(Id_cmpc, '-', 'LineWidth', 1, 'Color',[0 0 1]) 140 | grid on; hold on; axis ([0, length(Id_cmps), -1, 7]); 141 | title(['ABS SIGNAL DIFFERENCE:']) -------------------------------------------------------------------------------- /math/window_test.m: -------------------------------------------------------------------------------- 1 | %% ----------------------------------------------------------------------- 2 | % 3 | % Title : window_functions.m 4 | % Author : Alexander Kapitanov 5 | % Company : Insys 6 | % E-mail : sallador@bk.ru 7 | % Version : 1.0 8 | % 9 | %------------------------------------------------------------------------- 10 | % 11 | % Description : 12 | % Top level for testing Window functions from HLS 13 | % 14 | % Parameter: WINTYPE - 15 | % 2 - Hamming or Hann 16 | % 3 - Blackman_Harris 3-order 17 | % 4 - Blackman_Harris 4-order, Nuttall, Blackman-Nuttall, 18 | % 5 - Blackman_Harris 5-order, Flat-top 19 | % 7 - Blackman_Harris 7-order 20 | % 21 | % 22 | % 23 | %------------------------------------------------------------------------- 24 | % 25 | % Version : 1.0 26 | % Date : 2018.10.10 27 | % 28 | %------------------------------------------------------------------------- 29 | 30 | % Preparing to work 31 | close all; 32 | clear all; 33 | 34 | set(0, 'DefaultAxesFontSize', 14, 'DefaultAxesFontName', 'Times New Roman'); 35 | set(0, 'DefaultTextFontSize', 14, 'DefaultTextFontName', 'Times New Roman'); 36 | 37 | WINTYPE = 5; 38 | DATA_WIDTH = 24; 39 | 40 | % Load output data from Vivado HLS 41 | DT_CRD = load ("dout.dat"); 42 | DT_TST = load ("golden_dat.dat"); 43 | 44 | X_new(1,:) = DT_CRD(:,1); 45 | X_gld(1,:) = DT_TST(:,1); 46 | 47 | % Find length of vector 48 | N = length(X_new); 49 | 50 | 51 | a0 = 0; a1 = 0; a2 = 0; a3 = 0; a4 = 0; a5 = 0; a6 = 0; 52 | 53 | % -------- 2-order -------- 54 | % > Hann: 55 | % a0 = 0.5; 56 | % a1 = 0.5; 57 | % 58 | % -------- 2-order -------- 59 | % > Hamming: 60 | % a0 = 0.5434783; 61 | % a1 = 1.0 - 0.5434783; 62 | % 63 | % -------- 3-order -------- 64 | % > Blackman-Harris: 65 | % a0 = 0.21; 66 | % a1 = 0.25; 67 | % a2 = 0.04; 68 | % 69 | % -------- 4-order -------- 70 | % > Blackman-Harris: 71 | % a0 = 0.35875; 72 | % a1 = 0.48829; 73 | % a2 = 0.14128; 74 | % a3 = 0.01168; 75 | % 76 | % > Nuttall: 77 | % a0 = 0.355768; 78 | % a1 = 0.487396; 79 | % a2 = 0.144323; 80 | % a3 = 0.012604; 81 | % 82 | % > Blackman-Nuttall: 83 | % a0 = 0.3635819; 84 | % a1 = 0.4891775; 85 | % a2 = 0.1365995; 86 | % a3 = 0.0106411; 87 | % 88 | % -------- 5-order -------- 89 | % > Blackman-Harris: 90 | a0 = 0.3232153788877343; 91 | a1 = 0.4714921439576260; 92 | a2 = 0.1755341299601972; 93 | a3 = 0.0284969901061499; 94 | a4 = 0.0012613570882927; 95 | 96 | % > Flat-top (1): 97 | % a0 = 0.50000; 98 | % a1 = 0.98500; 99 | % a2 = 0.64500; 100 | % a3 = 0.19400; 101 | % a4 = 0.01500; 102 | % 103 | % > Flat-top (2): 104 | % a0 = 0.215578950; 105 | % a1 = 0.416631580; 106 | % a2 = 0.277263158; 107 | % a3 = 0.083578947; 108 | % a4 = 0.006947368; 109 | % 110 | % -------- 7-order -------- 111 | % > Blackman-Harris: 112 | % a0 = 0.271220360585039; 113 | % a1 = 0.433444612327442; 114 | % a2 = 0.218004122892930; 115 | % a3 = 0.065785343295606; 116 | % a4 = 0.010761867305342; 117 | % a5 = 0.000770012710581; 118 | % a6 = 0.000013680883060; 119 | % 120 | % Create ideal window function array 121 | sh_val = 1; 122 | for i=0:N-1 123 | if (WINTYPE == 2) 124 | Winf(i+1) = a0 - a1 * cos((2 * i * pi)/N); 125 | elseif (WINTYPE == 3) 126 | Winf(i+1) = a0 - a1 * cos((2 * i * pi)/N) + a2 * cos((2 * 2 * i * pi)/N); 127 | elseif (WINTYPE == 4) 128 | Winf(i+1) = a0 - a1 * cos((2 * i * pi)/N) + a2 * cos((2 * 2 * i * pi)/N) - a3 * cos((3 * 2 * i * pi)/N); 129 | elseif (WINTYPE == 5) 130 | Winf(i+1) = a0 - a1 * cos((2 * i * pi)/N) + a2 * cos((2 * 2 * i * pi)/N) - a3 * cos((3 * 2 * i * pi)/N) + a4 * cos((4 * 2 * i * pi)/N); 131 | sh_val = 2; 132 | elseif (WINTYPE == 7) 133 | Winf(i+1) = a0 - a1 * cos((2 * i * pi)/N) + a2 * cos((2 * 2 * i * pi)/N) - a3 * cos((3 * 2 * i * pi)/N) + a4 * cos((4 * 2 * i * pi)/N) - a5 * cos((5 * 2 * i * pi)/N) + a6 * cos((6 * 2 * i * pi)/N); 134 | sh_val = 2; 135 | else 136 | Winf(i+1) = 0; 137 | endif 138 | endfor 139 | Winf = round((2^(DATA_WIDTH-sh_val)-1) * Winf); 140 | 141 | % Plot results 142 | figure(1) 143 | subplot(3,1,1) 144 | plot(X_new, '-', 'LineWidth', 1, 'Color',[1 0 0]) 145 | grid on; hold on; axis tight; 146 | plot(X_gld, '-', 'LineWidth', 1, 'Color',[0 0 1]) 147 | grid on; hold on; axis tight; 148 | title(["Window function"]) 149 | legend("HLS Win", "Golden", "location", "northeast"); 150 | 151 | subplot(3,1,2) 152 | plot(X_new-Winf, '-.', 'LineWidth', 2, 'Color',[1 0 0]) 153 | grid on; hold on; axis tight; 154 | title(["Compare HLS"]) 155 | legend("Diff HLS - Matlab", "location", "southeast"); 156 | 157 | subplot(3,1,3) 158 | plot(X_gld-Winf, '--', 'LineWidth', 2, 'Color',[0 1 0]) 159 | grid on; hold on; axis ([0 N -1 1]); 160 | title(['Compare Golden']) 161 | legend("Diff Golden - Matlab", "location", "southeast"); -------------------------------------------------------------------------------- /hls/cordic/cordic.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | -- 3 | -- Title : CORDIC.c 4 | -- Design : CORDIC HLS 5 | -- Author : Kapitanov 6 | -- Company : insys.ru 7 | -- 8 | ------------------------------------------------------------------------------- 9 | -- 10 | -- Version 1.0 01.10.2018 11 | -- 12 | ------------------------------------------------------------------------------- 13 | -- 14 | -- Description : CORDIC mode for sine and cosine calculation 15 | -- 16 | ------------------------------------------------------------------------------- 17 | ------------------------------------------------------------------------------- 18 | -- 19 | -- GNU GENERAL PUBLIC LICENSE 20 | -- Version 3, 29 June 2007 21 | -- 22 | -- Copyright (c) 2018 Kapitanov Alexander 23 | -- 24 | -- This program is free software: you can redistribute it and/or modify 25 | -- it under the terms of the GNU General Public License as published by 26 | -- the Free Software Foundation, either version 3 of the License, or 27 | -- (at your option) any later version. 28 | -- 29 | -- You should have received a copy of the GNU General Public License 30 | -- along with this program. If not, see . 31 | -- 32 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 33 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 34 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 35 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 36 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 37 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 38 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 39 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 40 | -- 41 | *******************************************************************************/ 42 | #include 43 | #include "cordic.h" 44 | 45 | void cordic ( 46 | phi_t phi_int, 47 | out_t *out_cos, 48 | out_t *out_sin 49 | ) 50 | { 51 | #pragma HLS INTERFACE port=phi_int 52 | #pragma HLS INTERFACE register port=out_cos 53 | #pragma HLS INTERFACE register port=out_sin 54 | #pragma HLS PIPELINE 55 | 56 | // Create Look-up table array // 57 | long long lut_table [48] = { 58 | 0x400000000000, 0x25C80A3B3BE6, 0x13F670B6BDC7, 0x0A2223A83BBB, 59 | 0x05161A861CB1, 0x028BAFC2B209, 0x0145EC3CB850, 0x00A2F8AA23A9, 60 | 0x00517CA68DA2, 0x0028BE5D7661, 0x00145F300123, 0x000A2F982950, 61 | 0x000517CC19C0, 0x00028BE60D83, 0x000145F306D6, 0x0000A2F9836D, 62 | 0x0000517CC1B7, 0x000028BE60DC, 0x0000145F306E, 0x00000A2F9837, 63 | 0x00000517CC1B, 0x0000028BE60E, 0x00000145F307, 0x000000A2F983, 64 | 0x000000517CC2, 0x00000028BE61, 0x000000145F30, 0x0000000A2F98, 65 | 0x0000000517CC, 0x000000028BE6, 0x0000000145F3, 0x00000000A2FA, 66 | 0x00000000517D, 0x0000000028BE, 0x00000000145F, 0x000000000A30, 67 | 0x000000000518, 0x00000000028C, 0x000000000146, 0x0000000000A3, 68 | 0x000000000051, 0x000000000029, 0x000000000014, 0x00000000000A, 69 | 0x000000000005, 0x000000000003, 0x000000000001, 0x000000000000 70 | }; 71 | 72 | static dat_t lut_angle[NWIDTH - 1]; 73 | 74 | int i; 75 | for (i = 0; i < NWIDTH - 1; i++) { 76 | lut_angle[i] = (lut_table[i] >> (48 - NWIDTH - 2 + 1) & 0xFFFFFFFFFF); 77 | // lut_angle[i] = (dat_t)round(atan(pow(2.0, -i)) * pow(2.0, NWIDTH+1) / M_PI); 78 | } 79 | 80 | // Set data output gain level // 81 | static const dat_t GAIN48 = (0x26DD3B6A10D8 >> (48 - NWIDTH - 2)); 82 | 83 | // Calculate quadrant and phase // 84 | dbl_t quadrant = phi_int >> (NPHASE - 2); 85 | 86 | dat_t init_t = phi_int & (~(0x3 << (NPHASE - 2))); 87 | 88 | dat_t init_z; 89 | if ((NPHASE-1) < NWIDTH) { 90 | init_z = init_t << (NWIDTH - NPHASE + 2); 91 | } 92 | else { 93 | init_z = (init_t >> (NPHASE - NWIDTH)) << 2; 94 | } 95 | 96 | // Create array for parallel calculation // 97 | dat_t x[NWIDTH + 1]; 98 | dat_t y[NWIDTH + 1]; 99 | dat_t z[NWIDTH + 1]; 100 | 101 | // Initial values // 102 | x[0] = GAIN48; 103 | y[0] = 0x0; 104 | z[0] = init_z; 105 | 106 | // Unrolled loop // 107 | int k; 108 | stg: for (k = 0; k < NWIDTH; k++) { 109 | #pragma HLS UNROLL 110 | 111 | if (z[k] < 0) { 112 | x[k+1] = x[k] + (y[k] >> k); 113 | y[k+1] = y[k] - (x[k] >> k); 114 | 115 | z[k+1] = z[k] + lut_angle[k]; 116 | } else { 117 | x[k+1] = x[k] - (y[k] >> k); 118 | y[k+1] = y[k] + (x[k] >> k); 119 | 120 | z[k+1] = z[k] - lut_angle[k]; 121 | } 122 | 123 | } 124 | 125 | // Shift output data by 2 // 126 | dat_t out_c = (x[NWIDTH] >> 2); 127 | dat_t out_s = (y[NWIDTH] >> 2); 128 | 129 | dat_t dat_c; 130 | dat_t dat_s; 131 | 132 | // Check quadrant and find output sign of data // 133 | if (quadrant == 0x0) { 134 | dat_s = out_s; 135 | dat_c = out_c; 136 | } 137 | else if (quadrant == 0x1) { 138 | dat_s = out_c; 139 | dat_c = ~(out_s) + 1; 140 | } 141 | else if (quadrant == 0x2) { 142 | dat_s = ~(out_s) + 1; 143 | dat_c = ~(out_c) + 1; 144 | } 145 | else { 146 | dat_s = ~(out_c) + 1; 147 | dat_c = out_s; 148 | } 149 | 150 | // Get output values // 151 | *out_cos = (dat_c); 152 | *out_sin = (dat_s); 153 | 154 | } 155 | -------------------------------------------------------------------------------- /cpp/cordic_sincos.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define _CRT_SECURE_NO_WARNINGS 5 | #define _CRT_SECURE_NO_DEPRECATE 6 | 7 | #define PHASE_WIDTH 14 8 | #define DATA_WIDTH 12 9 | 10 | void cordic(int theta, long long *lut, int *s, int *c) 11 | { 12 | int PRECISION = 1; 13 | long long lut_angle[DATA_WIDTH - 1]; 14 | 15 | for (int i = 0; i < DATA_WIDTH - 1; i++) 16 | { 17 | lut_angle[i] = ((lut[i] >> (48 - DATA_WIDTH - PRECISION) & 0xFFFFFFFFFFFF)); 18 | } 19 | 20 | // Gain for output data ~ 1.64676025812107... 21 | static const long long GAIN48 = 0x26DD3B6A10D8; 22 | int long long GAIN32 = GAIN48 >> (48 - DATA_WIDTH - 2); 23 | 24 | // Find quadrant 25 | int quadrant = theta >> (PHASE_WIDTH - 2); 26 | 27 | long long init_t = theta & (~(0x3 << (PHASE_WIDTH - 2))); 28 | 29 | // Find actual phase 30 | long long init_z = 0x0; 31 | if (PHASE_WIDTH-1 < DATA_WIDTH) { 32 | init_z = init_t << (DATA_WIDTH - PHASE_WIDTH + PRECISION); 33 | } 34 | else { 35 | init_z = (init_t >> (PHASE_WIDTH - DATA_WIDTH)) << PRECISION; 36 | } 37 | 38 | // Create array for parallel calculation 39 | long long x[DATA_WIDTH + 1]; 40 | long long y[DATA_WIDTH + 1]; 41 | long long z[DATA_WIDTH + 1]; 42 | 43 | x[0] = GAIN32; 44 | y[0] = 0x0; 45 | z[0] = init_z; 46 | 47 | // Core of the CORDIC algorithm 48 | int k; 49 | for (k = 0; k < DATA_WIDTH; k++) { 50 | 51 | if (z[k] < 0) { 52 | x[k+1] = x[k] + (y[k] >> k); 53 | y[k+1] = y[k] - (x[k] >> k); 54 | } else { 55 | x[k+1] = x[k] - (y[k] >> k); 56 | y[k+1] = y[k] + (x[k] >> k); 57 | } 58 | if (z[k] < 0) { 59 | z[k+1] = z[k] + lut_angle[k]; 60 | } else { 61 | z[k+1] = z[k] - lut_angle[k]; 62 | } 63 | } 64 | long long out_c = (x[DATA_WIDTH] >> 2); 65 | long long out_s = (y[DATA_WIDTH] >> 2); 66 | 67 | long long dat_c = 0x0; 68 | long long dat_s = 0x0; 69 | 70 | if (quadrant == 0x0) { 71 | dat_s = out_s; 72 | dat_c = out_c; 73 | 74 | } 75 | else if (quadrant == 0x1) { 76 | dat_s = out_c; 77 | dat_c = ~out_s; 78 | } 79 | else if (quadrant == 0x2) { 80 | dat_s = ~out_s; 81 | dat_c = ~out_c; 82 | } 83 | else { 84 | dat_s = ~out_c; 85 | dat_c = out_s; 86 | } 87 | 88 | 89 | *c = int(dat_c); 90 | *s = int(dat_s); 91 | 92 | } 93 | 94 | int main(int argc, char **argv) 95 | { 96 | // Create 48-bit angle array: [ATAN(2^-i) * (2^32/PI)] 97 | long long lut_table [48] = { 98 | 0x200000000000, 0x12E4051D9DF3, 0x09FB385B5EE4, 0x051111D41DDE, 99 | 0x028B0D430E59, 0x0145D7E15904, 0x00A2F61E5C28, 0x00517C5511D4, 100 | 0x0028BE5346D1, 0x00145F2EBB31, 0x000A2F980092, 0x000517CC14A8, 101 | 0x00028BE60CE0, 0x000145F306C1, 0x0000A2F9836B, 0x0000517CC1B7, 102 | 0x000028BE60DC, 0x0000145F306E, 0x00000A2F9837, 0x00000517CC1B, 103 | 0x0000028BE60E, 0x00000145F307, 0x000000A2F983, 0x000000517CC2, 104 | 0x00000028BE61, 0x000000145F30, 0x0000000A2F98, 0x0000000517CC, 105 | 0x000000028BE6, 0x0000000145F3, 0x00000000A2FA, 0x00000000517D, 106 | 0x0000000028BE, 0x00000000145F, 0x000000000A30, 0x000000000518, 107 | 0x00000000028C, 0x000000000146, 0x0000000000A3, 0x000000000051, 108 | 0x000000000029, 0x000000000014, 0x00000000000A, 0x000000000005, 109 | 0x000000000003, 0x000000000001, 0x000000000001, 0x000000000000 110 | }; 111 | 112 | unsigned int lut_msb = 0x0; 113 | unsigned int lut_lsb = 0x0; 114 | 115 | // Printf look-up table array 116 | printf("Look-up table array: LUT_ROM := [\n"); 117 | for (int i = 0; i < 48; i++) 118 | { 119 | lut_lsb = (lut_table[i] & 0xFFFFFFFF); 120 | lut_msb = ((lut_table[i] >> 32) & 0xFFFFFFFF); 121 | printf(" 0x%04X%08X", lut_msb, lut_lsb); 122 | if (((i + 2) % 4) == 1) { 123 | printf("\n"); 124 | } 125 | } 126 | printf("];\n\n"); 127 | 128 | int s, c; 129 | 130 | FILE* FT; 131 | errno_t err = fopen_s(&FT, "..\\math\\coe.dat", "wt"); 132 | 133 | printf("Phase = %d, Data = %d\n", PHASE_WIDTH, DATA_WIDTH); 134 | 135 | for (int i = 0; i < pow(2.0, PHASE_WIDTH); i++) 136 | { 137 | cordic(i, lut_table, &s, &c); 138 | fprintf(FT, "%d %d\n", s, c); 139 | if (i < 50) { 140 | printf("%08X %08X %d % d\n", s, c, s, c); 141 | } 142 | } 143 | printf("\n\n"); 144 | fclose(FT); 145 | 146 | /* Use this m-script for testing CORDIC algorithm 147 | clear all; 148 | close all; 149 | 150 | DT_CRD = load ("coe.dat"); 151 | 152 | X_new(:,1) = DT_CRD(:,1); 153 | Y_new(:,1) = DT_CRD(:,2); 154 | 155 | Spec_Re = fft(Y_new + 1e-12 * randn(size(Y_new))); 156 | Spec_Im = fft(X_new + 1e-12 * randn(size(X_new))); 157 | Spec_Re = Spec_Re .* conj(Spec_Re); 158 | Spec_Im = Spec_Im .* conj(Spec_Im); 159 | 160 | Spec_Re = fftshift(Spec_Re); 161 | Spec_Im = fftshift(Spec_Im); 162 | 163 | Sabs_Re = Spec_Re / max(Spec_Re); 164 | Sabs_Im = Spec_Im / max(Spec_Im); 165 | 166 | Sidl_Re = 10*log10(Sabs_Re); 167 | Sidl_Im = 10*log10(Sabs_Im); 168 | 169 | figure(1) % Plot loaded data in Time Domain 170 | subplot(2,1,1) 171 | plot(X_new, '-', 'LineWidth', 1, 'Color',[1 0 0]) 172 | grid on; hold on; axis tight; 173 | plot(Y_new, '-', 'LineWidth', 1, 'Color',[0 0 1]) 174 | grid on; hold on; axis tight; 175 | title(['CORDIC SINE / COSINE:']) 176 | 177 | subplot(2,1,2) 178 | plot(Sidl_Re, '-', 'LineWidth', 1, 'Color',[1 0 0]) 179 | grid on; hold on; axis ([0, length(Sidl_Re), -160, 0]); 180 | plot(Sidl_Im, '-', 'LineWidth', 1, 'Color',[0 0 1]) 181 | grid on; hold on; axis ([0, length(Sidl_Re), -160, 0]); 182 | */ 183 | 184 | return 0; 185 | 186 | } -------------------------------------------------------------------------------- /math/cordic_main.m: -------------------------------------------------------------------------------- 1 | %% -------------------------------------------------------------------------- %% 2 | % 3 | % Title : cordic_main.m 4 | % Author : Alexander Kapitanov 5 | % Company : Insys 6 | % E-mail : sallador@bk.ru 7 | % Version : 1.0 8 | % 9 | set(0, 'DefaultAxesFontSize', 14, 'DefaultAxesFontName', 'Times New Roman'); 10 | set(0, 'DefaultTextFontSize', 14, 'DefaultTextFontName', 'Times New Roman'); 11 | 12 | clear all; 13 | close all; 14 | 15 | % Set: Phase vector size (phase - is a bit-vector) 16 | NPHI = 11; 17 | % Set: Gain of signal (output width in HDL) 18 | NOUT = 9; 19 | %GAIN = 2^(NOUT-1)/1.6467; 20 | GAIN = 2^(NOUT-1)/1.6467; 21 | 22 | 23 | 24 | % ---- Calculate angles and create Look up table for ATAN -------------------- % 25 | Angle(:,1) = round( atan(2.^(-(0:NOUT-1))) .* (2^(NOUT)/pi ) ); 26 | Angle(length(Angle),1) = 0; 27 | 28 | Angle_Int = int32(Angle); 29 | Angle_Hex = dec2hex(Angle_Int); 30 | 31 | Magn = prod(sqrt(1+2.^(-2*(0:(NOUT))))); 32 | % ---- Calculate quadrant from input phase ----------------------------------- % 33 | function quad_out = find_quad(Phase, PHI, NDAT) 34 | z_ret = 0; r_ret = 0; 35 | 36 | if ((Phase > 0) && (Phase < 2^(PHI-1)/2)) % MSBs: "00" in HDL 37 | z_ret = Phase; 38 | elseif ((Phase > 2^(PHI-1)/2-1) && (Phase < 2^(PHI-1))) % MSBs: "01" in HDL 39 | z_ret = Phase - 2^(PHI-1); 40 | r_ret = 1; 41 | elseif ((Phase > -2^(PHI-1)-1) && (Phase < -2^(PHI-1)/2)) % MSBs: "11" in HDL 42 | z_ret = Phase + 2^(PHI-1); 43 | r_ret = 1; 44 | else % MSBs: "10" in HDL 45 | z_ret = Phase; 46 | endif 47 | z_ret = round(z_ret * 2^(NDAT-PHI+1)); 48 | quad_out(1,1) = int32(z_ret); 49 | quad_out(1,2) = int32(r_ret); 50 | end 51 | 52 | % ---- Calculate sin / cos values -------------------------------------------- % 53 | function harmonic_out = find_wave(Data, Rot, LutAtan, Len, Phi) 54 | % sig_ret = double(Data); 55 | sig_ret = Data; 56 | cos_ret = 2^(Len+1); 57 | sin_ret = 0; 58 | 59 | for ii = 0:Len-1 60 | if (sig_ret < 0) 61 | sig_ret = sig_ret + LutAtan(ii+1); 62 | cos_new = cos_ret + floor(sin_ret * 2^(-ii)); 63 | sin_new = sin_ret - floor(cos_ret * 2^(-ii)); 64 | % sig_ret = sig_ret + 2^(Phi-3) * atan(2^-ii) / pi; 65 | else 66 | sig_ret = sig_ret - LutAtan(ii+1); 67 | cos_new = cos_ret - floor(sin_ret * 2^(-ii)); 68 | sin_new = sin_ret + floor(cos_ret * 2^(-ii)); 69 | % sig_ret = sig_ret - 2^(Phi-3) * atan(2^-ii) / pi; 70 | endif 71 | cos_ret = cos_new; 72 | sin_ret = sin_new; 73 | endfor 74 | 75 | if (Rot == 1) 76 | cos_ret = -cos_ret; 77 | sin_ret = -sin_ret; 78 | end 79 | 80 | 81 | harmonic_out(1,1) = round(cos_ret / 1.6467 / 4 / 1); 82 | harmonic_out(1,2) = round(sin_ret / 1.6467 / 4 / 1); 83 | end 84 | 85 | % ---- Create phase vector and calculate sin / cos --------------------------- % 86 | 87 | phi_ii = -2^(NPHI-1) : 1 : 2^(NPHI-1)-1; 88 | phi_1 = -2^(NPHI-1) : 1 : -1; 89 | phi_2 = 0 : 1 : 2^(NPHI-1)-1; 90 | 91 | phi_ii = [phi_2 phi_1]; 92 | 93 | for ii = 1:length(phi_ii) 94 | phi_out(ii,:) = find_quad(phi_ii(1,ii), NPHI, NOUT); 95 | sig_out(ii,:) = find_wave(phi_out(ii,1), phi_out(ii,2), Angle_Int, NOUT, NPHI); 96 | endfor 97 | 98 | %PhX = phi_out(:,1); 99 | %PhY = phi_out(:,2); 100 | PhZ = phi_out(:,1); 101 | ReSig = sig_out(:,1); 102 | ImSig = sig_out(:,2); 103 | 104 | max(abs(ReSig)) 105 | 106 | 107 | 108 | % ---- Calculate spectrum for CORDIC sine / cosine --------------------------- % 109 | %Spec_Re = fft(ReSig, 2^(NPHI)); 110 | %Spec_Im = fft(ImSig, 2^(NPHI)); 111 | Spec_Re = fft(ReSig + 0.1 * randn(size(ReSig)), length(phi_ii)); 112 | Spec_Im = fft(ImSig + 0.1 * randn(size(ImSig)), length(phi_ii)); 113 | Spec_Re = Spec_Re .* conj(Spec_Re); 114 | Spec_Im = Spec_Im .* conj(Spec_Im); 115 | 116 | Spec_Re = fftshift(Spec_Re); 117 | Spec_Im = fftshift(Spec_Im); 118 | 119 | Sabs_Re = Spec_Re / max(Spec_Re); 120 | Sabs_Im = Spec_Im / max(Spec_Im); 121 | 122 | Slog_Re = 10*log10(Sabs_Re); 123 | Slog_Im = 10*log10(Sabs_Im); 124 | 125 | 126 | % ---- Calculate ideal values of sine / cosine ------------------------------- % 127 | Id_sin(:,1) = round(2^(NOUT-1) * sin( ( 0: 2^NPHI-1 ) .* 2*pi/(2^NPHI))); 128 | Id_cos(:,1) = round(2^(NOUT-1) * cos( ( 0: 2^NPHI-1 ) .* 2*pi/(2^NPHI))); 129 | 130 | Id_sin(:,1) = Id_sin + 1 * randn(size(Id_sin)); 131 | Id_cos(:,1) = Id_cos + 1 * randn(size(Id_cos)); 132 | 133 | %Win = kaiser(length(Id_sin), 19); 134 | %Dat_X = filter2(Win, Id_sin); 135 | %Dat_Y = filter2(Win, Id_cos); 136 | 137 | Spec_Re = fft(Id_cos, length(phi_ii)); 138 | Spec_Im = fft(Id_sin, length(phi_ii)); 139 | Spec_Re = Spec_Re .* conj(Spec_Re); 140 | Spec_Im = Spec_Im .* conj(Spec_Im); 141 | 142 | Spec_Re = fftshift(Spec_Re); 143 | Spec_Im = fftshift(Spec_Im); 144 | 145 | Sabs_Re = Spec_Re / max(Spec_Re); 146 | Sabs_Im = Spec_Im / max(Spec_Im); 147 | 148 | Sidl_Re = 10*log10(Sabs_Re); 149 | Sidl_Im = 10*log10(Sabs_Im); 150 | 151 | % ---- Plot figures ---------------------------------------------------------- % 152 | figure(1) % Plot loaded data in Freq Domain 153 | % subplot(1,1,1) 154 | % plot(ReSig, '-', 'LineWidth', 1, 'Color',[1 0 0]) 155 | % grid on; hold on; axis ([450, 580, 2010, 2050]); 156 | % plot(ImSig, '-', 'LineWidth', 1, 'Color',[0 0 1]) 157 | % grid on; hold on; axis ([450, 580, 2010, 2050]); 158 | % title(['CORDIC SINE / COSINE:']) 159 | % 160 | subplot(4,1,1) 161 | plot(ReSig, '-', 'LineWidth', 1, 'Color',[1 0 0]) 162 | grid on; hold on; axis tight; 163 | plot(ImSig, '-', 'LineWidth', 1, 'Color',[0 0 1]) 164 | grid on; hold on; axis tight; 165 | title(['CORDIC SINE / COSINE:']) 166 | 167 | subplot(3,1,2) 168 | plot(Sabs_Re, '-', 'LineWidth', 1, 'Color',[1 0 0]) 169 | grid on; hold on; axis tight; 170 | plot(Sabs_Im, '-', 'LineWidth', 1, 'Color',[0 0 1]) 171 | grid on; hold on; axis tight; 172 | 173 | subplot(4,1,2) 174 | plot(Slog_Re, '-', 'LineWidth', 1, 'Color',[1 0 0]) 175 | grid on; hold on; axis ([0, length(Slog_Re), -120, 0]); 176 | plot(Slog_Im, '-', 'LineWidth', 1, 'Color',[0 0 1]) 177 | grid on; hold on; axis ([0, length(Slog_Re), -120, 0]); 178 | title(['CORDIC SPECTRUM:']) 179 | 180 | subplot(4,1,3) 181 | plot(Sidl_Re, '-', 'LineWidth', 1, 'Color',[1 0 0]) 182 | grid on; hold on; axis ([0, length(Sidl_Re), -120, 0]); 183 | plot(Sidl_Im, '-', 'LineWidth', 1, 'Color',[0 0 1]) 184 | grid on; hold on; axis ([0, length(Sidl_Re), -120, 0]); 185 | title(['IDEAL SPECTRUM:']) 186 | 187 | subplot(4,1,4) 188 | plot(ReSig-Id_cos, '-', 'LineWidth', 1, 'Color',[1 0 0]) 189 | grid on; hold on; axis tight; 190 | plot(ImSig-Id_sin, '-', 'LineWidth', 1, 'Color',[0 0 1]) 191 | grid on; hold on; axis tight; 192 | title(['DIFF - MODEL & THEORY:']) 193 | 194 | 195 | %% -------------------------------- EOF ------------------------------------- %% -------------------------------------------------------------------------------- /src/win_selector.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : win_selector 4 | -- Design : Blackman-Harris Windows 5 | -- Author : Kapitanov Alexander 6 | -- Company : 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | -- Description : Select type of windows: Hamming, Blackman-Harris 3, 4, 5, 7-term 10 | -- 11 | -- Parameters: 12 | -- PHI_WIDTH - Signal period = 2^PHI_WIDTH 13 | -- DAT_WIDTH - Output data width 14 | -- SIN_TYPE -Sine generator type: CORDIC / TAYLOR 15 | -- 16 | -- ---- For Taylor series only and Hamming / BH 3-term windows ---- 17 | -- LUT_SIZE - ROM depth for sin/cos (must be less than PHASE_WIDTH) 18 | -- XSERIES - for 6/7 series: "7SERIES"; for ULTRASCALE: "ULTRA"; 19 | -- 20 | -- Note: While using TAYLOR scheme You must set LUT_SIZE < (PHASE_WIDTH - 3) 21 | -- for correct delays. 22 | -- 23 | -- WIN_TYPE - type of window func: Hamming, Blackman-Harris 3, 4, 5, 7-term 24 | -- 25 | -- > HAMMING - Hamming (Hann) window, 26 | -- > BH3TERM - Blackman-Harris 3-term, 27 | -- > BH4TERM - Blackman-Harris 4-term, 28 | -- > BH5TERM - Blackman-Harris 5-term, 29 | -- > BH7TERM - Blackman-Harris 7-term. 30 | -- 31 | ------------------------------------------------------------------------------- 32 | ------------------------------------------------------------------------------- 33 | -- 34 | -- GNU GENERAL PUBLIC LICENSE 35 | -- Version 3, 29 June 2007 36 | -- 37 | -- Copyright (c) 2018 Kapitanov Alexander 38 | -- 39 | -- This program is free software: you can redistribute it and/or modify 40 | -- it under the terms of the GNU General Public License as published by 41 | -- the Free Software Foundation, either version 3 of the License, or 42 | -- (at your option) any later version. 43 | -- 44 | -- You should have received a copy of the GNU General Public License 45 | -- along with this program. If not, see . 46 | -- 47 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 48 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 49 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 50 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 51 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 52 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 53 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 54 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 55 | -- 56 | ------------------------------------------------------------------------------- 57 | library ieee; 58 | use ieee.std_logic_1164.all; 59 | 60 | entity win_selector is 61 | generic ( 62 | TD : time:=0.5ns; --! Time delay 63 | PHI_WIDTH : integer:=10; --! Signal period = 2^PHI_WIDTH 64 | DAT_WIDTH : integer:=16; --! Output data width 65 | WIN_TYPE : string:="HAMMING"; --! Window type: Hamming, Blackman-Harris 3-, 4-, 5-, 7-term 66 | SIN_TYPE : string:="CORDIC"; --! Sine generator type: CORDIC / TAYLOR 67 | ---- For Taylor series only ---- 68 | LUT_SIZE : integer:= 9; --! ROM depth for sin/cos (must be less than PHASE_WIDTH) 69 | XSERIES : string:="ULTRA" --! for 6/7 series: "7SERIES"; for ULTRASCALE: "ULTRA"; 70 | ); 71 | port ( 72 | RESET : in std_logic; --! Global reset 73 | CLK : in std_logic; --! System clock 74 | 75 | AA0 : in std_logic_vector(DAT_WIDTH-1 downto 0); --! Constant A0 76 | AA1 : in std_logic_vector(DAT_WIDTH-1 downto 0); --! Constant A1 77 | AA2 : in std_logic_vector(DAT_WIDTH-1 downto 0); --! Constant A1 78 | AA3 : in std_logic_vector(DAT_WIDTH-1 downto 0); --! Constant A1 79 | AA4 : in std_logic_vector(DAT_WIDTH-1 downto 0); --! Constant A1 80 | AA5 : in std_logic_vector(DAT_WIDTH-1 downto 0); --! Constant A1 81 | AA6 : in std_logic_vector(DAT_WIDTH-1 downto 0); --! Constant A1 82 | 83 | ENABLE : in std_logic; --! Input data enable block = NFFT clocks 84 | DT_WIN : out std_logic_vector(DAT_WIDTH-1 downto 0); --! Output (cos) 85 | DT_VLD : out std_logic --! Output data valid 86 | ); 87 | end win_selector; 88 | 89 | architecture win_selector of win_selector is 90 | 91 | begin 92 | 93 | xHAMMING: if (WIN_TYPE = "HAMMING") generate 94 | xWIN2: entity work.hamming_win 95 | generic map ( 96 | PHI_WIDTH => PHI_WIDTH, 97 | DAT_WIDTH => DAT_WIDTH, 98 | SIN_TYPE => SIN_TYPE, 99 | LUT_SIZE => LUT_SIZE, 100 | XSERIES => XSERIES 101 | ) 102 | port map ( 103 | RESET => RESET, 104 | CLK => CLK, 105 | 106 | AA0 => AA0, 107 | AA1 => AA1, 108 | ENABLE => ENABLE, 109 | DT_WIN => DT_WIN, 110 | DT_VLD => DT_VLD 111 | 112 | ); 113 | end generate; 114 | 115 | xBH3: if (WIN_TYPE = "BH3TERM") generate 116 | xWIN3: entity work.bh_win_3term 117 | generic map ( 118 | PHI_WIDTH => PHI_WIDTH, 119 | DAT_WIDTH => DAT_WIDTH, 120 | SIN_TYPE => SIN_TYPE, 121 | LUT_SIZE => LUT_SIZE, 122 | XSERIES => XSERIES 123 | ) 124 | port map ( 125 | RESET => RESET, 126 | CLK => CLK, 127 | 128 | AA0 => AA0, 129 | AA1 => AA1, 130 | AA2 => AA2, 131 | ENABLE => ENABLE, 132 | DT_WIN => DT_WIN, 133 | DT_VLD => DT_VLD 134 | ); 135 | end generate; 136 | 137 | xBH4: if (WIN_TYPE = "BH4TERM") generate 138 | xWIN4: entity work.bh_win_4term 139 | generic map ( 140 | PHI_WIDTH => PHI_WIDTH, 141 | DAT_WIDTH => DAT_WIDTH 142 | ) 143 | port map ( 144 | RESET => RESET, 145 | CLK => CLK, 146 | 147 | AA0 => AA0, 148 | AA1 => AA1, 149 | AA2 => AA2, 150 | AA3 => AA3, 151 | ENABLE => ENABLE, 152 | DT_WIN => DT_WIN, 153 | DT_VLD => DT_VLD 154 | ); 155 | end generate; 156 | 157 | xBH5: if (WIN_TYPE = "BH5TERM") generate 158 | xWIN5: entity work.bh_win_5term 159 | generic map ( 160 | PHI_WIDTH => PHI_WIDTH, 161 | DAT_WIDTH => DAT_WIDTH 162 | ) 163 | port map ( 164 | RESET => RESET, 165 | CLK => CLK, 166 | 167 | AA0 => AA0, 168 | AA1 => AA1, 169 | AA2 => AA2, 170 | AA3 => AA3, 171 | AA4 => AA4, 172 | ENABLE => ENABLE, 173 | DT_WIN => DT_WIN, 174 | DT_VLD => DT_VLD 175 | ); 176 | end generate; 177 | 178 | xBH7: if (WIN_TYPE = "BH7TERM") generate 179 | xWIN7: entity work.bh_win_7term 180 | generic map ( 181 | PHI_WIDTH => PHI_WIDTH, 182 | DAT_WIDTH => DAT_WIDTH 183 | ) 184 | port map ( 185 | RESET => RESET, 186 | CLK => CLK, 187 | 188 | AA0 => AA0, 189 | AA1 => AA1, 190 | AA2 => AA2, 191 | AA3 => AA3, 192 | AA4 => AA4, 193 | AA5 => AA5, 194 | AA6 => AA6, 195 | ENABLE => ENABLE, 196 | DT_WIN => DT_WIN, 197 | DT_VLD => DT_VLD 198 | ); 199 | end generate; 200 | 201 | end win_selector; -------------------------------------------------------------------------------- /hls/windows/window_test.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | -- 3 | -- Title : window_sel.c 4 | -- Design : Window function Testbench 5 | -- Author : Kapitanov Alexander 6 | -- Company : insys.ru 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | ------------------------------------------------------------------------------- 10 | -- 11 | -- Version 1.0 11.09.2018 12 | -- 13 | ------------------------------------------------------------------------------- 14 | -- 15 | -- Description : Simple model for calculating several window functions 16 | -- 17 | ------------------------------------------------------------------------------- 18 | ------------------------------------------------------------------------------- 19 | -- 20 | -- GNU GENERAL PUBLIC LICENSE 21 | -- Version 3, 29 June 2007 22 | -- 23 | -- Copyright (c) 2018 Kapitanov Alexander 24 | -- 25 | -- This program is free software: you can redistribute it and/or modify 26 | -- it under the terms of the GNU General Public License as published by 27 | -- the Free Software Foundation, either version 3 of the License, or 28 | -- (at your option) any later version. 29 | -- 30 | -- You should have received a copy of the GNU General Public License 31 | -- along with this program. If not, see . 32 | -- 33 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 34 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 35 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 36 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 37 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 38 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 39 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 40 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 41 | -- 42 | *******************************************************************************/ 43 | #include 44 | #include 45 | 46 | #include 47 | #include "win_function.h" 48 | 49 | int main () { 50 | 51 | printf("!!! ************************************************ !!!\n"); 52 | printf("\nPhase = %d, Data = %d, Samples = %d Result: \n", NPHASE, NWIDTH, NSAMPLES); 53 | 54 | FILE *fout; FILE *fgld; 55 | fout = fopen("..\\..\\..\\..\\..\\math\\dout.dat", "w"); 56 | fgld = fopen("..\\..\\..\\..\\..\\math\\golden_dat.dat", "w"); 57 | 58 | /* Select window function type */ 59 | int sel = 0xFFFF; 60 | if (strcmp(Wintype, "Hamming") == 0 ) { 61 | sel = 0x1; 62 | } else if (strcmp(Wintype, "Hann") == 0 ) { 63 | sel = 0x2; 64 | } else if (strcmp(Wintype, "Blackman-Harris-3") == 0 ) { 65 | sel = 0x3; 66 | } else if (strcmp(Wintype, "Blackman-Harris-4") == 0 ) { 67 | sel = 0x4; 68 | } else if (strcmp(Wintype, "Blackman-Harris-5") == 0 ) { 69 | sel = 0x5; 70 | } else if (strcmp(Wintype, "Blackman-Harris-7") == 0 ) { 71 | sel = 0x7; 72 | } else { 73 | sel = 0xAAAA; 74 | } 75 | printf("Selected window is %s (Number - %d)\n", Wintype, sel); 76 | 77 | 78 | double calc_dbl; 79 | win_t win_rnd[NSAMPLES]; 80 | win_t win_out[NSAMPLES]; 81 | win_t win_res; 82 | 83 | 84 | int shift = 1; 85 | printf("HLS Data: \t Golden Data:\n"); 86 | 87 | /* Weight parameters */ 88 | double a0, a1, a2, a3, a4, a5, a6; 89 | 90 | double acc_err = 0; 91 | 92 | int i = 0x0; 93 | for (i = 0; i < NSAMPLES; i++) 94 | { 95 | switch (sel) { 96 | case 0x1: 97 | a0 = 0.5434783; 98 | a1 = 1.0 - 0.5434783; 99 | calc_dbl = a0 - a1 * cos((2 * i * M_PI)/NSAMPLES); 100 | shift = 1; 101 | break; 102 | 103 | case 0x2: 104 | a0 = 0.5; 105 | a1 = 0.5; 106 | calc_dbl = a0 - a1 * cos((2 * i * M_PI)/NSAMPLES); 107 | shift = 1; 108 | break; 109 | 110 | case 0x3: 111 | a0 = 0.21; 112 | a1 = 0.25; 113 | a2 = 0.04; 114 | calc_dbl = a0 - a1 * cos((2 * i * M_PI)/NSAMPLES) + a2 * cos((2 * 2 * i * M_PI)/NSAMPLES); 115 | shift = 1; 116 | break; 117 | 118 | case 0x4: 119 | /* 120 | > Blackman-Harris: 121 | a0 = 0.35875, 122 | a1 = 0.48829, 123 | a2 = 0.14128, 124 | a3 = 0.01168. 125 | > Nuttall: 126 | a0 = 0.355768, 127 | a1 = 0.487396, 128 | a2 = 0.144323, 129 | a3 = 0.012604. 130 | > Blackman-Nuttall: 131 | a0 = 0.3635819, 132 | a1 = 0.4891775, 133 | a2 = 0.1365995, 134 | a3 = 0.0106411. 135 | */ 136 | a0 = 0.35875; 137 | a1 = 0.48829; 138 | a2 = 0.14128; 139 | a3 = 0.01168; 140 | 141 | calc_dbl = a0 - a1 * cos((2 * i * M_PI)/NSAMPLES) + a2 * cos((2 * 2 * i * M_PI)/NSAMPLES) - a3 * cos((3 * 2 * i * M_PI)/NSAMPLES); 142 | shift = 1; 143 | break; 144 | 145 | case 0x5: 146 | /* 147 | > Blackman-Harris: 148 | a0 = 0.3232153788877343; 149 | a1 = 0.4714921439576260; 150 | a2 = 0.1755341299601972; 151 | a3 = 0.0284969901061499; 152 | a4 = 0.0012613570882927; 153 | > Flat-top (1): 154 | a0 = 0.25000; 155 | a1 = 0.49250; 156 | a2 = 0.32250; 157 | a3 = 0.09700; 158 | a4 = 0.00750; 159 | > Flat-top (2): 160 | a0 = 0.215578950; 161 | a1 = 0.416631580; 162 | a2 = 0.277263158; 163 | a3 = 0.083578947; 164 | a4 = 0.006947368; 165 | */ 166 | a0 = 0.3232153788877343; 167 | a1 = 0.4714921439576260; 168 | a2 = 0.1755341299601972; 169 | a3 = 0.0284969901061499; 170 | a4 = 0.0012613570882927; 171 | 172 | calc_dbl = a0 - a1 * cos((2 * i * M_PI)/NSAMPLES) + a2 * cos((2 * 2 * i * M_PI)/NSAMPLES) - a3 * cos((3 * 2 * i * M_PI)/NSAMPLES) + a4 * cos((4 * 2 * i * M_PI)/NSAMPLES); 173 | shift = 2; 174 | break; 175 | 176 | case 0x7: 177 | a0 = 0.271220360585039; 178 | a1 = 0.433444612327442; 179 | a2 = 0.218004122892930; 180 | a3 = 0.065785343295606; 181 | a4 = 0.010761867305342; 182 | a5 = 0.000770012710581; 183 | a6 = 0.000013680883060; 184 | 185 | calc_dbl = a0 - a1 * cos((2 * i * M_PI)/NSAMPLES) + a2 * cos((2 * 2 * i * M_PI)/NSAMPLES) - a3 * cos((3 * 2 * i * M_PI)/NSAMPLES) + a4 * cos((4 * 2 * i * M_PI)/NSAMPLES) - a5 * cos((5 * 2 * i * M_PI)/NSAMPLES) + a6 * cos((6 * 2 * i * M_PI)/NSAMPLES); 186 | shift = 2; 187 | break; 188 | default: 189 | calc_dbl = 0x0; 190 | } 191 | 192 | /* Execute window function */ 193 | win_function(sel, i, &win_res); 194 | win_out[i] = win_res; 195 | 196 | win_rnd[i] = (win_t) (round((pow(2.0, NWIDTH-shift)-1.0) * calc_dbl)); 197 | 198 | acc_err += pow(abs((double)win_rnd[i] - (double)win_out[i]), 2); 199 | 200 | fprintf(fout, "%d \n", (int)win_out[i]); 201 | fprintf(fgld, "%d \n", (int)win_rnd[i]); 202 | 203 | if (i < 16) 204 | { 205 | printf("%08X \t %08X\n", (int)win_out[i], (int)win_rnd[i]); 206 | } 207 | 208 | } 209 | acc_err = sqrt(acc_err) / NSAMPLES; 210 | 211 | fclose(fout); 212 | fclose(fout); 213 | 214 | printf("\nCalculation error between integer and double = %lf \n", acc_err); 215 | 216 | if (acc_err < 10) { 217 | printf ("PASS: Data matches the golden output!\n"); 218 | return 0; 219 | } else { 220 | printf ("FAIL: Data DOES NOT match the golden output\n"); 221 | return 1; 222 | } 223 | 224 | } 225 | -------------------------------------------------------------------------------- /src/mults/mlt35x27_dsp48e2.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : mlt35x27_dsp48e2 4 | -- Design : FFTK 5 | -- Author : Kapitanov 6 | -- Company : 7 | -- 8 | -- Description : Multiplier 35x27 based on DSP48E2 block 9 | -- 10 | ------------------------------------------------------------------------------- 11 | -- 12 | -- Version 1.0: 14.02.2018 13 | -- 14 | -- Description: Double complex multiplier by DSP48 unit 15 | -- 16 | -- Math: MLT_P = MLT_A * MLT_B (w/ double multiplier) 17 | -- 18 | -- DSP48 data signals: 19 | -- A port - data width up to 25 (27)* bits 20 | -- B port - data width up to 35 bits 21 | -- * - 25 bits for DSP48E1, 27 bits for DSP48E2. 22 | -- 23 | -- Total delay : 4 clock cycles, 24 | -- Total resources : 2 DSP48 units 25 | -- 26 | ------------------------------------------------------------------------------- 27 | ------------------------------------------------------------------------------- 28 | -- 29 | -- GNU GENERAL PUBLIC LICENSE 30 | -- Version 3, 29 June 2007 31 | -- 32 | -- Copyright (c) 2018 Kapitanov Alexander 33 | -- 34 | -- This program is free software: you can redistribute it and/or modify 35 | -- it under the terms of the GNU General Public License as published by 36 | -- the Free Software Foundation, either version 3 of the License, or 37 | -- (at your option) any later version. 38 | -- 39 | -- You should have received a copy of the GNU General Public License 40 | -- along with this program. If not, see . 41 | -- 42 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 43 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 44 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 45 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 46 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 47 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 48 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 49 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 50 | -- 51 | ------------------------------------------------------------------------------- 52 | ------------------------------------------------------------------------------- 53 | 54 | library ieee; 55 | use ieee.std_logic_1164.all; 56 | 57 | library unisim; 58 | use unisim.vcomponents.DSP48E2; 59 | 60 | entity mlt35x27_dsp48e2 is 61 | port ( 62 | MLT_A : in std_logic_vector(34 downto 0); --! A port: up to 42 bits 63 | MLT_B : in std_logic_vector(26 downto 0); --! B port: up to 18 bits 64 | MLT_P : out std_logic_vector(61 downto 0); --! P port: double multiplier 65 | RST : in std_logic; --! Global reset 66 | CLK : in std_logic --! Math clock 67 | ); 68 | end mlt35x27_dsp48e2; 69 | 70 | architecture mlt35x27_dsp48e2 of mlt35x27_dsp48e2 is 71 | 72 | signal dspA_12 : std_logic_vector(29 downto 0); 73 | signal dspB_M1 : std_logic_vector(17 downto 0); 74 | signal dspB_M2 : std_logic_vector(17 downto 0); 75 | 76 | signal dspP_M1 : std_logic_vector(47 downto 0); 77 | signal dspP_M2 : std_logic_vector(47 downto 0); 78 | signal dspP_12 : std_logic_vector(47 downto 0); 79 | 80 | begin 81 | MLT_P(16 downto 00) <= dspP_M2(16 downto 00) when rising_edge(clk); 82 | MLT_P(61 downto 17) <= dspP_M1(44 downto 00); 83 | 84 | dspA_12(26 downto 00) <= MLT_B(26 downto 0); 85 | dspA_12(29 downto 27) <= (others => MLT_B(26)); 86 | 87 | dspB_M2(16 downto 00) <= MLT_A(16 downto 00); 88 | dspB_M2(17) <= '0'; 89 | dspB_M1(17 downto 00) <= MLT_A(34 downto 17); 90 | 91 | ---- Wrap DSP48E2 units ---- 92 | xDSP_M1: DSP48E2 93 | generic map ( 94 | -- Feature Control Attributes: Data Path Selection 95 | USE_MULT => "MULTIPLY", 96 | -- Register Control Attributes: Pipeline Register Configuration 97 | ACASCREG => 1, 98 | ADREG => 1, 99 | ALUMODEREG => 1, 100 | AREG => 2, 101 | BCASCREG => 1, 102 | BREG => 2, 103 | CARRYINREG => 1, 104 | CARRYINSELREG => 1, 105 | CREG => 1, 106 | DREG => 1, 107 | INMODEREG => 1, 108 | MREG => 1, 109 | OPMODEREG => 1, 110 | PREG => 1 111 | ) 112 | port map ( 113 | -- Data: input / output data ports 114 | A => dspA_12, -- 30-bit input: A data input 115 | B => dspB_M1, -- 18-bit input: B data input 116 | C => (others=>'0'), 117 | D => (others=>'0'), 118 | P => dspP_M1, 119 | PCOUT => open, 120 | -- Control: Inputs/Status Bits 121 | ALUMODE => (others=>'0'), 122 | INMODE => (others=>'0'), 123 | OPMODE => "001010101", 124 | -- Carry input data 125 | ACIN => (others=>'0'), 126 | BCIN => (others=>'0'), 127 | PCIN => dspP_12, 128 | CARRYINSEL => (others=>'0'), 129 | CARRYCASCIN => '0', 130 | CARRYIN => '0', 131 | MULTSIGNIN => '0', 132 | -- Clock enables 133 | CEA1 => '1', 134 | CEA2 => '1', 135 | CEAD => '1', 136 | CEALUMODE => '1', 137 | CEB1 => '1', 138 | CEB2 => '1', 139 | CEC => '1', 140 | CECARRYIN => '1', 141 | CECTRL => '1', 142 | CED => '1', 143 | CEINMODE => '1', 144 | CEM => '1', 145 | CEP => '1', 146 | CLK => CLK, 147 | -- Reset/Clock Enable -- 148 | RSTA => RST, 149 | RSTALLCARRYIN => RST, 150 | RSTALUMODE => RST, 151 | RSTB => RST, 152 | RSTC => RST, 153 | RSTCTRL => RST, 154 | RSTD => RST, 155 | RSTINMODE => RST, 156 | RSTM => RST, 157 | RSTP => RST 158 | ); 159 | 160 | xDSP_M2: DSP48E2 161 | generic map ( 162 | -- Feature Control Attributes: Data Path Selection 163 | USE_MULT => "MULTIPLY", 164 | -- Register Control Attributes: Pipeline Register Configuration 165 | ACASCREG => 1, 166 | ADREG => 1, 167 | ALUMODEREG => 1, 168 | AREG => 1, 169 | BCASCREG => 1, 170 | BREG => 1, 171 | CARRYINREG => 1, 172 | CARRYINSELREG => 1, 173 | CREG => 1, 174 | DREG => 1, 175 | INMODEREG => 1, 176 | MREG => 1, 177 | OPMODEREG => 1, 178 | PREG => 1 179 | ) 180 | port map ( 181 | -- Data: input / output data ports 182 | A => dspA_12, -- 30-bit input: A data input 183 | B => dspB_M2, -- 18-bit input: B data input 184 | C => (others=>'0'), 185 | D => (others=>'0'), 186 | P => dspP_M2, 187 | PCOUT => dspP_12, 188 | -- Control: Inputs/Status Bits 189 | ALUMODE => (others=>'0'), 190 | INMODE => (others=>'0'), 191 | OPMODE => "000000101", 192 | -- Carry input data 193 | ACIN => (others=>'0'), 194 | BCIN => (others=>'0'), 195 | PCIN => (others=>'0'), 196 | CARRYINSEL => (others=>'0'), 197 | CARRYCASCIN => '0', 198 | CARRYIN => '0', 199 | MULTSIGNIN => '0', 200 | -- Clock enables 201 | CEA1 => '1', 202 | CEA2 => '1', 203 | CEAD => '1', 204 | CEALUMODE => '1', 205 | CEB1 => '1', 206 | CEB2 => '1', 207 | CEC => '1', 208 | CECARRYIN => '1', 209 | CECTRL => '1', 210 | CED => '1', 211 | CEINMODE => '1', 212 | CEM => '1', 213 | CEP => '1', 214 | CLK => CLK, 215 | -- Reset/Clock Enable -- 216 | RSTA => RST, 217 | RSTALLCARRYIN => RST, 218 | RSTALUMODE => RST, 219 | RSTB => RST, 220 | RSTC => RST, 221 | RSTCTRL => RST, 222 | RSTD => RST, 223 | RSTINMODE => RST, 224 | RSTM => RST, 225 | RSTP => RST 226 | ); 227 | 228 | end mlt35x27_dsp48e2; -------------------------------------------------------------------------------- /src/mults/mlt35x25_dsp48e1.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : mlt35x25_dsp48e1 4 | -- Design : FFTK 5 | -- Author : Kapitanov 6 | -- Company : 7 | -- 8 | -- Description : Multiplier 35x25 based on DSP48E1 block 9 | -- 10 | ------------------------------------------------------------------------------- 11 | -- 12 | -- Version 1.0: 14.02.2018 13 | -- 14 | -- Description: Double complex multiplier by DSP48 unit 15 | -- 16 | -- Math: MLT_P = MLT_A * MLT_B (w/ double multiplier) 17 | -- 18 | -- DSP48 data signals: 19 | -- A port - data width up to 25 (27)* bits 20 | -- B port - data width up to 35 bits 21 | -- * - 25 bits for DSP48E1, 27 bits for DSP48E2. 22 | -- 23 | -- Total delay : 4 clock cycles, 24 | -- Total resources : 2 DSP48 units 25 | -- 26 | ------------------------------------------------------------------------------- 27 | ------------------------------------------------------------------------------- 28 | -- 29 | -- GNU GENERAL PUBLIC LICENSE 30 | -- Version 3, 29 June 2007 31 | -- 32 | -- Copyright (c) 2018 Kapitanov Alexander 33 | -- 34 | -- This program is free software: you can redistribute it and/or modify 35 | -- it under the terms of the GNU General Public License as published by 36 | -- the Free Software Foundation, either version 3 of the License, or 37 | -- (at your option) any later version. 38 | -- 39 | -- You should have received a copy of the GNU General Public License 40 | -- along with this program. If not, see . 41 | -- 42 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 43 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 44 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 45 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 46 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 47 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 48 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 49 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 50 | -- 51 | ------------------------------------------------------------------------------- 52 | ------------------------------------------------------------------------------- 53 | 54 | library ieee; 55 | use ieee.std_logic_1164.all; 56 | 57 | library unisim; 58 | use unisim.vcomponents.DSP48E1; 59 | 60 | entity mlt35x25_dsp48e1 is 61 | port ( 62 | MLT_A : in std_logic_vector(34 downto 0); --! A port: up to 42 bits 63 | MLT_B : in std_logic_vector(24 downto 0); --! B port: up to 18 bits 64 | MLT_P : out std_logic_vector(59 downto 0); --! P port: double multiplier 65 | RST : in std_logic; --! Global reset 66 | CLK : in std_logic --! Math clock 67 | ); 68 | end mlt35x25_dsp48e1; 69 | 70 | architecture mlt35x25_dsp48e1 of mlt35x25_dsp48e1 is 71 | 72 | signal dspA_12 : std_logic_vector(29 downto 0); 73 | signal dspB_M1 : std_logic_vector(17 downto 0); 74 | signal dspB_M2 : std_logic_vector(17 downto 0); 75 | 76 | signal dspP_M1 : std_logic_vector(47 downto 0); 77 | signal dspP_M2 : std_logic_vector(47 downto 0); 78 | signal dspP_12 : std_logic_vector(47 downto 0); 79 | 80 | begin 81 | MLT_P(16 downto 00) <= dspP_M2(16 downto 00) after 0.1 ns when rising_edge(clk); 82 | MLT_P(59 downto 17) <= dspP_M1(42 downto 00); 83 | 84 | dspA_12(24 downto 00) <= MLT_B(24 downto 0); 85 | dspA_12(29 downto 25) <= (others => MLT_B(24)); 86 | 87 | dspB_M2(16 downto 00) <= MLT_A(16 downto 00); 88 | dspB_M2(17) <= '0'; 89 | dspB_M1(17 downto 00) <= MLT_A(34 downto 17); 90 | 91 | ---- Wrap DSP48E1 units ---- 92 | xDSP_M1: DSP48E1 93 | generic map ( 94 | -- Feature Control Attributes: Data Path Selection 95 | USE_MULT => "MULTIPLY", 96 | -- Register Control Attributes: Pipeline Register Configuration 97 | ACASCREG => 1, 98 | ADREG => 1, 99 | ALUMODEREG => 1, 100 | AREG => 2, 101 | BCASCREG => 1, 102 | BREG => 2, 103 | CARRYINREG => 1, 104 | CARRYINSELREG => 1, 105 | CREG => 1, 106 | DREG => 1, 107 | INMODEREG => 1, 108 | MREG => 1, 109 | OPMODEREG => 1, 110 | PREG => 1 111 | ) 112 | port map ( 113 | -- Data: input / output data ports 114 | A => dspA_12, -- 30-bit input: A data input 115 | B => dspB_M1, -- 18-bit input: B data input 116 | C => (others=>'0'), 117 | D => (others=>'0'), 118 | P => dspP_M1, 119 | PCOUT => open, 120 | -- Control: Inputs/Status Bits 121 | ALUMODE => (others=>'0'), 122 | INMODE => (others=>'0'), 123 | OPMODE => "1010101", 124 | -- Carry input data 125 | ACIN => (others=>'0'), 126 | BCIN => (others=>'0'), 127 | PCIN => dspP_12, 128 | CARRYINSEL => (others=>'0'), 129 | CARRYCASCIN => '0', 130 | CARRYIN => '0', 131 | MULTSIGNIN => '0', 132 | -- Clock enables 133 | CEA1 => '1', 134 | CEA2 => '1', 135 | CEAD => '1', 136 | CEALUMODE => '1', 137 | CEB1 => '1', 138 | CEB2 => '1', 139 | CEC => '1', 140 | CECARRYIN => '1', 141 | CECTRL => '1', 142 | CED => '1', 143 | CEINMODE => '1', 144 | CEM => '1', 145 | CEP => '1', 146 | CLK => CLK, 147 | -- Reset/Clock Enable -- 148 | RSTA => RST, 149 | RSTALLCARRYIN => RST, 150 | RSTALUMODE => RST, 151 | RSTB => RST, 152 | RSTC => RST, 153 | RSTCTRL => RST, 154 | RSTD => RST, 155 | RSTINMODE => RST, 156 | RSTM => RST, 157 | RSTP => RST 158 | ); 159 | 160 | xDSP_M2: DSP48E1 161 | generic map ( 162 | -- Feature Control Attributes: Data Path Selection 163 | USE_MULT => "MULTIPLY", 164 | -- Register Control Attributes: Pipeline Register Configuration 165 | ACASCREG => 1, 166 | ADREG => 1, 167 | ALUMODEREG => 1, 168 | AREG => 1, 169 | BCASCREG => 1, 170 | BREG => 1, 171 | CARRYINREG => 1, 172 | CARRYINSELREG => 1, 173 | CREG => 1, 174 | DREG => 1, 175 | INMODEREG => 1, 176 | MREG => 1, 177 | OPMODEREG => 1, 178 | PREG => 1 179 | ) 180 | port map ( 181 | -- Data: input / output data ports 182 | A => dspA_12, -- 30-bit input: A data input 183 | B => dspB_M2, -- 18-bit input: B data input 184 | C => (others=>'0'), 185 | D => (others=>'0'), 186 | P => dspP_M2, 187 | PCOUT => dspP_12, 188 | -- Control: Inputs/Status Bits 189 | ALUMODE => (others=>'0'), 190 | INMODE => (others=>'0'), 191 | OPMODE => "0000101", 192 | -- Carry input data 193 | ACIN => (others=>'0'), 194 | BCIN => (others=>'0'), 195 | PCIN => (others=>'0'), 196 | CARRYINSEL => (others=>'0'), 197 | CARRYCASCIN => '0', 198 | CARRYIN => '0', 199 | MULTSIGNIN => '0', 200 | -- Clock enables 201 | CEA1 => '1', 202 | CEA2 => '1', 203 | CEAD => '1', 204 | CEALUMODE => '1', 205 | CEB1 => '1', 206 | CEB2 => '1', 207 | CEC => '1', 208 | CECARRYIN => '1', 209 | CECTRL => '1', 210 | CED => '1', 211 | CEINMODE => '1', 212 | CEM => '1', 213 | CEP => '1', 214 | CLK => CLK, 215 | -- Reset/Clock Enable -- 216 | RSTA => RST, 217 | RSTALLCARRYIN => RST, 218 | RSTALUMODE => RST, 219 | RSTB => RST, 220 | RSTC => RST, 221 | RSTCTRL => RST, 222 | RSTD => RST, 223 | RSTINMODE => RST, 224 | RSTM => RST, 225 | RSTP => RST 226 | ); 227 | 228 | end mlt35x25_dsp48e1; -------------------------------------------------------------------------------- /src/hamming_win.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : hamming_win 4 | -- Design : Blackman-Harris Windows 5 | -- Author : Kapitanov Alexander 6 | -- Company : 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | -- Description : Simple 2-term window: 10 | -- Hann (a = 0.5) or Hamming (a = 0.54347826087 or a = 25/46) 11 | -- 12 | -- Constants type - REAL (float IEEE-754) 13 | -- 14 | -- > Hann: 15 | -- a0 = 0.5; 16 | -- a1 = 1 - a0 = 0.5; 17 | -- 18 | -- > Hamming: (a = 25/46). 19 | -- a0 = 0.5434783; 20 | -- a1 = 0.4565217; 21 | -- or 22 | -- a0 = 0.5383554; 23 | -- a1 = 0.4616446; 24 | -- 25 | ------------------------------------------------------------------------------- 26 | ------------------------------------------------------------------------------- 27 | -- 28 | -- GNU GENERAL PUBLIC LICENSE 29 | -- Version 3, 29 June 2007 30 | -- 31 | -- Copyright (c) 2018 Kapitanov Alexander 32 | -- 33 | -- This program is free software: you can redistribute it and/or modify 34 | -- it under the terms of the GNU General Public License as published by 35 | -- the Free Software Foundation, either version 3 of the License, or 36 | -- (at your option) any later version. 37 | -- 38 | -- You should have received a copy of the GNU General Public License 39 | -- along with this program. If not, see . 40 | -- 41 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 42 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 43 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 44 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 45 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 46 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 47 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 48 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 49 | -- 50 | ------------------------------------------------------------------------------- 51 | library ieee; 52 | use ieee.std_logic_1164.all; 53 | use ieee.std_logic_arith.all; 54 | use ieee.std_logic_signed.all; 55 | 56 | -- library unisim; 57 | -- use unisim.vcomponents.DSP48E1; 58 | -- use unisim.vcomponents.DSP48E2; 59 | 60 | entity hamming_win is 61 | generic ( 62 | TD : time:=0.5ns; --! Time delay 63 | PHI_WIDTH : integer:=10; --! Signal period = 2^PHI_WIDTH 64 | DAT_WIDTH : integer:=16; --! Output data width 65 | SIN_TYPE : string:="CORDIC"; --! Sine generator type: CORDIC / TAYLOR 66 | ---- For Taylor series only ---- 67 | LUT_SIZE : integer:= 9; --! ROM depth for sin/cos (must be less than PHASE_WIDTH) 68 | XSERIES : string:="ULTRA" --! for 6/7 series: "7SERIES"; for ULTRASCALE: "ULTRA"; 69 | ); 70 | port ( 71 | RESET : in std_logic; --! Global reset 72 | CLK : in std_logic; --! System clock 73 | 74 | AA0 : in std_logic_vector(DAT_WIDTH-1 downto 0); --! Constant A0 75 | AA1 : in std_logic_vector(DAT_WIDTH-1 downto 0); --! Constant A1 76 | 77 | ENABLE : in std_logic; --! Input data enable block = NFFT clocks 78 | DT_WIN : out std_logic_vector(DAT_WIDTH-1 downto 0); --! Output (cos) 79 | DT_VLD : out std_logic --! Output data valid 80 | ); 81 | end hamming_win; 82 | 83 | architecture hamming_win of hamming_win is 84 | 85 | ---------------- Cordic signals ---------------- 86 | signal cos1 : std_logic_vector(DAT_WIDTH-1 downto 0); 87 | 88 | signal ph_in1 : std_logic_vector(PHI_WIDTH-1 downto 0); 89 | 90 | ---------------- Multiplier signals ---------------- 91 | signal mult_a1 : std_logic_vector(DAT_WIDTH-1 downto 0); 92 | signal mult_b1 : std_logic_vector(DAT_WIDTH-1 downto 0); 93 | signal mult_p1 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 94 | 95 | ---------------- Product signals ---------------- 96 | signal dsp_b0 : std_logic_vector(DAT_WIDTH-1 downto 0); 97 | signal dsp_b1 : std_logic_vector(DAT_WIDTH-1 downto 0); 98 | signal dsp_r1 : std_logic_vector(DAT_WIDTH downto 0); 99 | signal dsp_pp : std_logic_vector(DAT_WIDTH downto 0); 100 | 101 | ---------------- DSP48 signals ---------------- 102 | 103 | ---- Addition delay ---- 104 | function find_delay return integer is 105 | variable ret : integer:=0; 106 | begin 107 | if (SIN_TYPE = "CORDIC") then 108 | ret := DAT_WIDTH+7; 109 | elsif (SIN_TYPE = "TAYLOR") then 110 | if (PHI_WIDTH - LUT_SIZE <= 2) then 111 | ret := 10; 112 | else 113 | if (DAT_WIDTH < 19) then 114 | ret := 13; 115 | else 116 | ret := 16; 117 | end if; 118 | end if; 119 | end if; 120 | return ret; 121 | end find_delay; 122 | 123 | constant ADD_DELAY : integer:=find_delay; 124 | 125 | -- signal vldx : std_logic; 126 | signal ena_zz : std_logic_vector(ADD_DELAY downto 0); 127 | 128 | attribute USE_DSP : string; 129 | attribute USE_DSP of dsp_pp : signal is "YES"; 130 | 131 | begin 132 | 133 | ---------------- Multiplier ---------------- 134 | mult_a1 <= AA1 after td when rising_edge(clk); 135 | mult_b1 <= cos1 after td when rising_edge(clk); 136 | 137 | ---------------- Counter for phase ---------------- 138 | PR_CNT1: process(clk) is 139 | begin 140 | if rising_edge(clk) then 141 | if (reset = '1') then 142 | ph_in1 <= (others => '0') after TD; 143 | else 144 | if (ENABLE = '1') then 145 | ph_in1 <= ph_in1 + 1 after TD; 146 | end if; 147 | end if; 148 | end if; 149 | end process; 150 | 151 | ---------------- Twiddle part 1 ---------------- 152 | xUSE_CORD: if (SIN_TYPE = "CORDIC") generate 153 | xCRD1: entity work.cordic_dds 154 | generic map ( 155 | DATA_WIDTH => DAT_WIDTH, 156 | PHASE_WIDTH => PHI_WIDTH 157 | ) 158 | port map ( 159 | RESET => reset, 160 | CLK => clk, 161 | PH_IN => ph_in1, 162 | PH_EN => ENABLE, 163 | DT_COS => cos1 164 | ); 165 | end generate; 166 | 167 | xUSE_TAY: if (SIN_TYPE = "TAYLOR") generate 168 | xTAY1: entity work.taylor_sincos 169 | generic map ( 170 | XSERIES => XSERIES, 171 | LUT_SIZE => LUT_SIZE, 172 | DATA_WIDTH => DAT_WIDTH, 173 | PHASE_WIDTH => PHI_WIDTH 174 | ) 175 | port map ( 176 | RST => reset, 177 | CLK => clk, 178 | PHI_ENA => ENABLE, 179 | OUT_COS => cos1 180 | ); 181 | end generate; 182 | 183 | xMLT1: entity work.int_multNxN_dsp48 184 | generic map ( DTW => DAT_WIDTH) 185 | port map ( 186 | DAT_A => mult_a1, 187 | DAT_B => mult_b1, 188 | DAT_Q => mult_p1, 189 | CLK => clk, 190 | RST => reset 191 | ); 192 | 193 | ---------------- DSP48 1-2 ---------------- 194 | dsp_b0 <= AA0 after td when rising_edge(clk); 195 | dsp_r1 <= mult_p1(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 196 | 197 | ---------------- Round data from N to N-1 bits ---------------- 198 | pr_rnd: process(clk) is 199 | begin 200 | if rising_edge(clk) then 201 | ---- Round 1 ---- 202 | if (dsp_r1(0) = '0') then 203 | dsp_b1 <= dsp_r1(DAT_WIDTH downto 1) after td; 204 | else 205 | dsp_b1 <= dsp_r1(DAT_WIDTH downto 1) + 1 after td; 206 | end if; 207 | end if; 208 | end process; 209 | 210 | ---------------- DSP48 signal mapping ---------------- 211 | pr_add: process(clk) is 212 | begin 213 | if rising_edge(clk) then 214 | dsp_pp <= (dsp_b0(DAT_WIDTH-1) & dsp_b0) - (dsp_b1(DAT_WIDTH-1) & dsp_b1); 215 | end if; 216 | end process; 217 | 218 | ena_zz <= ena_zz(ena_zz'left-1 downto 0) & enable after td when rising_edge(clk); 219 | ---------------- Round output data from 25 to 24 bits ---------------- 220 | pr_out: process(clk) is 221 | begin 222 | if rising_edge(clk) then 223 | ---- Round 1 ---- 224 | if (dsp_pp(0) = '0') then 225 | DT_WIN <= dsp_pp(DAT_WIDTH downto 1) after td; 226 | else 227 | DT_WIN <= dsp_pp(DAT_WIDTH downto 1) + 1 after td; 228 | end if; 229 | DT_VLD <= ena_zz(ena_zz'left) after td; 230 | end if; 231 | end process; 232 | 233 | end hamming_win; -------------------------------------------------------------------------------- /src/taylor_sincos.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : taylor_sincos 4 | -- Design : Blackman-Harris Windows 5 | -- Author : Kapitanov Alexander 6 | -- Company : 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | -- Description : Sine & Cosine generator by using Taylor function. 10 | -- 11 | -- Input signal of sine/cosine is placed into ROM (or Look-up Table). 12 | -- You can configure DATA WIDTH and PHASE WIDTH, 13 | -- Also you can set the order of Taylor series: 1 or 2. 14 | -- Data values is signed integer type [DATA_WIDTH-1 : 0] 15 | -- Phase values is signed integer type [PHASE_WIDTH : 0] 16 | -- Look-up table for sine and cosine has LUT_SIZE parameter of ROM depth. 17 | -- 18 | -- Parameters: 19 | -- 20 | -- DATA_WIDTH - Number of bits in sin/cos 21 | -- PHASE_WIDT - Number of bits in phase accumulator 22 | -- LUT_SIZE - ROM depth for sin/cos (common depth is from 8 to 10) 23 | -- TAY_ORDER - Taylor series order: 1 or 2 24 | -- 25 | -- Total delay datapath: 26 | -- IF (PHASE_WIDTH - LUT_SIZE < 2) THEN delay = 5 taps, 27 | -- ELSE 28 | -- IF (DATA_WIDTH < 19) THEN delay = 8 taps. 29 | -- else delay = 11 taps. 30 | -- 31 | ------------------------------------------------------------------------------- 32 | ------------------------------------------------------------------------------- 33 | -- 34 | -- GNU GENERAL PUBLIC LICENSE 35 | -- Version 3, 29 June 2007 36 | -- 37 | -- Copyright (c) 2018 Kapitanov Alexander 38 | -- 39 | -- This program is free software: you can redistribute it and/or modify 40 | -- it under the terms of the GNU General Public License as published by 41 | -- the Free Software Foundation, either version 3 of the License, or 42 | -- (at your option) any later version. 43 | -- 44 | -- You should have received a copy of the GNU General Public License 45 | -- along with this program. If not, see . 46 | -- 47 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 48 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 49 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 50 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 51 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 52 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 53 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 54 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 55 | -- 56 | ------------------------------------------------------------------------------- 57 | 58 | library ieee; 59 | use ieee.std_logic_1164.all; 60 | use ieee.std_logic_signed.all; 61 | use ieee.std_logic_arith.all; 62 | 63 | use ieee.math_real.all; 64 | 65 | entity taylor_sincos is 66 | generic ( 67 | DATA_WIDTH : integer:= 32; --! Number of bits in sin/cos 68 | PHASE_WIDTH : integer:= 14; --! Number of bits in phase accumulator 69 | LUT_SIZE : integer:= 9; --! ROM depth for sin/cos (must be less than PHASE_WIDTH) 70 | -- TAY_ORDER : integer range 1 to 2:=1; -- Taylor series order 1 or 2 71 | XSERIES : string:="ULTRA" --! for 6/7 series: "7SERIES"; for ULTRASCALE: "ULTRA"; 72 | ); 73 | port ( 74 | RST : in std_logic; --! Global reset 75 | CLK : in std_logic; --! Rising edge DSP clock 76 | 77 | PHI_ENA : in std_logic; --! Phase valid signal 78 | OUT_SIN : out std_logic_vector(DATA_WIDTH-1 downto 0); -- Sine output 79 | OUT_COS : out std_logic_vector(DATA_WIDTH-1 downto 0) -- Cosine output 80 | ); 81 | end entity; 82 | 83 | architecture taylor_sincos of taylor_sincos is 84 | 85 | ---- Constant declaration ---- 86 | constant ROM_DEPTH : integer := 2**LUT_SIZE; 87 | 88 | ---- Create ROM array via HDL-function by using MATH package ---- 89 | type std_array_RxN is array (0 to ROM_DEPTH-1) of std_logic_vector(2*DATA_WIDTH-1 downto 0); 90 | 91 | function rom_calculate(val_size : integer) return std_array_RxN is 92 | variable pi_new : real:=0.0; 93 | variable sc_int : std_array_RxN; 94 | 95 | variable re_int : integer:=0; 96 | variable im_int : integer:=0; 97 | begin 98 | for ii in 0 to ROM_DEPTH-1 loop 99 | pi_new := (real(ii) * MATH_PI) / (2.0 * real(ROM_DEPTH)); 100 | 101 | re_int := INTEGER((2.0**(DATA_WIDTH-1)-1.0) * cos(pi_new)); 102 | im_int := INTEGER((2.0**(DATA_WIDTH-1)-1.0) * sin(pi_new)); 103 | 104 | sc_int(ii)(2*DATA_WIDTH-1 downto 1*DATA_WIDTH) := STD_LOGIC_VECTOR(CONV_SIGNED(im_int, DATA_WIDTH)); 105 | sc_int(ii)(1*DATA_WIDTH-1 downto 0*DATA_WIDTH) := STD_LOGIC_VECTOR(CONV_SIGNED(re_int, DATA_WIDTH)); 106 | end loop; 107 | 108 | return sc_int; 109 | end rom_calculate; 110 | 111 | constant ROM_ARRAY : std_array_RxN := rom_calculate(LUT_SIZE); 112 | 113 | ---- Phase counter and quadrant ---- 114 | signal cnt : std_logic_vector(PHASE_WIDTH-1 downto 0); 115 | signal addr : std_logic_vector(LUT_SIZE-1 downto 0); 116 | signal quadrant : std_logic_vector(1 downto 0); 117 | signal selq : std_logic_vector(1 downto 0); 118 | 119 | ---- Output mem & registers ---- 120 | signal dpo : std_logic_vector(2*DATA_WIDTH-1 downto 0); 121 | signal mem_sin : std_logic_vector(DATA_WIDTH-1 downto 0); 122 | signal mem_cos : std_logic_vector(DATA_WIDTH-1 downto 0); 123 | 124 | ---- Select RAM type: Distributed or Block ---- 125 | function calc_string(xx : integer) return string is 126 | begin 127 | if (xx < 10) then -- 11 or 12 128 | return "distributed"; 129 | else 130 | return "block"; 131 | end if; 132 | end calc_string; 133 | 134 | constant RAMB_TYPE : string:=calc_string(LUT_SIZE); 135 | 136 | attribute rom_style: string; 137 | attribute rom_style of dpo : signal is RAMB_TYPE; 138 | 139 | begin 140 | ---- Select quadrant ---- 141 | quadrant <= cnt(PHASE_WIDTH-1 downto PHASE_WIDTH-2); 142 | 143 | ---- Phase counter ---- 144 | pr_cnt: process(clk) is 145 | begin 146 | if rising_edge(clk) then 147 | if (rst = '1') then 148 | cnt <= (others => '0'); 149 | elsif (phi_ena = '1') then 150 | cnt <= cnt + '1'; 151 | end if; 152 | end if; 153 | end process; 154 | 155 | ---- Sddress for ROM depends on phase width and lut size ----- 156 | ---- Phase width less than lut size ---- 157 | xGEN_LESS: if ((PHASE_WIDTH - LUT_SIZE) < 2) generate 158 | begin 159 | addr(LUT_SIZE-1 downto LUT_SIZE-PHASE_WIDTH+2) <= cnt(PHASE_WIDTH-3 downto 0) when rising_edge(clk); 160 | addr(LUT_SIZE-PHASE_WIDTH+1 downto 0) <= (others=>'0'); 161 | end generate; 162 | 163 | ---- Phase width equal lut size ---- 164 | xGEN_EQ: if ((PHASE_WIDTH - LUT_SIZE) = 2) generate 165 | begin 166 | addr <= cnt(LUT_SIZE-1 downto 0) when rising_edge(clk); 167 | end generate; 168 | ---- Phase width more than lut size ---- 169 | xGEN_MORE: if ((PHASE_WIDTH - LUT_SIZE) > 2) generate 170 | signal acnt : std_logic_vector(PHASE_WIDTH-LUT_SIZE-3 downto 0); 171 | signal tay_dat : std_logic_vector(2*DATA_WIDTH-1 downto 0); 172 | 173 | ---- Addition delay for 1-order Taylor series ---- 174 | function find_delay(xx: in integer) return integer is 175 | variable ret : integer:=0; 176 | begin 177 | if (xx < 19) then 178 | ret := 5; 179 | else 180 | ret := 8; 181 | end if; 182 | return ret; 183 | end; 184 | constant ADD_DELAY : integer:=find_delay(DATA_WIDTH); 185 | 186 | type std_logic_delN is array (ADD_DELAY downto 0) of std_logic_vector(1 downto 0); 187 | signal quad : std_logic_delN; 188 | 189 | begin 190 | addr <= cnt(PHASE_WIDTH-3 downto PHASE_WIDTH-LUT_SIZE-2);-- when rising_edge(clk); 191 | acnt <= cnt(PHASE_WIDTH-3-LUT_SIZE downto 0);-- when rising_edge(clk); 192 | 193 | ---- 1st order Taylor scheme ---- 194 | xTAY1: entity work.tay1_order 195 | generic map ( 196 | DATA_WIDTH => DATA_WIDTH, 197 | USE_MLT => FALSE, 198 | VAL_SHIFT => LUT_SIZE, 199 | XSERIES => XSERIES, 200 | STAGE => PHASE_WIDTH-LUT_SIZE-3 201 | ) 202 | port map ( 203 | rom_dat => dpo, 204 | rom_cnt => acnt, 205 | 206 | dsp_dat => tay_dat, 207 | 208 | clk => clk, 209 | rst => rst 210 | ); 211 | 212 | 213 | ---- 2nd order Taylor scheme ---- 214 | ---- *DELETED* ---- 215 | 216 | mem_sin <= tay_dat(2*DATA_WIDTH-1 downto 1*DATA_WIDTH) when rising_edge(clk); 217 | mem_cos <= tay_dat(1*DATA_WIDTH-1 downto 0*DATA_WIDTH) when rising_edge(clk); 218 | 219 | quad <= quad(quad'left-1 downto 0) & quadrant when rising_edge(clk); 220 | selq <= quad(quad'left); 221 | end generate; 222 | 223 | xGEN_OUT: if ((PHASE_WIDTH - LUT_SIZE) <= 2) generate 224 | type std_logic_delN is array (2 downto 0) of std_logic_vector(1 downto 0); 225 | signal quad : std_logic_delN; 226 | begin 227 | mem_sin <= dpo(2*DATA_WIDTH-1 downto 1*DATA_WIDTH) when rising_edge(clk); 228 | mem_cos <= dpo(1*DATA_WIDTH-1 downto 0*DATA_WIDTH) when rising_edge(clk); 229 | 230 | quad <= quad(quad'left-1 downto 0) & quadrant when rising_edge(clk); 231 | selq <= quad(quad'left); 232 | end generate; 233 | 234 | dpo <= ROM_ARRAY(conv_integer(UNSIGNED(addr))) when rising_edge(clk); 235 | 236 | ---- Output data ---- 237 | pr_quad: process(clk) is 238 | begin 239 | if rising_edge(clk) then 240 | case selq is 241 | when "00" => 242 | out_sin <= mem_sin; 243 | out_cos <= mem_cos; 244 | when "01" => 245 | out_sin <= mem_cos; 246 | out_cos <= NOT(mem_sin) + '1'; 247 | when "10" => 248 | out_sin <= NOT(mem_sin) + '1'; 249 | out_cos <= NOT(mem_cos) + '1'; 250 | when others => 251 | out_sin <= NOT(mem_cos) + '1'; 252 | out_cos <= mem_sin; 253 | end case; 254 | end if; 255 | end process; 256 | 257 | end architecture; -------------------------------------------------------------------------------- /src/cordic_atan2.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : cordic_atan2 4 | -- Design : Blackman-Harris Windows 5 | -- Author : Kapitanov Alexander 6 | -- Company : 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | -- Description : Simple cordic algorithm for sine and cosine generator (DDS) 10 | -- 11 | ------------------------------------------------------------------------------- 12 | -- 13 | -- Version 1.0 30.08.2018 14 | -- Description: Cordic for calc ATAN2(X,Y) function {-pi : pi} 15 | -- 16 | -- Phase radians - Look up table array ROM [WIDTH-1 : 0] 17 | -- Formula: Angle = Round[atan(2^-i) * (2^48/(2*pi))] where i - variable of ROM array 18 | -- 19 | -- Gain for output signal is production of: 20 | -- Gain = PROD[ SQRT(1.0+2.0**(-2*i)) ], where i = 0 to ANGLE_WIDTH. 21 | -- 22 | -- Example: WIDTH = 16: create ROM array from 0 to 14: 23 | -- { 0x2000, 0x12E4, 0x09FB, 0x0511, 0x028B, 0x0146, 0x00A3, 0x0051 24 | -- 0x0029, 0x0014, 0x000A, 0x0005, 0x0003, 0x0001, 0x0000 } 25 | -- 26 | -- The fixed-point CORDIC requires: 27 | -- > 1 LUT, 28 | -- > 2 shifts, 29 | -- > 3 additions, 30 | -- per iteration. 31 | -- 32 | ------------------------------------------------------------------------------- 33 | ------------------------------------------------------------------------------- 34 | -- 35 | -- GNU GENERAL PUBLIC LICENSE 36 | -- Version 3, 29 June 2007 37 | -- 38 | -- Copyright (c) 2018 Kapitanov Alexander 39 | -- 40 | -- This program is free software: you can redistribute it and/or modify 41 | -- it under the terms of the GNU General Public License as published by 42 | -- the Free Software Foundation, either version 3 of the License, or 43 | -- (at your option) any later version. 44 | -- 45 | -- You should have received a copy of the GNU General Public License 46 | -- along with this program. If not, see . 47 | -- 48 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 49 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 50 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 51 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 52 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 53 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 54 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 55 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 56 | -- 57 | ------------------------------------------------------------------------------- 58 | ------------------------------------------------------------------------------- 59 | library ieee; 60 | use ieee.std_logic_1164.all; 61 | use ieee.std_logic_arith.all; 62 | use ieee.std_logic_signed.all; 63 | 64 | entity cordic_atan2 is 65 | generic ( 66 | PRECISION : integer := 1; --! Data precision: from 1 to 7, avg = 2-4 67 | INPUT_WIDTH : integer := 20;-- Input width: sets number of bits in X/Y vectors 68 | ANGLE_WIDTH : integer := 24 -- Output width: sets magnitude of angle 69 | ); 70 | port ( 71 | CLK : in std_logic; --! Clock source 72 | RESET : in std_logic; --! Positive reset: '1' - reset, '0' - calculate 73 | VEC_DX : in std_logic_vector(INPUT_WIDTH-1 downto 0); --! Input X coordinate 74 | VEC_DY : in std_logic_vector(INPUT_WIDTH-1 downto 0); --! Input Y coordinate 75 | VEC_EN : in std_logic; --! Input phase enable 76 | PHI_DT : out std_logic_vector(ANGLE_WIDTH-1 downto 0); --! Output angle 77 | PHI_VL : out std_logic --! Output data valid 78 | ); 79 | end cordic_atan2; 80 | 81 | architecture cordic_atan2 of cordic_atan2 is 82 | 83 | ---------------- ROM: Look up table for CORDIC ---------------- 84 | ---- Result of [ATAN(2^-i) * (2^47/MATH_PI)] rounded and converted to HEX 85 | type rom_array is array (0 to 47) of std_logic_vector(47 downto 0); 86 | 87 | constant ROM_LUT : rom_array := ( 88 | x"400000000000", x"25C80A3B3BE6", x"13F670B6BDC7", x"0A2223A83BBB", x"05161A861CB1", x"028BAFC2B209", 89 | x"0145EC3CB850", x"00A2F8AA23A9", x"00517CA68DA2", x"0028BE5D7661", x"00145F300123", x"000A2F982950", 90 | x"000517CC19C0", x"00028BE60D83", x"000145F306D6", x"0000A2F9836D", x"0000517CC1B7", x"000028BE60DC", 91 | x"0000145F306E", x"00000A2F9837", x"00000517CC1B", x"0000028BE60E", x"00000145F307", x"000000A2F983", 92 | x"000000517CC2", x"00000028BE61", x"000000145F30", x"0000000A2F98", x"0000000517CC", x"000000028BE6", 93 | x"0000000145F3", x"00000000A2FA", x"00000000517D", x"0000000028BE", x"00000000145F", x"000000000A30", 94 | x"000000000518", x"00000000028C", x"000000000146", x"0000000000A3", x"000000000051", x"000000000029", 95 | x"000000000014", x"00000000000A", x"000000000005", x"000000000003", x"000000000001", x"000000000000" 96 | ); 97 | 98 | type rom_atan is array (0 to ANGLE_WIDTH-2) of std_logic_vector(ANGLE_WIDTH+PRECISION-1 downto 0); 99 | 100 | function func_atan return rom_atan is 101 | variable ret : rom_atan; 102 | begin 103 | for ii in 0 to ANGLE_WIDTH-2 loop 104 | ret(ii)(ANGLE_WIDTH+PRECISION-2 downto 0) := ROM_LUT(ii)(47 downto (47-(ANGLE_WIDTH+PRECISION-2))); 105 | ret(ii)(ANGLE_WIDTH+PRECISION-1 downto ANGLE_WIDTH+PRECISION-1) := (others => '0'); 106 | end loop; 107 | return ret; 108 | end function func_atan; 109 | 110 | constant ROM_TABLE : rom_atan := func_atan; 111 | 112 | ---------------- Signal declaration ---------------- 113 | type dat_array is array (0 to ANGLE_WIDTH-1) of std_logic_vector(ANGLE_WIDTH+PRECISION-1 downto 0); 114 | type phi_array is array (0 to ANGLE_WIDTH-1) of std_logic_vector(ANGLE_WIDTH+PRECISION-1 downto 0); 115 | 116 | constant PHI_PI : std_logic_vector(ANGLE_WIDTH-1 downto 0):=(ANGLE_WIDTH-2 => '1', others => '0'); 117 | 118 | signal sigX : dat_array := (others => (others => '0')); 119 | signal sigY : dat_array := (others => (others => '0')); 120 | signal sigZ : phi_array := (others => (others => '0')); 121 | 122 | signal init_x : std_logic_vector(ANGLE_WIDTH+PRECISION-1 downto 0); 123 | signal init_y : std_logic_vector(ANGLE_WIDTH+PRECISION-1 downto 0); 124 | signal init_z : std_logic_vector(ANGLE_WIDTH+PRECISION-1 downto 0); 125 | 126 | signal quadrant : std_logic_vector(1 downto 0); 127 | signal quadz1 : std_logic_vector(ANGLE_WIDTH-1 downto 0); 128 | signal quadz2 : std_logic_vector(ANGLE_WIDTH-1 downto 0); 129 | signal dt_vld : std_logic_vector(ANGLE_WIDTH-1 downto 0); 130 | 131 | signal dat_phi : std_logic_vector(ANGLE_WIDTH-1 downto 0); 132 | 133 | begin 134 | 135 | --------------------------------------------------------------------- 136 | ---------------- Calculate Quadrant: two MSBs of input phase -------- 137 | --------------------------------------------------------------------- 138 | quadz1 <= quadz1(ANGLE_WIDTH-2 downto 0) & VEC_DX(INPUT_WIDTH-1) when rising_edge(clk); 139 | quadz2 <= quadz2(ANGLE_WIDTH-2 downto 0) & VEC_DY(INPUT_WIDTH-1) when rising_edge(clk); 140 | quadrant <= quadz1(ANGLE_WIDTH-1) & quadz2(ANGLE_WIDTH-1); 141 | 142 | --------------------------------------------------------------------- 143 | ---------------- Registered: initial values for X, Y, Z ------------- 144 | --------------------------------------------------------------------- 145 | 146 | pr_abs: process(clk) is 147 | begin 148 | if rising_edge(clk) then 149 | xl: for ii in 0 to ANGLE_WIDTH-2 loop 150 | init_x(ii) <= VEC_DX(ii) xor VEC_DX(INPUT_WIDTH-1); 151 | init_y(ii) <= VEC_DY(ii) xor VEC_DY(INPUT_WIDTH-1); 152 | end loop; 153 | init_x(ANGLE_WIDTH+PRECISION-1 downto ANGLE_WIDTH-1) <= (others=>'0'); 154 | init_y(ANGLE_WIDTH+PRECISION-1 downto ANGLE_WIDTH-1) <= (others=>'0'); 155 | end if; 156 | end process; 157 | 158 | 159 | init_z <= (others=>'0'); 160 | 161 | --------------------------------------------------------------------- 162 | ---------------- Compute Angle array and X/Y ------------------------ 163 | --------------------------------------------------------------------- 164 | pr_crd: process(clk) is 165 | begin 166 | if rising_edge(clk) then 167 | if (reset = '1') then 168 | ---- Reset sine / cosine / angle vector ---- 169 | sigX <= (others => (others => '0')); 170 | sigY <= (others => (others => '0')); 171 | sigZ <= (others => (others => '0')); 172 | else 173 | sigX(0) <= init_x; 174 | sigY(0) <= init_y; 175 | sigZ(0) <= init_z; 176 | ---- calculate sine & cosine ---- 177 | lpXY: for ii in 0 to ANGLE_WIDTH-2 loop 178 | if (sigY(ii)(sigY(ii)'left) = '0') then 179 | sigX(ii+1) <= sigX(ii) + sigY(ii)(ANGLE_WIDTH+PRECISION-1 downto ii); 180 | sigY(ii+1) <= sigY(ii) - sigX(ii)(ANGLE_WIDTH+PRECISION-1 downto ii); 181 | else 182 | sigX(ii+1) <= sigX(ii) - sigY(ii)(ANGLE_WIDTH+PRECISION-1 downto ii); 183 | sigY(ii+1) <= sigY(ii) + sigX(ii)(ANGLE_WIDTH+PRECISION-1 downto ii); 184 | end if; 185 | end loop; 186 | ---- calculate phase ---- 187 | lpZ: for ii in 0 to ANGLE_WIDTH-2 loop 188 | if (sigY(ii)(sigY(ii)'left) = '1') then 189 | sigZ(ii+1) <= sigZ(ii) + ROM_TABLE(ii); 190 | else 191 | sigZ(ii+1) <= sigZ(ii) - ROM_TABLE(ii); 192 | end if; 193 | end loop; 194 | end if; 195 | end if; 196 | end process; 197 | 198 | dat_phi <= sigZ(ANGLE_WIDTH-1)(ANGLE_WIDTH+PRECISION-1 downto PRECISION); 199 | 200 | dt_vld <= dt_vld(dt_vld'left-1 downto 0) & VEC_EN when rising_edge(clk); 201 | PHI_VL <= dt_vld(dt_vld'left); 202 | 203 | ---- Output data ---- 204 | pr_xy: process(clk) is 205 | begin 206 | if rising_edge(clk) then 207 | if (reset = '1') then 208 | PHI_DT <= (others => '0'); 209 | else 210 | case quadrant is 211 | when "00" => PHI_DT <= dat_phi; 212 | when "01" => PHI_DT <= dat_phi + PHI_PI; 213 | when "10" => PHI_DT <= not(dat_phi) + '1'; 214 | when "11" => PHI_DT <= dat_phi - PHI_PI; 215 | when others => null; 216 | end case; 217 | end if; 218 | end if; 219 | end process; 220 | 221 | end cordic_atan2; -------------------------------------------------------------------------------- /src/bh_win_4term.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : bh_win_4term 4 | -- Design : Blackman-Harris Windows 5 | -- Author : Kapitanov Alexander 6 | -- Company : 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | -- Description : Simple Blackman-Harris window function: 4- term 10 | -- Configurable data length and number of terms. 11 | -- 12 | -- Constants {0-3} (gain for harmonics): type - REAL (float IEEE-754) 13 | -- 14 | -- > Blackman-Harris: 15 | -- a0 = 0.35875, a1 = 0.48829, a2 = 0.14128, a3 = 0.01168. 16 | -- > Nuttall: 17 | -- a0 = 0.355768, a1 = 0.487396, a2 = 0.144323, a3 = 0.012604. 18 | -- > Blackman-Nuttall: 19 | -- a0 = 0.3635819, a1 = 0.4891775, a2 = 0.1365995, a3 = 0.0106411. 20 | -- 21 | ------------------------------------------------------------------------------- 22 | ------------------------------------------------------------------------------- 23 | -- 24 | -- GNU GENERAL PUBLIC LICENSE 25 | -- Version 3, 29 June 2007 26 | -- 27 | -- Copyright (c) 2018 Kapitanov Alexander 28 | -- 29 | -- This program is free software: you can redistribute it and/or modify 30 | -- it under the terms of the GNU General Public License as published by 31 | -- the Free Software Foundation, either version 3 of the License, or 32 | -- (at your option) any later version. 33 | -- 34 | -- You should have received a copy of the GNU General Public License 35 | -- along with this program. If not, see . 36 | -- 37 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 38 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 39 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 40 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 41 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 42 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 43 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 44 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 45 | -- 46 | ------------------------------------------------------------------------------- 47 | library ieee; 48 | use ieee.std_logic_1164.all; 49 | use ieee.std_logic_arith.all; 50 | use ieee.std_logic_signed.all; 51 | 52 | -- library unisim; 53 | -- use unisim.vcomponents.DSP48E1; 54 | -- use unisim.vcomponents.DSP48E2; 55 | 56 | entity bh_win_4term is 57 | generic ( 58 | TD : time:=0.5ns; --! Time delay 59 | PHI_WIDTH : integer:=10; --! Signal period = 2^PHI_WIDTH 60 | DAT_WIDTH : integer:=16 --! Output data width 61 | ); 62 | port ( 63 | RESET : in std_logic; --! Global reset 64 | CLK : in std_logic; --! System clock 65 | 66 | AA0 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A0 67 | AA1 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A1 68 | AA2 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A2 69 | AA3 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A3 70 | 71 | ENABLE : in std_logic; --! Input data enable block = NFFT clocks 72 | DT_WIN : out std_logic_vector(DAT_WIDTH-1 downto 0); --! Output (cos) 73 | DT_VLD : out std_logic --! Output data valid 74 | ); 75 | end bh_win_4term; 76 | 77 | architecture bh_win_4term of bh_win_4term is 78 | 79 | ---------------- Cordic signals ---------------- 80 | signal cos1 : std_logic_vector(DAT_WIDTH-1 downto 0); 81 | signal cos2 : std_logic_vector(DAT_WIDTH-1 downto 0); 82 | signal cos3 : std_logic_vector(DAT_WIDTH-1 downto 0); 83 | 84 | signal ph_in1 : std_logic_vector(PHI_WIDTH-1 downto 0); 85 | signal ph_in2 : std_logic_vector(PHI_WIDTH-1 downto 0); 86 | signal ph_in3 : std_logic_vector(PHI_WIDTH-1 downto 0); 87 | 88 | ---------------- Multiplier signals ---------------- 89 | signal mult_a1 : std_logic_vector(DAT_WIDTH-1 downto 0); 90 | signal mult_a2 : std_logic_vector(DAT_WIDTH-1 downto 0); 91 | signal mult_a3 : std_logic_vector(DAT_WIDTH-1 downto 0); 92 | 93 | signal mult_b1 : std_logic_vector(DAT_WIDTH-1 downto 0); 94 | signal mult_b2 : std_logic_vector(DAT_WIDTH-1 downto 0); 95 | signal mult_b3 : std_logic_vector(DAT_WIDTH-1 downto 0); 96 | 97 | signal mult_p1 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 98 | signal mult_p2 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 99 | signal mult_p3 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 100 | 101 | ---------------- Product signals ---------------- 102 | signal dsp_b0 : std_logic_vector(DAT_WIDTH-1 downto 0); 103 | signal dsp_b1 : std_logic_vector(DAT_WIDTH-1 downto 0); 104 | signal dsp_b2 : std_logic_vector(DAT_WIDTH-1 downto 0); 105 | signal dsp_b3 : std_logic_vector(DAT_WIDTH-1 downto 0); 106 | 107 | signal dsp_r1 : std_logic_vector(DAT_WIDTH downto 0); 108 | signal dsp_r2 : std_logic_vector(DAT_WIDTH downto 0); 109 | signal dsp_r3 : std_logic_vector(DAT_WIDTH downto 0); 110 | 111 | ---------------- DSP48 signals ---------------- 112 | signal dsp_p1 : std_logic_vector(DAT_WIDTH downto 0); 113 | signal dsp_p2 : std_logic_vector(DAT_WIDTH downto 0); 114 | signal dsp_pp : std_logic_vector(DAT_WIDTH+1 downto 0); 115 | -- signal vldx : std_logic; 116 | signal ena_zz : std_logic_vector(DAT_WIDTH+8 downto 0); 117 | 118 | attribute USE_DSP : string; 119 | attribute USE_DSP of dsp_pp : signal is "YES"; 120 | attribute USE_DSP of dsp_p1 : signal is "YES"; 121 | attribute USE_DSP of dsp_p2 : signal is "YES"; 122 | 123 | begin 124 | 125 | ---------------- Multiplier ---------------- 126 | mult_a1 <= AA1 after td when rising_edge(clk); 127 | mult_a2 <= AA2 after td when rising_edge(clk); 128 | mult_a3 <= AA3 after td when rising_edge(clk); 129 | 130 | mult_b1 <= cos1 after td when rising_edge(clk); 131 | mult_b2 <= cos2 after td when rising_edge(clk); 132 | mult_b3 <= cos3 after td when rising_edge(clk); 133 | 134 | ---------------- Counter for phase ---------------- 135 | PR_CNT1: process(clk) is 136 | begin 137 | if rising_edge(clk) then 138 | if (reset = '1') then 139 | ph_in1 <= (others => '0') after TD; 140 | ph_in2 <= (others => '0') after TD; 141 | ph_in3 <= (others => '0') after TD; 142 | else 143 | if (ENABLE = '1') then 144 | ph_in1 <= ph_in1 + 1 after TD; 145 | ph_in2 <= ph_in2 + 2 after TD; 146 | ph_in3 <= ph_in3 + 3 after TD; 147 | end if; 148 | end if; 149 | end if; 150 | end process; 151 | 152 | ---------------- Twiddle part 1 ---------------- 153 | xCRD1: entity work.cordic_dds 154 | generic map ( 155 | DATA_WIDTH => DAT_WIDTH, 156 | PHASE_WIDTH => PHI_WIDTH 157 | ) 158 | port map ( 159 | RESET => reset, 160 | CLK => clk, 161 | PH_IN => ph_in1, 162 | PH_EN => ENABLE, 163 | DT_COS => cos1 164 | ); 165 | ---------------- Twiddle part 2 ---------------- 166 | xCRD2: entity work.cordic_dds 167 | generic map ( 168 | DATA_WIDTH => DAT_WIDTH, 169 | PHASE_WIDTH => PHI_WIDTH 170 | ) 171 | port map ( 172 | RESET => reset, 173 | CLK => clk, 174 | PH_IN => ph_in2, 175 | PH_EN => ENABLE, 176 | DT_COS => cos2 177 | ); 178 | ---------------- Twiddle part 3 ---------------- 179 | xCRD3: entity work.cordic_dds 180 | generic map ( 181 | DATA_WIDTH => DAT_WIDTH, 182 | PHASE_WIDTH => PHI_WIDTH 183 | ) 184 | port map ( 185 | RESET => reset, 186 | CLK => clk, 187 | PH_IN => ph_in3, 188 | PH_EN => ENABLE, 189 | DT_COS => cos3 190 | ); 191 | 192 | xMLT1: entity work.int_multNxN_dsp48 193 | generic map ( DTW => DAT_WIDTH) 194 | port map ( 195 | DAT_A => mult_a1, 196 | DAT_B => mult_b1, 197 | DAT_Q => mult_p1, 198 | CLK => clk, 199 | RST => reset 200 | ); 201 | 202 | xMLT2: entity work.int_multNxN_dsp48 203 | generic map ( DTW => DAT_WIDTH) 204 | port map ( 205 | DAT_A => mult_a2, 206 | DAT_B => mult_b2, 207 | DAT_Q => mult_p2, 208 | CLK => clk, 209 | RST => reset 210 | ); 211 | 212 | xMLT3: entity work.int_multNxN_dsp48 213 | generic map ( DTW => DAT_WIDTH) 214 | port map ( 215 | DAT_A => mult_a3, 216 | DAT_B => mult_b3, 217 | DAT_Q => mult_p3, 218 | CLK => clk, 219 | RST => reset 220 | ); 221 | 222 | ---------------- DSP48E2 1-2 ---------------- 223 | dsp_b0 <= AA0 after td when rising_edge(clk); 224 | 225 | dsp_r1 <= mult_p1(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 226 | dsp_r2 <= mult_p2(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 227 | dsp_r3 <= mult_p3(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 228 | 229 | ---------------- Round data from 25 to 24 bits ---------------- 230 | pr_rnd: process(clk) is 231 | begin 232 | if rising_edge(clk) then 233 | ---- Round 1 ---- 234 | if (dsp_r1(0) = '0') then 235 | dsp_b1 <= dsp_r1(DAT_WIDTH downto 1) after td; 236 | else 237 | dsp_b1 <= dsp_r1(DAT_WIDTH downto 1) + 1 after td; 238 | end if; 239 | ---- Round 2 ---- 240 | if (dsp_r2(0) = '0') then 241 | dsp_b2 <= dsp_r2(DAT_WIDTH downto 1) after td; 242 | else 243 | dsp_b2 <= dsp_r2(DAT_WIDTH downto 1) + 1 after td; 244 | end if; 245 | ---- Round 3 ---- 246 | if (dsp_r3(0) = '0') then 247 | dsp_b3 <= dsp_r3(DAT_WIDTH downto 1) after td; 248 | else 249 | dsp_b3 <= dsp_r3(DAT_WIDTH downto 1) + 1 after td; 250 | end if; 251 | 252 | end if; 253 | end process; 254 | 255 | ---------------- DSP48 signal mapping ---------------- 256 | pr_add: process(clk) is 257 | begin 258 | if rising_edge(clk) then 259 | dsp_p1 <= (dsp_b2(DAT_WIDTH-1) & dsp_b2) - (dsp_b3(DAT_WIDTH-1) & dsp_b3); 260 | dsp_p2 <= (dsp_b0(DAT_WIDTH-1) & dsp_b0) - (dsp_b1(DAT_WIDTH-1) & dsp_b1); 261 | dsp_pp <= (dsp_p1(DAT_WIDTH) & dsp_p1) + 262 | (dsp_p2(DAT_WIDTH) & dsp_p2); 263 | end if; 264 | end process; 265 | 266 | ena_zz <= ena_zz(ena_zz'left-1 downto 0) & enable after td when rising_edge(clk); 267 | 268 | ---------------- Round output data from N+1 to N bits ---------------- 269 | pr_out: process(clk) is 270 | begin 271 | if rising_edge(clk) then 272 | ---- Round 1 ---- 273 | if (dsp_pp(1) = '0') then 274 | DT_WIN <= dsp_pp(DAT_WIDTH+1 downto 2) after td; 275 | else 276 | DT_WIN <= dsp_pp(DAT_WIDTH+1 downto 2) + 1 after td; 277 | end if; 278 | DT_VLD <= ena_zz(ena_zz'left) after td; 279 | end if; 280 | end process; 281 | 282 | end bh_win_4term; -------------------------------------------------------------------------------- /src/bh_win_3term.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : bh_win_3term 4 | -- Design : Blackman-Harris Windows 5 | -- Author : Kapitanov Alexander 6 | -- Company : 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | -- Description : Simple Blackman-Harris window function: 3- term 10 | -- Configurable data length and number of terms. 11 | -- 12 | -- Constants {0-2} (gain for harmonics): type - REAL (float IEEE-754) 13 | -- AA_FLT0 = (1 - alpha)/2; 14 | -- AA_FLT1 = 1/2; 15 | -- AA_FLT2 = alpha/2; 16 | -- 17 | -- where: 18 | -- 19 | -- a0 = 0.42, a1 = 0.5, a2 = 0.08. (alpha = 0.16) Side-lobe level 58 dB. 20 | -- a0 = 0.4243801, a1 = 0.4973406, a2 = 0.0782793). Side-lobe level 71.48 dB. 21 | -- 22 | -- Parameters: 23 | -- PHI_WIDTH - Signal period = 2^PHI_WIDTH 24 | -- DAT_WIDTH - Output data width 25 | -- SIN_TYPE -Sine generator type: CORDIC / TAYLOR 26 | -- ---- For Taylor series only ---- 27 | -- LUT_SIZE - ROM depth for sin/cos (must be less than PHASE_WIDTH) 28 | -- XSERIES - for 6/7 series: "7SERIES"; for ULTRASCALE: "ULTRA"; 29 | -- 30 | -- Note: While using TAYLOR scheme You must set LUT_SIZE < (PHASE_WIDTH - 3) 31 | -- for correct delays. 32 | -- 33 | ------------------------------------------------------------------------------- 34 | ------------------------------------------------------------------------------- 35 | -- 36 | -- GNU GENERAL PUBLIC LICENSE 37 | -- Version 3, 29 June 2007 38 | -- 39 | -- Copyright (c) 2018 Kapitanov Alexander 40 | -- 41 | -- This program is free software: you can redistribute it and/or modify 42 | -- it under the terms of the GNU General Public License as published by 43 | -- the Free Software Foundation, either version 3 of the License, or 44 | -- (at your option) any later version. 45 | -- 46 | -- You should have received a copy of the GNU General Public License 47 | -- along with this program. If not, see . 48 | -- 49 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 50 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 51 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 52 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 53 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 54 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 55 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 56 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 57 | -- 58 | ------------------------------------------------------------------------------- 59 | library ieee; 60 | use ieee.std_logic_1164.all; 61 | use ieee.std_logic_arith.all; 62 | use ieee.std_logic_signed.all; 63 | 64 | -- library unisim; 65 | -- use unisim.vcomponents.DSP48E1; 66 | -- use unisim.vcomponents.DSP48E2; 67 | 68 | entity bh_win_3term is 69 | generic ( 70 | TD : time:=0.5ns; --! Time delay 71 | PHI_WIDTH : integer:=10; --! Signal period = 2^PHI_WIDTH 72 | DAT_WIDTH : integer:=16; --! Output data width 73 | SIN_TYPE : string:="CORDIC"; --! Sine generator type: CORDIC / TAYLOR 74 | ---- For Taylor series only ---- 75 | LUT_SIZE : integer:= 9; --! ROM depth for sin/cos (must be less than PHASE_WIDTH) 76 | XSERIES : string:="ULTRA" --! for 6/7 series: "7SERIES"; for ULTRASCALE: "ULTRA"; 77 | ); 78 | port ( 79 | RESET : in std_logic; --! Global reset 80 | CLK : in std_logic; --! System clock 81 | 82 | AA0 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A0 83 | AA1 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A1 84 | AA2 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A2 85 | 86 | ENABLE : in std_logic; --! Input data enable block = NFFT clocks 87 | DT_WIN : out std_logic_vector(DAT_WIDTH-1 downto 0); --! Output (cos) 88 | DT_VLD : out std_logic --! Output data valid 89 | ); 90 | end bh_win_3term; 91 | 92 | architecture bh_win_3term of bh_win_3term is 93 | 94 | ---------------- Cordic signals ---------------- 95 | signal cos1 : std_logic_vector(DAT_WIDTH-1 downto 0); 96 | signal cos2 : std_logic_vector(DAT_WIDTH-1 downto 0); 97 | 98 | signal ph_in1 : std_logic_vector(PHI_WIDTH-1 downto 0); 99 | signal ph_in2 : std_logic_vector(PHI_WIDTH-1 downto 0); 100 | 101 | ---------------- Multiplier signals ---------------- 102 | signal mult_a1 : std_logic_vector(DAT_WIDTH-1 downto 0); 103 | signal mult_a2 : std_logic_vector(DAT_WIDTH-1 downto 0); 104 | 105 | signal mult_b1 : std_logic_vector(DAT_WIDTH-1 downto 0); 106 | signal mult_b2 : std_logic_vector(DAT_WIDTH-1 downto 0); 107 | 108 | signal mult_p1 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 109 | signal mult_p2 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 110 | 111 | ---------------- Product signals ---------------- 112 | signal dsp_b0 : std_logic_vector(DAT_WIDTH-1 downto 0); 113 | signal dsp_b1 : std_logic_vector(DAT_WIDTH-1 downto 0); 114 | signal dsp_b2 : std_logic_vector(DAT_WIDTH-1 downto 0); 115 | 116 | signal dsp_r1 : std_logic_vector(DAT_WIDTH downto 0); 117 | signal dsp_r2 : std_logic_vector(DAT_WIDTH downto 0); 118 | 119 | ---------------- DSP48 signals ---------------- 120 | ---- Addition delay ---- 121 | function find_delay return integer is 122 | variable ret : integer:=0; 123 | begin 124 | if (SIN_TYPE = "CORDIC") then 125 | ret := DAT_WIDTH+7; 126 | elsif (SIN_TYPE = "TAYLOR") then 127 | if (PHI_WIDTH - LUT_SIZE <= 2) then 128 | ret := 10; 129 | else 130 | if (DAT_WIDTH < 19) then 131 | ret := 13; 132 | else 133 | ret := 16; 134 | end if; 135 | end if; 136 | end if; 137 | return ret; 138 | end find_delay; 139 | 140 | constant ADD_DELAY : integer:=find_delay; 141 | 142 | signal dsp_pp : std_logic_vector(DAT_WIDTH+1 downto 0); 143 | -- signal vldx : std_logic; 144 | signal ena_zz : std_logic_vector(ADD_DELAY downto 0); 145 | 146 | attribute USE_DSP : string; 147 | attribute USE_DSP of dsp_pp : signal is "YES"; 148 | 149 | begin 150 | 151 | ---------------- Multiplier ---------------- 152 | mult_a1 <= AA1 after td when rising_edge(clk); 153 | mult_a2 <= AA2 after td when rising_edge(clk); 154 | 155 | mult_b1 <= cos1 after td when rising_edge(clk); 156 | mult_b2 <= cos2 after td when rising_edge(clk); 157 | 158 | ---------------- Counter for phase ---------------- 159 | PR_CNT1: process(clk) is 160 | begin 161 | if rising_edge(clk) then 162 | if (reset = '1') then 163 | ph_in1 <= (others => '0') after TD; 164 | ph_in2 <= (others => '0') after TD; 165 | else 166 | if (ENABLE = '1') then 167 | ph_in1 <= ph_in1 + 1 after TD; 168 | ph_in2 <= ph_in2 + 2 after TD; 169 | end if; 170 | end if; 171 | end if; 172 | end process; 173 | 174 | ---------------- Cordic scheme ---------------- 175 | xUSE_CORD: if (SIN_TYPE = "CORDIC") generate 176 | ---------------- Twiddle part 1 ---------------- 177 | xCRD1: entity work.cordic_dds 178 | generic map ( 179 | DATA_WIDTH => DAT_WIDTH, 180 | PHASE_WIDTH => PHI_WIDTH 181 | ) 182 | port map ( 183 | RESET => reset, 184 | CLK => clk, 185 | PH_IN => ph_in1, 186 | PH_EN => ENABLE, 187 | DT_COS => cos1 188 | ); 189 | ---------------- Twiddle part 2 ---------------- 190 | xCRD2: entity work.cordic_dds 191 | generic map ( 192 | DATA_WIDTH => DAT_WIDTH, 193 | PHASE_WIDTH => PHI_WIDTH 194 | ) 195 | port map ( 196 | RESET => reset, 197 | CLK => clk, 198 | PH_IN => ph_in2, 199 | PH_EN => ENABLE, 200 | DT_COS => cos2 201 | ); 202 | end generate; 203 | 204 | ---------------- Taylor series scheme ---------------- 205 | xUSE_TAY: if (SIN_TYPE = "TAYLOR") generate 206 | ---------------- Twiddle part 1 ---------------- 207 | xTAY1: entity work.taylor_sincos 208 | generic map ( 209 | XSERIES => XSERIES, 210 | LUT_SIZE => LUT_SIZE, 211 | DATA_WIDTH => DAT_WIDTH, 212 | PHASE_WIDTH => PHI_WIDTH 213 | ) 214 | port map ( 215 | RST => reset, 216 | CLK => clk, 217 | PHI_ENA => ENABLE, 218 | OUT_COS => cos1 219 | ); 220 | ---------------- Twiddle part 2 ---------------- 221 | xTAY2: entity work.taylor_sincos 222 | generic map ( 223 | XSERIES => XSERIES, 224 | LUT_SIZE => LUT_SIZE, 225 | DATA_WIDTH => DAT_WIDTH, 226 | PHASE_WIDTH => PHI_WIDTH-1 227 | ) 228 | port map ( 229 | RST => reset, 230 | CLK => clk, 231 | PHI_ENA => ENABLE, 232 | OUT_COS => cos2 233 | ); 234 | end generate; 235 | 236 | ---------------- Weight constants ---------------- 237 | xMLT1: entity work.int_multNxN_dsp48 238 | generic map ( DTW => DAT_WIDTH) 239 | port map ( 240 | DAT_A => mult_a1, 241 | DAT_B => mult_b1, 242 | DAT_Q => mult_p1, 243 | CLK => clk, 244 | RST => reset 245 | ); 246 | 247 | xMLT2: entity work.int_multNxN_dsp48 248 | generic map ( DTW => DAT_WIDTH) 249 | port map ( 250 | DAT_A => mult_a2, 251 | DAT_B => mult_b2, 252 | DAT_Q => mult_p2, 253 | CLK => clk, 254 | RST => reset 255 | ); 256 | 257 | ---------------- DSP48E2 1-2 ---------------- 258 | dsp_b0 <= AA0 after td when rising_edge(clk); 259 | 260 | dsp_r1 <= mult_p1(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 261 | dsp_r2 <= mult_p2(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 262 | 263 | ---------------- Round data from 25 to 24 bits ---------------- 264 | pr_rnd: process(clk) is 265 | begin 266 | if rising_edge(clk) then 267 | ---- Round 1 ---- 268 | if (dsp_r1(0) = '0') then 269 | dsp_b1 <= dsp_r1(DAT_WIDTH downto 1) after td; 270 | else 271 | dsp_b1 <= dsp_r1(DAT_WIDTH downto 1) + 1 after td; 272 | end if; 273 | ---- Round 2 ---- 274 | if (dsp_r2(0) = '0') then 275 | dsp_b2 <= dsp_r2(DAT_WIDTH downto 1) after td; 276 | else 277 | dsp_b2 <= dsp_r2(DAT_WIDTH downto 1) + 1 after td; 278 | end if; 279 | end if; 280 | end process; 281 | 282 | ---------------- DSP48 signal mapping ---------------- 283 | pr_add: process(clk) is 284 | begin 285 | if rising_edge(clk) then 286 | dsp_pp <= (dsp_b2(DAT_WIDTH-1) & dsp_b2(DAT_WIDTH-1) & dsp_b2) - 287 | (dsp_b1(DAT_WIDTH-1) & dsp_b1(DAT_WIDTH-1) & dsp_b1) + 288 | (dsp_b0(DAT_WIDTH-1) & dsp_b0(DAT_WIDTH-1) & dsp_b0); 289 | end if; 290 | end process; 291 | 292 | ena_zz <= ena_zz(ena_zz'left-1 downto 0) & enable after td when rising_edge(clk); 293 | 294 | ---------------- Round output data from N+1 to N bits ---------------- 295 | pr_out: process(clk) is 296 | begin 297 | if rising_edge(clk) then 298 | ---- Round 1 ---- 299 | if (dsp_pp(1) = '0') then 300 | DT_WIN <= dsp_pp(DAT_WIDTH+1 downto 2) after td; 301 | else 302 | DT_WIN <= dsp_pp(DAT_WIDTH+1 downto 2) + 1 after td; 303 | end if; 304 | DT_VLD <= ena_zz(ena_zz'left) after td; 305 | end if; 306 | end process; 307 | 308 | end bh_win_3term; -------------------------------------------------------------------------------- /src/cordic_dds48.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : cordic_dds48 4 | -- Design : Blackman-Harris Windows 5 | -- Author : Kapitanov Alexander 6 | -- Company : 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | -- Description : Simple cordic algorithm for sine and cosine generator (DDS) 10 | -- 11 | ------------------------------------------------------------------------------- 12 | -- 13 | -- Version 1.0 30.08.2018 14 | -- Description: Cordic for sin/cos wave generator (DDS style) 15 | -- 16 | -- Coordinates: X represents the sine, Y represents the cosine, and 17 | -- Z represents theta. 18 | -- 19 | -- Cosine mode: 20 | -- x0 - initialized to 1/Magnitude = 1/2^(WIDTH); 21 | -- y0 - initialized to 0; 22 | -- z0 - initialized to the THETA input argument value (phase); 23 | -- 24 | -- Sine mode: 25 | -- x0 - initialized to 0; 26 | -- y0 - initialized to (+/-)1/Magnitude = 1/2^(WIDTH); 27 | -- z0 - initialized to the THETA input argument value (phase); 28 | -- 29 | -- Phase radians - Look up table array ROM [WIDTH-1 : 0] 30 | -- Formula: Angle = Round[atan(2^-i) * (2^48/(2*pi))] where i - variable of ROM array 31 | -- 32 | -- Gain for output signal is production of: 33 | -- Gain = PROD[ SQRT(1.0+2.0**(-2*i)) ] = 1.64676025812106541, 34 | -- where i = 0 to 47. 35 | -- 36 | -- ROM_LUT := ( 37 | -- x"200000000000", x"12E4051D9DF3", x"09FB385B5EE4", x"051111D41DDE", 38 | -- x"028B0D430E59", x"0145D7E15904", x"00A2F61E5C28", x"00517C5511D4", 39 | -- x"0028BE5346D1", x"00145F2EBB31", x"000A2F980092", x"000517CC14A8", 40 | -- x"00028BE60CE0", x"000145F306C1", x"0000A2F9836B", x"0000517CC1B7", 41 | -- x"000028BE60DC", x"0000145F306E", x"00000A2F9837", x"00000517CC1B", 42 | -- x"0000028BE60E", x"00000145F307", x"000000A2F983", x"000000517CC2", 43 | -- x"00000028BE61", x"000000145F30", x"0000000A2F98", x"0000000517CC", 44 | -- x"000000028BE6", x"0000000145F3", x"00000000A2FA", x"00000000517D", 45 | -- x"0000000028BE", x"00000000145F", x"000000000A30", x"000000000518", 46 | -- x"00000000028C", x"000000000146", x"0000000000A3", x"000000000051", 47 | -- x"000000000029", x"000000000014", x"00000000000A", x"000000000005", 48 | -- x"000000000003", x"000000000001", x"000000000001", x"000000000000" ); 49 | -- 50 | -- 51 | -- The fixed-point CORDIC requires: 52 | -- > 1 LUT, 53 | -- > 2 shifts, 54 | -- > 3 additions, 55 | -- per iteration. 56 | -- 57 | -- Internal data width and phase width are 48-bit vector. 58 | -- 59 | ------------------------------------------------------------------------------- 60 | ------------------------------------------------------------------------------- 61 | -- 62 | -- GNU GENERAL PUBLIC LICENSE 63 | -- Version 3, 29 June 2007 64 | -- 65 | -- Copyright (c) 2018 Kapitanov Alexander 66 | -- 67 | -- This program is free software: you can redistribute it and/or modify 68 | -- it under the terms of the GNU General Public License as published by 69 | -- the Free Software Foundation, either version 3 of the License, or 70 | -- (at your option) any later version. 71 | -- 72 | -- You should have received a copy of the GNU General Public License 73 | -- along with this program. If not, see . 74 | -- 75 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 76 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 77 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 78 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 79 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 80 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 81 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 82 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 83 | -- 84 | ------------------------------------------------------------------------------- 85 | ------------------------------------------------------------------------------- 86 | library ieee; 87 | use ieee.std_logic_1164.all; 88 | use ieee.std_logic_arith.all; 89 | use ieee.std_logic_signed.all; 90 | 91 | entity cordic_dds48 is 92 | generic ( 93 | PHASE_WIDTH : integer := 16;-- Phase width: sets period of signal 94 | DATA_WIDTH : integer := 16 -- Output width: sets magnitude of signal 95 | ); 96 | port ( 97 | CLK : in std_logic; --! Clock source 98 | RESET : in std_logic; --! Positive reset: '1' - reset, '0' - calculate 99 | PH_IN : in std_logic_vector(PHASE_WIDTH-1 downto 0); --! Input phase increment 100 | PH_EN : in std_logic; --! Input phase enable 101 | DT_SIN : out std_logic_vector(DATA_WIDTH-1 downto 0); --! Output sine value 102 | DT_COS : out std_logic_vector(DATA_WIDTH-1 downto 0); --! Output cosine value 103 | DT_VAL : out std_logic --! Output data valid 104 | ); 105 | end cordic_dds48; 106 | 107 | architecture cordic_dds48 of cordic_dds48 is 108 | 109 | ---------------- Constant declaration ---------------- 110 | constant GAIN48 : std_logic_vector(47 downto 0):=x"26DD3B6A10D8"; 111 | 112 | ---------------- ROM: Look up table for CORDIC ---------------- 113 | type rom_array is array (0 to 47) of std_logic_vector(47 downto 0); 114 | 115 | constant ROM_LUT : rom_array := ( 116 | x"200000000000", x"12E4051D9DF3", x"09FB385B5EE4", x"051111D41DDE", 117 | x"028B0D430E59", x"0145D7E15904", x"00A2F61E5C28", x"00517C5511D4", 118 | x"0028BE5346D1", x"00145F2EBB31", x"000A2F980092", x"000517CC14A8", 119 | x"00028BE60CE0", x"000145F306C1", x"0000A2F9836B", x"0000517CC1B7", 120 | x"000028BE60DC", x"0000145F306E", x"00000A2F9837", x"00000517CC1B", 121 | x"0000028BE60E", x"00000145F307", x"000000A2F983", x"000000517CC2", 122 | x"00000028BE61", x"000000145F30", x"0000000A2F98", x"0000000517CC", 123 | x"000000028BE6", x"0000000145F3", x"00000000A2FA", x"00000000517D", 124 | x"0000000028BE", x"00000000145F", x"000000000A30", x"000000000518", 125 | x"00000000028C", x"000000000146", x"0000000000A3", x"000000000051", 126 | x"000000000029", x"000000000014", x"00000000000A", x"000000000005", 127 | x"000000000003", x"000000000001", x"000000000001", x"000000000000" 128 | ); 129 | 130 | type rom_atan is array (0 to DATA_WIDTH-2) of std_logic_vector(47 downto 0); 131 | 132 | function func_atan return rom_atan is 133 | variable ret : rom_atan; 134 | begin 135 | for ii in 0 to DATA_WIDTH-2 loop 136 | ret(ii) := ROM_LUT(ii); 137 | end loop; 138 | return ret; 139 | end function func_atan; 140 | 141 | constant ROM_TABLE : rom_atan := func_atan; 142 | 143 | ---------------- Signal declaration ---------------- 144 | type dat_array is array (0 to DATA_WIDTH) of std_logic_vector(47 downto 0); 145 | type phi_array is array (0 to DATA_WIDTH-1) of std_logic_vector(47 downto 0); 146 | 147 | signal sigX : dat_array := (others => (others => '0')); 148 | signal sigY : dat_array := (others => (others => '0')); 149 | signal sigZ : phi_array := (others => (others => '0')); 150 | 151 | signal init_x : std_logic_vector(47 downto 0); 152 | signal init_y : std_logic_vector(47 downto 0); 153 | signal init_t : std_logic_vector(PHASE_WIDTH-1 downto 0); 154 | signal init_z : std_logic_vector(47 downto 0); 155 | 156 | signal quadrant : std_logic_vector(1 downto 0); 157 | signal dt_vld : std_logic_vector(DATA_WIDTH+1 downto 0); 158 | 159 | begin 160 | 161 | --------------------------------------------------------------------- 162 | ---------------- Convert phase width ------------------------------- 163 | --------------------------------------------------------------------- 164 | init_z(47 downto 47-(PHASE_WIDTH-1)) <= init_t(PHASE_WIDTH-1 downto 0); 165 | init_z(47-PHASE_WIDTH downto 00) <= (others => '0'); 166 | 167 | --------------------------------------------------------------------- 168 | ---------------- Calculate Quadrant: two MSBs of input phase -------- 169 | --------------------------------------------------------------------- 170 | quadrant <= ph_in(ph_in'left downto ph_in'left-1); 171 | 172 | pr_phi: process(clk) is 173 | begin 174 | if rising_edge(clk) then 175 | if (reset = '1') then 176 | init_t <= (others => '0'); 177 | else 178 | if (ph_en = '1') then 179 | case quadrant is 180 | when "00" | "11" => init_t <= ph_in; 181 | when "01" => init_t <= ("00" & ph_in(ph_in'left-2 downto 0)); 182 | when "10" => init_t <= ("11" & ph_in(ph_in'left-2 downto 0)); 183 | when others => null; 184 | end case; 185 | end if; 186 | end if; 187 | end if; 188 | end process; 189 | 190 | --------------------------------------------------------------------- 191 | ---------------- Registered: initial values for X, Y, Z ------------- 192 | --------------------------------------------------------------------- 193 | pr_xy: process(clk) is 194 | begin 195 | if rising_edge(clk) then 196 | if (reset = '1') then 197 | init_x <= (others => '0'); 198 | init_y <= (others => '0'); 199 | else 200 | if (ph_en = '1') then 201 | case quadrant is 202 | when "00" | "11" => 203 | init_x <= GAIN48; 204 | init_y <= (others => '0'); 205 | when "01" => 206 | init_x <= (others => '0'); 207 | init_y <= not(GAIN48) + '1'; 208 | when "10" => 209 | init_x <= (others => '0'); 210 | init_y <= GAIN48; 211 | when others => null; 212 | end case; 213 | end if; 214 | end if; 215 | end if; 216 | end process; 217 | 218 | --------------------------------------------------------------------- 219 | ---------------- Compute Angle array and X/Y ------------------------ 220 | --------------------------------------------------------------------- 221 | pr_crd: process(clk, reset) 222 | begin 223 | if (reset = '1') then 224 | ---- Reset [x y z] vector ---- 225 | sigX <= (others => (others => '0')); 226 | sigY <= (others => (others => '0')); 227 | sigZ <= (others => (others => '0')); 228 | elsif rising_edge(clk) then 229 | ---- Initial values ---- 230 | sigX(0) <= init_x; 231 | sigY(0) <= init_y; 232 | sigZ(0) <= init_z; 233 | ---- calculate sine & cosine ---- 234 | xl: for ii in 0 to DATA_WIDTH-1 loop 235 | if (sigZ(ii)(sigZ(ii)'left) = '0') then 236 | sigX(ii+1) <= sigX(ii) + sigY(ii)(47 downto ii); 237 | sigY(ii+1) <= sigY(ii) - sigX(ii)(47 downto ii); 238 | else 239 | sigX(ii+1) <= sigX(ii) - sigY(ii)(47 downto ii); 240 | sigY(ii+1) <= sigY(ii) + sigX(ii)(47 downto ii); 241 | end if; 242 | end loop; 243 | ---- calculate phase ---- 244 | xp: for ii in 0 to DATA_WIDTH-2 loop 245 | if (sigZ(ii)(sigZ(ii)'left) = '1') then 246 | sigZ(ii+1) <= sigZ(ii) + ROM_TABLE(ii); 247 | else 248 | sigZ(ii+1) <= sigZ(ii) - ROM_TABLE(ii); 249 | end if; 250 | end loop; 251 | end if; 252 | end process; 253 | 254 | dt_vld <= dt_vld(dt_vld'left-1 downto 0) & ph_en when rising_edge(clk); 255 | 256 | ---- Output data ---- 257 | dt_sin <= sigY(DATA_WIDTH)(47 downto 47-(DATA_WIDTH-1)) when rising_edge(clk); 258 | dt_cos <= sigX(DATA_WIDTH)(47 downto 47-(DATA_WIDTH-1)) when rising_edge(clk); 259 | dt_val <= dt_vld(dt_vld'left) when rising_edge(clk); 260 | 261 | end cordic_dds48; -------------------------------------------------------------------------------- /src/cordic_dds.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : cordic_dds 4 | -- Design : Blackman-Harris Windows 5 | -- Author : Kapitanov Alexander 6 | -- Company : 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | -- Description : Simple cordic algorithm for sine and cosine generator (DDS) 10 | -- 11 | ------------------------------------------------------------------------------- 12 | -- 13 | -- Version 1.0 30.08.2018 14 | -- Description: Cordic for sin/cos wave generator (DDS style) 15 | -- 16 | -- Coordinates: X represents the sine, Y represents the cosine, and 17 | -- Z represents theta. 18 | -- 19 | -- Cosine mode: 20 | -- x0 - initialized to 1/Magnitude = 1/2^(WIDTH); 21 | -- y0 - initialized to 0; 22 | -- z0 - initialized to the THETA input argument value (phase); 23 | -- 24 | -- Sine mode: 25 | -- x0 - initialized to 0; 26 | -- y0 - initialized to (+/-)1/Magnitude = 1/2^(WIDTH); 27 | -- z0 - initialized to the THETA input argument value (phase); 28 | -- 29 | -- Phase radians - Look up table array ROM [WIDTH-1 : 0] 30 | -- Formula: Angle = Round[atan(2^-i) * (2^48/(2*pi))] where i - variable of ROM array 31 | -- 32 | -- Gain for output signal is production of: 33 | -- Gain = PROD[ SQRT(1.0+2.0**(-2*i)) ], where i = 0 to DATA_WIDTH. 34 | -- 35 | -- Example: WIDTH = 16: create ROM array from 0 to 14: 36 | -- { 0x2000, 0x12E4, 0x09FB, 0x0511, 0x028B, 0x0146, 0x00A3, 0x0051 37 | -- 0x0029, 0x0014, 0x000A, 0x0005, 0x0003, 0x0001, 0x0000 } 38 | -- 39 | -- The fixed-point CORDIC requires: 40 | -- > 1 LUT, 41 | -- > 2 shifts, 42 | -- > 3 additions, 43 | -- per iteration. 44 | -- 45 | ------------------------------------------------------------------------------- 46 | ------------------------------------------------------------------------------- 47 | -- 48 | -- GNU GENERAL PUBLIC LICENSE 49 | -- Version 3, 29 June 2007 50 | -- 51 | -- Copyright (c) 2018 Kapitanov Alexander 52 | -- 53 | -- This program is free software: you can redistribute it and/or modify 54 | -- it under the terms of the GNU General Public License as published by 55 | -- the Free Software Foundation, either version 3 of the License, or 56 | -- (at your option) any later version. 57 | -- 58 | -- You should have received a copy of the GNU General Public License 59 | -- along with this program. If not, see . 60 | -- 61 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 62 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 63 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 64 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 65 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 66 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 67 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 68 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 69 | -- 70 | ------------------------------------------------------------------------------- 71 | ------------------------------------------------------------------------------- 72 | library ieee; 73 | use ieee.std_logic_1164.all; 74 | use ieee.std_logic_arith.all; 75 | use ieee.std_logic_signed.all; 76 | 77 | entity cordic_dds is 78 | generic ( 79 | PRECISION : integer := 1; --! Data precision: from 1 to 7, avg = 2-4 80 | PHASE_WIDTH : integer := 20;-- Phase width: sets period of signal 81 | DATA_WIDTH : integer := 24 -- Output width: sets magnitude of signal 82 | ); 83 | port ( 84 | CLK : in std_logic; --! Clock source 85 | RESET : in std_logic; --! Positive reset: '1' - reset, '0' - calculate 86 | PH_IN : in std_logic_vector(PHASE_WIDTH-1 downto 0); --! Input phase increment 87 | PH_EN : in std_logic; --! Input phase enable 88 | DT_SIN : out std_logic_vector(DATA_WIDTH-1 downto 0); --! Output sine value 89 | DT_COS : out std_logic_vector(DATA_WIDTH-1 downto 0); --! Output cosine value 90 | DT_VAL : out std_logic --! Output data valid 91 | ); 92 | end cordic_dds; 93 | 94 | architecture cordic_dds of cordic_dds is 95 | 96 | ---------------- Constant declaration ---------------- 97 | constant GAIN48 : std_logic_vector(47 downto 0):=x"4DBA76D421AF"; 98 | constant GAIN : std_logic_vector(DATA_WIDTH+PRECISION-1 downto 0):="0" & GAIN48(47 downto 48-DATA_WIDTH-PRECISION+1); 99 | 100 | ---------------- ROM: Look up table for CORDIC ---------------- 101 | ---- Result of [ATAN(2^-i) * (2^47/MATH_PI)] rounded and converted to HEX 102 | type rom_array is array (0 to 47) of std_logic_vector(47 downto 0); 103 | 104 | constant ROM_LUT : rom_array := ( 105 | x"400000000000", x"25C80A3B3BE6", x"13F670B6BDC7", x"0A2223A83BBB", 106 | x"05161A861CB1", x"028BAFC2B209", x"0145EC3CB850", x"00A2F8AA23A9", 107 | x"00517CA68DA2", x"0028BE5D7661", x"00145F300123", x"000A2F982950", 108 | x"000517CC19C0", x"00028BE60D83", x"000145F306D6", x"0000A2F9836D", 109 | x"0000517CC1B7", x"000028BE60DC", x"0000145F306E", x"00000A2F9837", 110 | x"00000517CC1B", x"0000028BE60E", x"00000145F307", x"000000A2F983", 111 | x"000000517CC2", x"00000028BE61", x"000000145F30", x"0000000A2F98", 112 | x"0000000517CC", x"000000028BE6", x"0000000145F3", x"00000000A2FA", 113 | x"00000000517D", x"0000000028BE", x"00000000145F", x"000000000A30", 114 | x"000000000518", x"00000000028C", x"000000000146", x"0000000000A3", 115 | x"000000000051", x"000000000029", x"000000000014", x"00000000000A", 116 | x"000000000005", x"000000000003", x"000000000001", x"000000000000" 117 | ); 118 | 119 | type rom_atan is array (0 to DATA_WIDTH-2) of std_logic_vector(DATA_WIDTH+PRECISION-1 downto 0); 120 | 121 | function func_atan return rom_atan is 122 | variable ret : rom_atan; 123 | begin 124 | for ii in 0 to DATA_WIDTH-2 loop 125 | ret(ii)(DATA_WIDTH+PRECISION-2 downto 0) := ROM_LUT(ii)(47 downto (47-(DATA_WIDTH+PRECISION-2))); 126 | ret(ii)(DATA_WIDTH+PRECISION-1 downto DATA_WIDTH+PRECISION-1) := (others => '0'); 127 | end loop; 128 | return ret; 129 | end function func_atan; 130 | 131 | constant ROM_TABLE : rom_atan := func_atan; 132 | 133 | ---------------- Signal declaration ---------------- 134 | type dat_array is array (0 to DATA_WIDTH-1) of std_logic_vector(DATA_WIDTH+PRECISION-1 downto 0); 135 | type phi_array is array (0 to DATA_WIDTH-1) of std_logic_vector(DATA_WIDTH+PRECISION-1 downto 0); 136 | 137 | signal sigX : dat_array := (others => (others => '0')); 138 | signal sigY : dat_array := (others => (others => '0')); 139 | signal sigZ : phi_array := (others => (others => '0')); 140 | 141 | signal init_x : std_logic_vector(DATA_WIDTH+PRECISION-1 downto 0); 142 | signal init_y : std_logic_vector(DATA_WIDTH+PRECISION-1 downto 0); 143 | signal init_t : std_logic_vector(PHASE_WIDTH-1 downto 0); 144 | signal init_z : std_logic_vector(DATA_WIDTH+PRECISION-1 downto 0); 145 | 146 | signal quadrant : std_logic_vector(1 downto 0); 147 | signal quadz1 : std_logic_vector(DATA_WIDTH-1 downto 0); 148 | signal quadz2 : std_logic_vector(DATA_WIDTH-1 downto 0); 149 | signal dt_vld : std_logic_vector(DATA_WIDTH-1 downto 0); 150 | 151 | signal dat_sin : std_logic_vector(DATA_WIDTH-1 downto 0); 152 | signal dat_cos : std_logic_vector(DATA_WIDTH-1 downto 0); 153 | 154 | begin 155 | 156 | --------------------------------------------------------------------- 157 | ---------------- Convert phase width ------------------------------- 158 | --------------------------------------------------------------------- 159 | xPHI_LESS: if (PHASE_WIDTH >= DATA_WIDTH) generate 160 | init_z(PRECISION-1 downto 0) <= (others => '0'); 161 | init_z(DATA_WIDTH+PRECISION-1 downto PRECISION) <= init_t(PHASE_WIDTH-1 downto PHASE_WIDTH-DATA_WIDTH); 162 | end generate; 163 | xPHI_MORE: if (PHASE_WIDTH < DATA_WIDTH) generate 164 | init_z(DATA_WIDTH-PHASE_WIDTH+PRECISION-1 downto 0) <= (others => '0'); 165 | init_z(DATA_WIDTH+PRECISION-1 downto DATA_WIDTH-PHASE_WIDTH+PRECISION) <= init_t(PHASE_WIDTH-1 downto 0); 166 | end generate; 167 | --------------------------------------------------------------------- 168 | ---------------- Calculate Quadrant: two MSBs of input phase -------- 169 | --------------------------------------------------------------------- 170 | quadz1 <= quadz1(DATA_WIDTH-2 downto 0) & ph_in(PHASE_WIDTH-1) when rising_edge(clk); 171 | quadz2 <= quadz2(DATA_WIDTH-2 downto 0) & ph_in(PHASE_WIDTH-2) when rising_edge(clk); 172 | quadrant <= quadz1(DATA_WIDTH-1) & quadz2(DATA_WIDTH-1); 173 | 174 | --------------------------------------------------------------------- 175 | ---------------- Registered: initial values for X, Y, Z ------------- 176 | --------------------------------------------------------------------- 177 | init_x <= GAIN; 178 | init_y <= (others => '0'); 179 | init_t <= ("00" & ph_in(ph_in'left-2 downto 0)); 180 | 181 | --------------------------------------------------------------------- 182 | ---------------- Compute Angle array and X/Y ------------------------ 183 | --------------------------------------------------------------------- 184 | pr_crd: process(clk, reset) 185 | begin 186 | if rising_edge(clk) then 187 | if (reset = '1') then 188 | ---- Reset sine / cosine / angle vector ---- 189 | sigX <= (others => (others => '0')); 190 | sigY <= (others => (others => '0')); 191 | sigZ <= (others => (others => '0')); 192 | else 193 | sigX(0) <= init_x; 194 | sigY(0) <= init_y; 195 | sigZ(0) <= init_z; 196 | ---- calculate sine & cosine ---- 197 | lpXY: for ii in 0 to DATA_WIDTH-2 loop 198 | if (sigZ(ii)(sigZ(ii)'left) = '1') then 199 | sigX(ii+1) <= sigX(ii) + sigY(ii)(DATA_WIDTH+PRECISION-1 downto ii); 200 | sigY(ii+1) <= sigY(ii) - sigX(ii)(DATA_WIDTH+PRECISION-1 downto ii); 201 | else 202 | sigX(ii+1) <= sigX(ii) - sigY(ii)(DATA_WIDTH+PRECISION-1 downto ii); 203 | sigY(ii+1) <= sigY(ii) + sigX(ii)(DATA_WIDTH+PRECISION-1 downto ii); 204 | end if; 205 | end loop; 206 | ---- calculate phase ---- 207 | lpZ: for ii in 0 to DATA_WIDTH-2 loop 208 | if (sigZ(ii)(sigZ(ii)'left) = '1') then 209 | sigZ(ii+1) <= sigZ(ii) + ROM_TABLE(ii); 210 | else 211 | sigZ(ii+1) <= sigZ(ii) - ROM_TABLE(ii); 212 | end if; 213 | end loop; 214 | end if; 215 | end if; 216 | end process; 217 | 218 | dat_sin <= sigY(DATA_WIDTH-1)(DATA_WIDTH+PRECISION-1 downto PRECISION); 219 | dat_cos <= sigX(DATA_WIDTH-1)(DATA_WIDTH+PRECISION-1 downto PRECISION); 220 | 221 | dt_vld <= dt_vld(dt_vld'left-1 downto 0) & ph_en when rising_edge(clk); 222 | dt_val <= dt_vld(dt_vld'left) when rising_edge(clk); 223 | 224 | ---- Output data ---- 225 | pr_xy: process(clk) is 226 | begin 227 | if rising_edge(clk) then 228 | if (reset = '1') then 229 | dt_sin <= (others => '0'); 230 | dt_cos <= (others => '0'); 231 | else 232 | case quadrant is 233 | when "00" => 234 | dt_sin <= dat_sin; 235 | dt_cos <= dat_cos; 236 | when "01" => 237 | dt_sin <= dat_cos; 238 | dt_cos <= not(dat_sin) + '1'; 239 | when "10" => 240 | dt_sin <= not(dat_sin) + '1'; 241 | dt_cos <= not(dat_cos) + '1'; 242 | when "11" => 243 | dt_sin <= not(dat_cos) + '1'; 244 | dt_cos <= dat_sin; 245 | when others => null; 246 | end case; 247 | end if; 248 | end if; 249 | end process; 250 | 251 | end cordic_dds; -------------------------------------------------------------------------------- /src/cordic_dds_scaled.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : cordic_dds_scaled 4 | -- Design : Blackman-Harris Windows 5 | -- Author : Kapitanov Alexander 6 | -- Company : 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | -- Description : Simple cordic algorithm for sine and cosine generator (DDS) 10 | -- 11 | ------------------------------------------------------------------------------- 12 | -- 13 | -- Version 1.0 30.08.2018 14 | -- Description: Cordic for sin/cos wave generator (DDS style) 15 | -- 16 | -- Coordinates: X represents the sine, Y represents the cosine, and 17 | -- Z represents theta. 18 | -- 19 | -- Cosine mode: 20 | -- x0 - initialized to 1/Magnitude = 1/2^(WIDTH); 21 | -- y0 - initialized to 0; 22 | -- z0 - initialized to the THETA input argument value (phase); 23 | -- 24 | -- Sine mode: 25 | -- x0 - initialized to 0; 26 | -- y0 - initialized to (+/-)1/Magnitude = 1/2^(WIDTH); 27 | -- z0 - initialized to the THETA input argument value (phase); 28 | -- 29 | -- Phase radians - Look up table array ROM [WIDTH-1 : 0] 30 | -- Formula: Angle = Round[atan(2^-i) * (2^32/(2*pi))] where i - variable of ROM array 31 | -- 32 | -- Gain for output signal is production of: 33 | -- Gain = PROD[ SQRT(1.0+2.0**(-2*i)) ], where i = 0 to DATA_WIDTH. 34 | -- 35 | -- This version contains weight constant for resize internal data & phase vectors. 36 | -- It is improve accuracy. Data weight vector calculated via experiment. 37 | -- 38 | -- constant SEL_SIZE : size_array := ( 39 | -- 15, 15, 15, 18, 21, 22, 23, 26, 30, 31, 32, 33, 40 | -- 38, 38, 38, 42, 42, 45, 47, 47, 47, 48, 48, 48, 48 41 | -- ); 42 | -- 43 | -- The fixed-point CORDIC requires: 44 | -- > 1 LUT, 45 | -- > 2 shifts, 46 | -- > 3 additions, 47 | -- per iteration. 48 | -- 49 | ------------------------------------------------------------------------------- 50 | ------------------------------------------------------------------------------- 51 | -- 52 | -- GNU GENERAL PUBLIC LICENSE 53 | -- Version 3, 29 June 2007 54 | -- 55 | -- Copyright (c) 2018 Kapitanov Alexander 56 | -- 57 | -- This program is free software: you can redistribute it and/or modify 58 | -- it under the terms of the GNU General Public License as published by 59 | -- the Free Software Foundation, either version 3 of the License, or 60 | -- (at your option) any later version. 61 | -- 62 | -- You should have received a copy of the GNU General Public License 63 | -- along with this program. If not, see . 64 | -- 65 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 66 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 67 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 68 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 69 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 70 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 71 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 72 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 73 | -- 74 | ------------------------------------------------------------------------------- 75 | ------------------------------------------------------------------------------- 76 | library ieee; 77 | use ieee.std_logic_1164.all; 78 | use ieee.std_logic_arith.all; 79 | use ieee.std_logic_signed.all; 80 | 81 | entity cordic_dds_scaled is 82 | generic ( 83 | PHASE_WIDTH : integer := 16;-- Phase width: sets period of signal 84 | DATA_WIDTH : integer := 16 -- Output width: sets magnitude of signal 85 | ); 86 | port ( 87 | CLK : in std_logic; --! Clock source 88 | RESET : in std_logic; --! Positive reset: '1' - reset, '0' - calculate 89 | PH_IN : in std_logic_vector(PHASE_WIDTH-1 downto 0); --! Input phase increment 90 | PH_EN : in std_logic; --! Input phase enable 91 | DT_SIN : out std_logic_vector(DATA_WIDTH-1 downto 0); --! Output sine value 92 | DT_COS : out std_logic_vector(DATA_WIDTH-1 downto 0); --! Output cosine value 93 | DT_VAL : out std_logic --! Output data valid 94 | ); 95 | end cordic_dds_scaled; 96 | 97 | architecture cordic_dds_scaled of cordic_dds_scaled is 98 | 99 | ---------------- Weight coefs ---------------- 100 | type size_array is array (0 to 24) of integer; 101 | 102 | constant SEL_SIZE : size_array := ( 103 | 15, 15, 15, 18, 21, 22, 23, 26, 30, 31, 32, 33, 104 | 38, 38, 38, 42, 42, 45, 47, 47, 47, 48, 48, 48, 48 105 | ); 106 | 107 | constant SIZE : integer:=SEL_SIZE(DATA_WIDTH-8); 108 | 109 | ---------------- Constant declaration ---------------- 110 | constant GAIN48 : std_logic_vector(47 downto 0):=x"26DD3B6A10D8"; 111 | constant GAIN32 : std_logic_vector(SIZE-1 downto 0):=GAIN48(47 downto 47-(SIZE-1)); 112 | 113 | ---------------- ROM: Look up table for CORDIC ---------------- 114 | ---- Result of [ATAN(2^-i) * (2^32/360)] rounded and converted to HEX 115 | type rom_array is array (0 to 47) of std_logic_vector(47 downto 0); 116 | 117 | constant ROM_LUT : rom_array := ( 118 | x"200000000000", x"12E4051D9DF3", x"09FB385B5EE4", x"051111D41DDE", 119 | x"028B0D430E59", x"0145D7E15904", x"00A2F61E5C28", x"00517C5511D4", 120 | x"0028BE5346D1", x"00145F2EBB31", x"000A2F980092", x"000517CC14A8", 121 | x"00028BE60CE0", x"000145F306C1", x"0000A2F9836B", x"0000517CC1B7", 122 | x"000028BE60DC", x"0000145F306E", x"00000A2F9837", x"00000517CC1B", 123 | x"0000028BE60E", x"00000145F307", x"000000A2F983", x"000000517CC2", 124 | x"00000028BE61", x"000000145F30", x"0000000A2F98", x"0000000517CC", 125 | x"000000028BE6", x"0000000145F3", x"00000000A2FA", x"00000000517D", 126 | x"0000000028BE", x"00000000145F", x"000000000A30", x"000000000518", 127 | x"00000000028C", x"000000000146", x"0000000000A3", x"000000000051", 128 | x"000000000029", x"000000000014", x"00000000000A", x"000000000005", 129 | x"000000000003", x"000000000001", x"000000000001", x"000000000000" 130 | ); 131 | 132 | function func_width return integer is 133 | variable ret : integer; 134 | begin 135 | if (SIZE < PHASE_WIDTH) then 136 | ret := PHASE_WIDTH; 137 | else 138 | ret := SIZE; 139 | end if; 140 | return ret; 141 | end function func_width; 142 | 143 | constant DWPH : integer:=func_width; 144 | 145 | 146 | 147 | type rom_atan is array (0 to DATA_WIDTH-2) of std_logic_vector(DWPH-1 downto 0); 148 | 149 | function func_atan return rom_atan is 150 | variable ret : rom_atan; 151 | begin 152 | for ii in 0 to DATA_WIDTH-2 loop 153 | ret(ii) := ROM_LUT(ii)(47 downto 47-(DWPH-1)); 154 | end loop; 155 | return ret; 156 | end function func_atan; 157 | 158 | constant ROM_TABLE : rom_atan := func_atan; 159 | 160 | 161 | 162 | ---------------- Signal declaration ---------------- 163 | type dat_array is array (0 to DATA_WIDTH) of std_logic_vector(SIZE-1 downto 0); 164 | type phi_array is array (0 to DATA_WIDTH-1) of std_logic_vector(DWPH-1 downto 0); 165 | 166 | signal sigX : dat_array := (others => (others => '0')); 167 | signal sigY : dat_array := (others => (others => '0')); 168 | signal sigZ : phi_array := (others => (others => '0')); 169 | 170 | signal init_x : std_logic_vector(SIZE-1 downto 0); 171 | signal init_y : std_logic_vector(SIZE-1 downto 0); 172 | signal init_t : std_logic_vector(PHASE_WIDTH-1 downto 0); 173 | 174 | -- signal init_z : std_logic_vector(DATA_WIDTH-1 downto 0); 175 | -- signal init_z : std_logic_vector(SIZE-1 downto 0); 176 | signal init_z : std_logic_vector(DWPH-1 downto 0); 177 | 178 | signal quadrant : std_logic_vector(1 downto 0); 179 | signal dt_vld : std_logic_vector(DATA_WIDTH+1 downto 0); 180 | 181 | begin 182 | 183 | --------------------------------------------------------------------- 184 | ---------------- Convert phase width ------------------------------- 185 | --------------------------------------------------------------------- 186 | xGEN_PH_HI: if (SIZE >= PHASE_WIDTH) generate 187 | init_z(SIZE-1 downto SIZE-1-(PHASE_WIDTH-1)) <= init_t; 188 | init_z(SIZE-1-PHASE_WIDTH downto 00) <= (others => '0'); 189 | end generate; 190 | xGEN_PH_LO: if (SIZE < PHASE_WIDTH) generate 191 | init_z <= init_t; 192 | end generate; 193 | --------------------------------------------------------------------- 194 | ---------------- Calculate Quadrant: two MSBs of input phase -------- 195 | --------------------------------------------------------------------- 196 | quadrant <= ph_in(ph_in'left downto ph_in'left-1); 197 | 198 | pr_phi: process(clk) is 199 | begin 200 | if rising_edge(clk) then 201 | if (reset = '1') then 202 | init_t <= (others => '0'); 203 | else 204 | if (ph_en = '1') then 205 | case quadrant is 206 | when "00" | "11" => init_t <= ph_in; 207 | when "01" => init_t <= ("00" & ph_in(ph_in'left-2 downto 0)); 208 | when "10" => init_t <= ("11" & ph_in(ph_in'left-2 downto 0)); 209 | when others => null; 210 | end case; 211 | end if; 212 | end if; 213 | end if; 214 | end process; 215 | 216 | --------------------------------------------------------------------- 217 | ---------------- Registered: initial values for X, Y, Z ------------- 218 | --------------------------------------------------------------------- 219 | pr_xy: process(clk) is 220 | begin 221 | if rising_edge(clk) then 222 | if (reset = '1') then 223 | init_x <= (others => '0'); 224 | init_y <= (others => '0'); 225 | else 226 | if (ph_en = '1') then 227 | case quadrant is 228 | when "00" | "11" => 229 | init_x <= GAIN32; 230 | init_y <= (others => '0'); 231 | when "01" => 232 | init_x <= (others => '0'); 233 | init_y <= not(GAIN32) + '1'; 234 | when "10" => 235 | init_x <= (others => '0'); 236 | init_y <= GAIN32; 237 | when others => null; 238 | end case; 239 | end if; 240 | end if; 241 | end if; 242 | end process; 243 | 244 | --------------------------------------------------------------------- 245 | ---------------- Compute Angle array and X/Y ------------------------ 246 | --------------------------------------------------------------------- 247 | pr_crd: process(clk, reset) 248 | begin 249 | if (reset = '1') then 250 | ---- Reset sine / cosine / angle vector ---- 251 | sigX <= (others => (others => '0')); 252 | sigY <= (others => (others => '0')); 253 | sigZ <= (others => (others => '0')); 254 | elsif rising_edge(clk) then 255 | sigX(0) <= init_x; 256 | sigY(0) <= init_y; 257 | sigZ(0) <= init_z; 258 | ---- calculate sine & cosine ---- 259 | xl: for ii in 0 to DATA_WIDTH-1 loop 260 | if (sigZ(ii)(sigZ(ii)'left) = '0') then 261 | sigX(ii+1) <= sigX(ii) + sigY(ii)(SIZE-1 downto ii); 262 | sigY(ii+1) <= sigY(ii) - sigX(ii)(SIZE-1 downto ii); 263 | else 264 | sigX(ii+1) <= sigX(ii) - sigY(ii)(SIZE-1 downto ii); 265 | sigY(ii+1) <= sigY(ii) + sigX(ii)(SIZE-1 downto ii); 266 | end if; 267 | end loop; 268 | ---- calculate phase ---- 269 | xp: for ii in 0 to DATA_WIDTH-2 loop 270 | if (sigZ(ii)(sigZ(ii)'left) = '1') then 271 | sigZ(ii+1) <= sigZ(ii) + ROM_TABLE(ii); 272 | else 273 | sigZ(ii+1) <= sigZ(ii) - ROM_TABLE(ii); 274 | end if; 275 | end loop; 276 | end if; 277 | end process; 278 | 279 | dt_vld <= dt_vld(dt_vld'left-1 downto 0) & ph_en when rising_edge(clk); 280 | 281 | ---- Output data ---- 282 | dt_sin <= sigY(DATA_WIDTH)(SIZE-1 downto SIZE-1-(DATA_WIDTH-1)) when rising_edge(clk); 283 | dt_cos <= sigX(DATA_WIDTH)(SIZE-1 downto SIZE-1-(DATA_WIDTH-1)) when rising_edge(clk); 284 | 285 | dt_val <= dt_vld(dt_vld'left) when rising_edge(clk); 286 | 287 | end cordic_dds_scaled; -------------------------------------------------------------------------------- /hls/windows/win_function.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | -- 3 | -- Title : win_function.c 4 | -- Design : Window functions by HLS 5 | -- Author : Kapitanov Alexander 6 | -- Company : insys.ru 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | ------------------------------------------------------------------------------- 10 | -- 11 | -- Version 1.0 01.10.2018 12 | -- 13 | ------------------------------------------------------------------------------- 14 | -- 15 | -- Description : Some window functions in HLS 16 | -- 17 | ------------------------------------------------------------------------------- 18 | ------------------------------------------------------------------------------- 19 | -- 20 | -- GNU GENERAL PUBLIC LICENSE 21 | -- Version 3, 29 June 2007 22 | -- 23 | -- Copyright (c) 2018 Kapitanov Alexander 24 | -- 25 | -- This program is free software: you can redistribute it and/or modify 26 | -- it under the terms of the GNU General Public License as published by 27 | -- the Free Software Foundation, either version 3 of the License, or 28 | -- (at your option) any later version. 29 | -- 30 | -- You should have received a copy of the GNU General Public License 31 | -- along with this program. If not, see . 32 | -- 33 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 34 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 35 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 36 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 37 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 38 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 39 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 40 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 41 | -- 42 | *******************************************************************************/ 43 | #include 44 | #include "win_function.h" 45 | 46 | /* ---------------- CORDIC core ---------------- */ 47 | void cordic ( 48 | phi_t phi_int, 49 | win_t *out_cos, 50 | win_t *out_sin 51 | ) 52 | { 53 | #pragma HLS INTERFACE port=phi_int 54 | #pragma HLS INTERFACE ap_none register port=out_cos 55 | #pragma HLS INTERFACE ap_none register port=out_sin 56 | #pragma HLS PIPELINE 57 | 58 | // Create Look-up table array // 59 | long long lut_table [48] = { 60 | 0x400000000000, 0x25C80A3B3BE6, 0x13F670B6BDC7, 0x0A2223A83BBB, 61 | 0x05161A861CB1, 0x028BAFC2B209, 0x0145EC3CB850, 0x00A2F8AA23A9, 62 | 0x00517CA68DA2, 0x0028BE5D7661, 0x00145F300123, 0x000A2F982950, 63 | 0x000517CC19C0, 0x00028BE60D83, 0x000145F306D6, 0x0000A2F9836D, 64 | 0x0000517CC1B7, 0x000028BE60DC, 0x0000145F306E, 0x00000A2F9837, 65 | 0x00000517CC1B, 0x0000028BE60E, 0x00000145F307, 0x000000A2F983, 66 | 0x000000517CC2, 0x00000028BE61, 0x000000145F30, 0x0000000A2F98, 67 | 0x0000000517CC, 0x000000028BE6, 0x0000000145F3, 0x00000000A2FA, 68 | 0x00000000517D, 0x0000000028BE, 0x00000000145F, 0x000000000A30, 69 | 0x000000000518, 0x00000000028C, 0x000000000146, 0x0000000000A3, 70 | 0x000000000051, 0x000000000029, 0x000000000014, 0x00000000000A, 71 | 0x000000000005, 0x000000000003, 0x000000000001, 0x000000000000 72 | }; 73 | 74 | static dat_t lut_angle[NWIDTH - 1]; 75 | 76 | int i; 77 | for (i = 0; i < NWIDTH - 1; i++) { 78 | lut_angle[i] = (lut_table[i] >> (48 - NWIDTH - 2 + 1) & 0xFFFFFFFFFF); 79 | // lut_angle[i] = (dat_t)round(atan(pow(2.0, -i)) * pow(2.0, NWIDTH+1) / M_PI); 80 | } 81 | 82 | // Set data output gain level // 83 | static const dat_t GAIN48 = (0x26DD3B6A10D8 >> (48 - NWIDTH - 2)); 84 | 85 | // Calculate quadrant and phase // 86 | duo_t quadrant = phi_int >> (NPHASE - 2); 87 | 88 | dat_t init_t = phi_int & (~(0x3 << (NPHASE - 2))); 89 | 90 | dat_t init_z; 91 | if ((NPHASE-1) < NWIDTH) { 92 | init_z = init_t << (NWIDTH - NPHASE + 2); 93 | } 94 | else { 95 | init_z = (init_t >> (NPHASE - NWIDTH)) << 2; 96 | } 97 | 98 | // Create array for parallel calculation // 99 | dat_t x[NWIDTH + 1]; 100 | dat_t y[NWIDTH + 1]; 101 | dat_t z[NWIDTH + 1]; 102 | 103 | // Initial values // 104 | x[0] = GAIN48; 105 | y[0] = 0x0; 106 | z[0] = init_z; 107 | 108 | // Unrolled loop // 109 | int k; 110 | stg: for (k = 0; k < NWIDTH; k++) { 111 | #pragma HLS UNROLL 112 | 113 | if (z[k] < 0) { 114 | x[k+1] = x[k] + (y[k] >> k); 115 | y[k+1] = y[k] - (x[k] >> k); 116 | 117 | z[k+1] = z[k] + lut_angle[k]; 118 | } else { 119 | x[k+1] = x[k] - (y[k] >> k); 120 | y[k+1] = y[k] + (x[k] >> k); 121 | 122 | z[k+1] = z[k] - lut_angle[k]; 123 | } 124 | 125 | } 126 | 127 | // Shift output data by 2 // 128 | dat_t out_c = (x[NWIDTH] >> 2); 129 | dat_t out_s = (y[NWIDTH] >> 2); 130 | 131 | dat_t dat_c; 132 | dat_t dat_s; 133 | 134 | // Check quadrant and find output sign of data // 135 | if (quadrant == 0x0) { 136 | dat_s = out_s; 137 | dat_c = out_c; 138 | } 139 | else if (quadrant == 0x1) { 140 | dat_s = out_c; 141 | dat_c = ~(out_s) + 1; 142 | } 143 | else if (quadrant == 0x2) { 144 | dat_s = ~(out_s) + 1; 145 | dat_c = ~(out_c) + 1; 146 | } 147 | else { 148 | dat_s = ~(out_c) + 1; 149 | dat_c = out_s; 150 | } 151 | 152 | // Get output values // 153 | *out_cos = (dat_c); 154 | *out_sin = (dat_s); 155 | 156 | } 157 | 158 | /* ---------------- Window: Empty ---------------- */ 159 | void win_empty ( 160 | phi_t i, 161 | win_t* out_win 162 | ) 163 | { 164 | *out_win = 0x0; 165 | } 166 | 167 | /* ---------------- Window: Hamming ---------------- */ 168 | void win_hamming ( 169 | phi_t i, 170 | win_t* out_win 171 | ) 172 | { 173 | const double coeA0 = 0.5434783; 174 | const double coeA1 = (1 - coeA0); 175 | 176 | dbl_t a0 = round(coeA0 * (pow(2.0, NWIDTH-1)-1.0)); 177 | dbl_t a1 = round(coeA1 * (pow(2.0, NWIDTH-1)-1.0)); 178 | 179 | win_t s, c; 180 | 181 | cordic(i, &c, &s); 182 | *out_win = (win_t) (a0 - ((a1 * c) >> (NWIDTH-2))); 183 | } 184 | 185 | /* ---------------- Window: Hann ---------------- */ 186 | void win_hann ( 187 | phi_t i, 188 | win_t* out_win 189 | ) 190 | { 191 | const dbl_t a0 = round(0.5 * (pow(2.0, NWIDTH-1)-1.0)); 192 | const dbl_t a1 = round(0.5 * (pow(2.0, NWIDTH-1)-1.0)); 193 | 194 | win_t s, c; 195 | 196 | cordic(i, &c, &s); 197 | *out_win = (win_t) (a0 - ((a1 * c) >> (NWIDTH-2))); 198 | } 199 | 200 | /* ---------------- Window: Blackman-Harris-3 ---------------- */ 201 | void win_blackman_harris_3 ( 202 | phi_t i, 203 | win_t* out_win 204 | ) 205 | { 206 | const double coeA0 = 0.21; 207 | const double coeA1 = 0.25; 208 | const double coeA2 = 0.04; 209 | 210 | dbl_t a0 = round(coeA0 * (pow(2.0, NWIDTH-1)-1.0)); 211 | dbl_t a1 = round(coeA1 * (pow(2.0, NWIDTH-1)-1.0)); 212 | dbl_t a2 = round(coeA2 * (pow(2.0, NWIDTH-1)-1.0)); 213 | 214 | win_t s1, c1, s2, c2; 215 | 216 | dbl_t mlt1, mlt2; 217 | dbl_t sum; 218 | 219 | cordic(i, &c1, &s1); 220 | cordic(2*i, &c2, &s2); 221 | 222 | mlt1 = (a1 * c1) >> (NWIDTH-2); 223 | mlt2 = (a2 * c2) >> (NWIDTH-2); 224 | 225 | *out_win = (win_t) (a0 - mlt1 + mlt2); 226 | 227 | } 228 | 229 | /* ---------------- Window: Blackman-Harris-4 ---------------- */ 230 | void win_blackman_harris_4 ( 231 | phi_t i, 232 | win_t* out_win 233 | ) 234 | { 235 | /* 236 | > Blackman-Harris: 237 | a0 = 0.35875, 238 | a1 = 0.48829, 239 | a2 = 0.14128, 240 | a3 = 0.01168. 241 | > Nuttall: 242 | a0 = 0.355768, 243 | a1 = 0.487396, 244 | a2 = 0.144323, 245 | a3 = 0.012604. 246 | > Blackman-Nuttall: 247 | a0 = 0.3635819, 248 | a1 = 0.4891775, 249 | a2 = 0.1365995, 250 | a3 = 0.0106411. 251 | */ 252 | 253 | const double coeA0 = 0.35875; 254 | const double coeA1 = 0.48829; 255 | const double coeA2 = 0.14128; 256 | const double coeA3 = 0.01168; 257 | 258 | dbl_t a0 = round(coeA0 * (pow(2.0, NWIDTH-1)-1.0)); 259 | dbl_t a1 = round(coeA1 * (pow(2.0, NWIDTH-1)-1.0)); 260 | dbl_t a2 = round(coeA2 * (pow(2.0, NWIDTH-1)-1.0)); 261 | dbl_t a3 = round(coeA3 * (pow(2.0, NWIDTH-1)-1.0)); 262 | 263 | win_t s1, c1, s2, c2, s3, c3; 264 | 265 | dbl_t mlt1, mlt2, mlt3; 266 | 267 | cordic(1*i, &c1, &s1); 268 | cordic(2*i, &c2, &s2); 269 | cordic(3*i, &c3, &s3); 270 | 271 | mlt1 = (a1 * c1) >> (NWIDTH-2); 272 | mlt2 = (a2 * c2) >> (NWIDTH-2); 273 | mlt3 = (a3 * c3) >> (NWIDTH-2); 274 | 275 | *out_win = (win_t) (a0 - mlt1 + mlt2 - mlt3); 276 | 277 | } 278 | 279 | /* ---------------- Window: Blackman-Harris-5 ---------------- */ 280 | void win_blackman_harris_5 ( 281 | phi_t i, 282 | win_t* out_win 283 | ) 284 | { 285 | /* 286 | > Blackman-Harris: 287 | a0 = 0.3232153788877343; 288 | a1 = 0.4714921439576260; 289 | a2 = 0.1755341299601972; 290 | a3 = 0.0284969901061499; 291 | a4 = 0.0012613570882927; 292 | > Flat-top (1): 293 | a0 = 0.25000; 294 | a1 = 0.49250; 295 | a2 = 0.32250; 296 | a3 = 0.09700; 297 | a4 = 0.00750; 298 | > Flat-top (2): 299 | a0 = 0.215578950; 300 | a1 = 0.416631580; 301 | a2 = 0.277263158; 302 | a3 = 0.083578947; 303 | a3 = 0.006947368; 304 | */ 305 | 306 | const double coeA0 = 0.3232153788877343; 307 | const double coeA1 = 0.4714921439576260; 308 | const double coeA2 = 0.1755341299601972; 309 | const double coeA3 = 0.0284969901061499; 310 | const double coeA4 = 0.0012613570882927; 311 | 312 | dbl_t a0 = round(coeA0 * (pow(2.0, NWIDTH-2)-1.0)); 313 | dbl_t a1 = round(coeA1 * (pow(2.0, NWIDTH-2)-1.0)); 314 | dbl_t a2 = round(coeA2 * (pow(2.0, NWIDTH-2)-1.0)); 315 | dbl_t a3 = round(coeA3 * (pow(2.0, NWIDTH-2)-1.0)); 316 | dbl_t a4 = round(coeA4 * (pow(2.0, NWIDTH-2)-1.0)); 317 | 318 | win_t s1, c1, s2, c2, s3, c3, s4, c4; 319 | 320 | dbl_t mlt1, mlt2, mlt3, mlt4; 321 | 322 | cordic(1*i, &c1, &s1); 323 | cordic(2*i, &c2, &s2); 324 | cordic(3*i, &c3, &s3); 325 | cordic(4*i, &c4, &s4); 326 | 327 | mlt1 = (a1 * c1) >> (NWIDTH-2); 328 | mlt2 = (a2 * c2) >> (NWIDTH-2); 329 | mlt3 = (a3 * c3) >> (NWIDTH-2); 330 | mlt4 = (a4 * c4) >> (NWIDTH-2); 331 | 332 | *out_win = (win_t) (a0 - mlt1 + mlt2 - mlt3 + mlt4); 333 | } 334 | 335 | /* ---------------- Window: Blackman-Harris-7 ---------------- */ 336 | void win_blackman_harris_7 ( 337 | phi_t i, 338 | win_t* out_win 339 | ) 340 | { 341 | const double coeA0= 0.271220360585039; 342 | const double coeA1= 0.433444612327442; 343 | const double coeA2= 0.218004122892930; 344 | const double coeA3= 0.065785343295606; 345 | const double coeA4= 0.010761867305342; 346 | const double coeA5= 0.000770012710581; 347 | const double coeA6= 0.000013680883060; 348 | 349 | dbl_t a0 = round(coeA0 * (pow(2.0, NWIDTH-2)-1.0)); 350 | dbl_t a1 = round(coeA1 * (pow(2.0, NWIDTH-2)-1.0)); 351 | dbl_t a2 = round(coeA2 * (pow(2.0, NWIDTH-2)-1.0)); 352 | dbl_t a3 = round(coeA3 * (pow(2.0, NWIDTH-2)-1.0)); 353 | dbl_t a4 = round(coeA4 * (pow(2.0, NWIDTH-2)-1.0)); 354 | dbl_t a5 = round(coeA5 * (pow(2.0, NWIDTH-2)-1.0)); 355 | dbl_t a6 = round(coeA6 * (pow(2.0, NWIDTH-2)-1.0)); 356 | 357 | win_t s1, c1, s2, c2, s3, c3, s4, c4, s5, c5, s6, c6; 358 | 359 | dbl_t mlt1, mlt2, mlt3, mlt4, mlt5, mlt6; 360 | 361 | cordic(1*i, &c1, &s1); 362 | cordic(2*i, &c2, &s2); 363 | cordic(3*i, &c3, &s3); 364 | cordic(4*i, &c4, &s4); 365 | cordic(5*i, &c5, &s5); 366 | cordic(6*i, &c6, &s6); 367 | 368 | mlt1 = (a1 * c1) >> (NWIDTH-2); 369 | mlt2 = (a2 * c2) >> (NWIDTH-2); 370 | mlt3 = (a3 * c3) >> (NWIDTH-2); 371 | mlt4 = (a4 * c4) >> (NWIDTH-2); 372 | mlt5 = (a5 * c5) >> (NWIDTH-2); 373 | mlt6 = (a6 * c6) >> (NWIDTH-2); 374 | 375 | *out_win = (win_t) (a0 - mlt1 + mlt2 - mlt3 + mlt4 - mlt5 + mlt6); 376 | 377 | } 378 | 379 | /* ---------------- Window Function ---------------- */ 380 | void win_function ( 381 | const char win_type, 382 | phi_t i, 383 | win_t* out_win 384 | ) 385 | { 386 | #pragma HLS INTERFACE ap_none port=win_type 387 | #pragma HLS INTERFACE ap_none port=i 388 | #pragma HLS INTERFACE ap_none register port=out_win 389 | #pragma HLS PIPELINE 390 | 391 | switch (win_type) 392 | { 393 | case 0x1: 394 | win_hamming(i, out_win); 395 | break; 396 | 397 | case 0x2: 398 | win_hann(i, out_win); 399 | break; 400 | 401 | case 0x3: 402 | win_blackman_harris_3(i, out_win); 403 | break; 404 | 405 | case 0x4: 406 | win_blackman_harris_4(i, out_win); 407 | break; 408 | 409 | case 0x5: 410 | win_blackman_harris_5(i, out_win); 411 | break; 412 | 413 | case 0x7: 414 | win_blackman_harris_7(i, out_win); 415 | break; 416 | 417 | default: 418 | win_empty(i, out_win); 419 | break; 420 | } 421 | 422 | } 423 | -------------------------------------------------------------------------------- /src/bh_win_5term.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : bh_win_5term 4 | -- Design : Blackman-Harris Windows 5 | -- Author : Kapitanov Alexander 6 | -- Company : 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | -- Description : Simple Blackman-Harris window function: 5- term 10 | -- Configurable data length and number of terms. 11 | -- 12 | -- Constants {0-4} (gain for harmonics): type - REAL (float IEEE-754) 13 | -- 14 | -- > Blackman-Harris: 15 | -- a0 = 0.3232153788877343; 16 | -- a1 = 0.4714921439576260; 17 | -- a2 = 0.1755341299601972; 18 | -- a3 = 0.0284969901061499; 19 | -- a4 = 0.0012613570882927; 20 | -- 21 | -- > Flat-top: 22 | -- a0 = 1.000; 23 | -- a1 = 1.930; 24 | -- a2 = 1.290; 25 | -- a3 = 0.388; 26 | -- a4 = 0.030; 27 | -- 28 | -- or: 29 | -- a0 = 0.215578950; 30 | -- a1 = 0.416631580; 31 | -- a2 = 0.277263158; 32 | -- a3 = 0.083578947; 33 | -- a4 = 0.006947368; 34 | -- 35 | ------------------------------------------------------------------------------- 36 | ------------------------------------------------------------------------------- 37 | -- 38 | -- GNU GENERAL PUBLIC LICENSE 39 | -- Version 3, 29 June 2007 40 | -- 41 | -- Copyright (c) 2018 Kapitanov Alexander 42 | -- 43 | -- This program is free software: you can redistribute it and/or modify 44 | -- it under the terms of the GNU General Public License as published by 45 | -- the Free Software Foundation, either version 3 of the License, or 46 | -- (at your option) any later version. 47 | -- 48 | -- You should have received a copy of the GNU General Public License 49 | -- along with this program. If not, see . 50 | -- 51 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 52 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 53 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 54 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 55 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 56 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 57 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 58 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 59 | -- 60 | ------------------------------------------------------------------------------- 61 | library ieee; 62 | use ieee.std_logic_1164.all; 63 | use ieee.std_logic_arith.all; 64 | use ieee.std_logic_signed.all; 65 | 66 | -- library unisim; 67 | -- use unisim.vcomponents.DSP48E1; 68 | -- use unisim.vcomponents.DSP48E2; 69 | 70 | entity bh_win_5term is 71 | generic( 72 | TD : time:=0.5ns; --! Time delay 73 | PHI_WIDTH : integer:=10; --! Signal period = 2^PHI_WIDTH 74 | DAT_WIDTH : integer:=16 --! Output data width 75 | ); 76 | port( 77 | RESET : in std_logic; --! Global reset 78 | CLK : in std_logic; --! System clock 79 | 80 | AA0 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A0 81 | AA1 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A1 82 | AA2 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A2 83 | AA3 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A3 84 | AA4 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A4 85 | 86 | ENABLE : in std_logic; --! Input data enable block = NFFT clocks 87 | DT_WIN : out std_logic_vector(DAT_WIDTH-1 downto 0); --! Output (cos) 88 | DT_VLD : out std_logic --! Output data valid 89 | ); 90 | end bh_win_5term; 91 | 92 | architecture bh_win_5term of bh_win_5term is 93 | 94 | ---------------- Cordic signals ---------------- 95 | signal cos1 : std_logic_vector(DAT_WIDTH-1 downto 0); 96 | signal cos2 : std_logic_vector(DAT_WIDTH-1 downto 0); 97 | signal cos3 : std_logic_vector(DAT_WIDTH-1 downto 0); 98 | signal cos4 : std_logic_vector(DAT_WIDTH-1 downto 0); 99 | 100 | signal ph_in1 : std_logic_vector(PHI_WIDTH-1 downto 0); 101 | signal ph_in2 : std_logic_vector(PHI_WIDTH-1 downto 0); 102 | signal ph_in3 : std_logic_vector(PHI_WIDTH-1 downto 0); 103 | signal ph_in4 : std_logic_vector(PHI_WIDTH-1 downto 0); 104 | 105 | ---------------- Multiplier signals ---------------- 106 | signal mult_a1 : std_logic_vector(DAT_WIDTH-1 downto 0); 107 | signal mult_a2 : std_logic_vector(DAT_WIDTH-1 downto 0); 108 | signal mult_a3 : std_logic_vector(DAT_WIDTH-1 downto 0); 109 | signal mult_a4 : std_logic_vector(DAT_WIDTH-1 downto 0); 110 | 111 | signal mult_b1 : std_logic_vector(DAT_WIDTH-1 downto 0); 112 | signal mult_b2 : std_logic_vector(DAT_WIDTH-1 downto 0); 113 | signal mult_b3 : std_logic_vector(DAT_WIDTH-1 downto 0); 114 | signal mult_b4 : std_logic_vector(DAT_WIDTH-1 downto 0); 115 | 116 | 117 | signal mult_p1 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 118 | signal mult_p2 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 119 | signal mult_p3 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 120 | signal mult_p4 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 121 | 122 | ---------------- Product signals ---------------- 123 | signal dsp_b0 : std_logic_vector(DAT_WIDTH-1 downto 0); 124 | signal dsp_b1 : std_logic_vector(DAT_WIDTH-1 downto 0); 125 | signal dsp_b2 : std_logic_vector(DAT_WIDTH-1 downto 0); 126 | signal dsp_b3 : std_logic_vector(DAT_WIDTH-1 downto 0); 127 | signal dsp_b4 : std_logic_vector(DAT_WIDTH-1 downto 0); 128 | 129 | signal dsp_r1 : std_logic_vector(DAT_WIDTH downto 0); 130 | signal dsp_r2 : std_logic_vector(DAT_WIDTH downto 0); 131 | signal dsp_r3 : std_logic_vector(DAT_WIDTH downto 0); 132 | signal dsp_r4 : std_logic_vector(DAT_WIDTH downto 0); 133 | 134 | ---------------- DSP48 signals ---------------- 135 | signal dsp_p1 : std_logic_vector(DAT_WIDTH+1 downto 0); 136 | signal dsp_p2 : std_logic_vector(DAT_WIDTH+1 downto 0); 137 | signal dsp_pp : std_logic_vector(DAT_WIDTH+1 downto 0); 138 | signal vldx : std_logic; 139 | signal ena_zz : std_logic_vector(DAT_WIDTH+8 downto 0); 140 | 141 | attribute USE_DSP : string; 142 | attribute USE_DSP of dsp_pp : signal is "YES"; 143 | attribute USE_DSP of dsp_p1 : signal is "YES"; 144 | attribute USE_DSP of dsp_p2 : signal is "YES"; 145 | 146 | begin 147 | 148 | ---------------- Multiplier ---------------- 149 | mult_a1 <= AA1 after td when rising_edge(clk); 150 | mult_a2 <= AA2 after td when rising_edge(clk); 151 | mult_a3 <= AA3 after td when rising_edge(clk); 152 | mult_a4 <= AA4 after td when rising_edge(clk); 153 | 154 | mult_b1 <= cos1 after td when rising_edge(clk); 155 | mult_b2 <= cos2 after td when rising_edge(clk); 156 | mult_b3 <= cos3 after td when rising_edge(clk); 157 | mult_b4 <= cos4 after td when rising_edge(clk); 158 | 159 | ---------------- Counter for phase ---------------- 160 | PR_CNT1: process(clk) is 161 | begin 162 | if rising_edge(clk) then 163 | if (reset = '1') then 164 | ph_in1 <= (others => '0') after TD; 165 | ph_in2 <= (others => '0') after TD; 166 | ph_in3 <= (others => '0') after TD; 167 | ph_in4 <= (others => '0') after TD; 168 | else 169 | if (ENABLE = '1') then 170 | ph_in1 <= ph_in1 + 1 after TD; 171 | ph_in2 <= ph_in2 + 2 after TD; 172 | ph_in3 <= ph_in3 + 3 after TD; 173 | ph_in4 <= ph_in4 + 4 after TD; 174 | end if; 175 | end if; 176 | end if; 177 | end process; 178 | 179 | ---------------- Twiddle part 1 ---------------- 180 | xCRD1: entity work.cordic_dds 181 | generic map ( 182 | DATA_WIDTH => DAT_WIDTH, 183 | PHASE_WIDTH => PHI_WIDTH 184 | ) 185 | port map ( 186 | RESET => reset, 187 | CLK => clk, 188 | PH_IN => ph_in1, 189 | PH_EN => ENABLE, 190 | DT_COS => cos1, 191 | DT_VAL => vldx 192 | ); 193 | 194 | xMLT1: entity work.int_multNxN_dsp48 195 | generic map ( DTW => DAT_WIDTH) 196 | port map ( 197 | DAT_A => mult_a1, 198 | DAT_B => mult_b1, 199 | DAT_Q => mult_p1, 200 | CLK => clk, 201 | RST => reset 202 | ); 203 | 204 | ---------------- Twiddle part 2 ---------------- 205 | xCRD2: entity work.cordic_dds 206 | generic map ( 207 | DATA_WIDTH => DAT_WIDTH, 208 | PHASE_WIDTH => PHI_WIDTH 209 | ) 210 | port map ( 211 | RESET => reset, 212 | CLK => clk, 213 | PH_IN => ph_in2, 214 | PH_EN => ENABLE, 215 | DT_COS => cos2, 216 | DT_VAL => vldx 217 | ); 218 | 219 | 220 | xMLT2: entity work.int_multNxN_dsp48 221 | generic map ( DTW => DAT_WIDTH) 222 | port map ( 223 | DAT_A => mult_a2, 224 | DAT_B => mult_b2, 225 | DAT_Q => mult_p2, 226 | CLK => clk, 227 | RST => reset 228 | ); 229 | 230 | ---------------- Twiddle part 3 ---------------- 231 | xCRD3: entity work.cordic_dds 232 | generic map ( 233 | DATA_WIDTH => DAT_WIDTH, 234 | PHASE_WIDTH => PHI_WIDTH 235 | ) 236 | port map ( 237 | RESET => reset, 238 | CLK => clk, 239 | PH_IN => ph_in3, 240 | PH_EN => ENABLE, 241 | DT_COS => cos3, 242 | DT_VAL => vldx 243 | ); 244 | 245 | xMLT3: entity work.int_multNxN_dsp48 246 | generic map ( DTW => DAT_WIDTH) 247 | port map ( 248 | DAT_A => mult_a3, 249 | DAT_B => mult_b3, 250 | DAT_Q => mult_p3, 251 | CLK => clk, 252 | RST => reset 253 | ); 254 | 255 | ---------------- Twiddle part 4 ---------------- 256 | xCRD4: entity work.cordic_dds 257 | generic map ( 258 | DATA_WIDTH => DAT_WIDTH, 259 | PHASE_WIDTH => PHI_WIDTH 260 | ) 261 | port map ( 262 | RESET => reset, 263 | CLK => clk, 264 | PH_IN => ph_in4, 265 | PH_EN => ENABLE, 266 | DT_COS => cos4, 267 | DT_VAL => vldx 268 | ); 269 | 270 | xMLT4: entity work.int_multNxN_dsp48 271 | generic map ( DTW => DAT_WIDTH) 272 | port map ( 273 | DAT_A => mult_a4, 274 | DAT_B => mult_b4, 275 | DAT_Q => mult_p4, 276 | CLK => clk, 277 | RST => reset 278 | ); 279 | 280 | ---------------- DSP48E2 1-2 ---------------- 281 | dsp_b0 <= AA0 after td when rising_edge(clk); 282 | 283 | dsp_r1 <= mult_p1(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 284 | dsp_r2 <= mult_p2(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 285 | dsp_r3 <= mult_p3(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 286 | dsp_r4 <= mult_p4(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 287 | 288 | ---------------- Round data from 25 to 24 bits ---------------- 289 | pr_rnd: process(clk) is 290 | begin 291 | if rising_edge(clk) then 292 | ---- Round 1 ---- 293 | if (dsp_r1(0) = '0') then 294 | dsp_b1 <= dsp_r1(DAT_WIDTH downto 1) after td; 295 | else 296 | dsp_b1 <= dsp_r1(DAT_WIDTH downto 1) + 1 after td; 297 | end if; 298 | ---- Round 2 ---- 299 | if (dsp_r2(0) = '0') then 300 | dsp_b2 <= dsp_r2(DAT_WIDTH downto 1) after td; 301 | else 302 | dsp_b2 <= dsp_r2(DAT_WIDTH downto 1) + 1 after td; 303 | end if; 304 | ---- Round 3 ---- 305 | if (dsp_r3(0) = '0') then 306 | dsp_b3 <= dsp_r3(DAT_WIDTH downto 1) after td; 307 | else 308 | dsp_b3 <= dsp_r3(DAT_WIDTH downto 1) + 1 after td; 309 | end if; 310 | ---- Round 4 ---- 311 | if (dsp_r4(0) = '0') then 312 | dsp_b4 <= dsp_r4(DAT_WIDTH downto 1) after td; 313 | else 314 | dsp_b4 <= dsp_r4(DAT_WIDTH downto 1) + 1 after td; 315 | end if; 316 | 317 | end if; 318 | end process; 319 | 320 | ---------------- DSP48 signal mapping ---------------- 321 | pr_add: process(clk) is 322 | begin 323 | if rising_edge(clk) then 324 | dsp_p1 <= (dsp_b4(DAT_WIDTH-1) & dsp_b4(DAT_WIDTH-1) & dsp_b4) - 325 | (dsp_b3(DAT_WIDTH-1) & dsp_b3(DAT_WIDTH-1) & dsp_b3) + 326 | (dsp_b2(DAT_WIDTH-1) & dsp_b2(DAT_WIDTH-1) & dsp_b2); 327 | dsp_p2 <= (dsp_b0(DAT_WIDTH-1) & dsp_b0(DAT_WIDTH-1) & dsp_b0) - 328 | (dsp_b1(DAT_WIDTH-1) & dsp_b1(DAT_WIDTH-1) & dsp_b1); 329 | 330 | dsp_pp <= dsp_p1 + dsp_p2; 331 | end if; 332 | end process; 333 | 334 | ena_zz <= ena_zz(ena_zz'left-1 downto 0) & enable after td when rising_edge(clk); 335 | ---------------- Round output data from N+1 to N bits ---------------- 336 | pr_out: process(clk) is 337 | begin 338 | if rising_edge(clk) then 339 | ---- Round 1 ---- 340 | if (dsp_pp(1) = '0') then 341 | DT_WIN <= dsp_pp(DAT_WIDTH+1 downto 2) after td; 342 | else 343 | DT_WIN <= dsp_pp(DAT_WIDTH+1 downto 2) + 1 after td; 344 | end if; 345 | DT_VLD <= ena_zz(ena_zz'left) after td; 346 | end if; 347 | end process; 348 | 349 | end bh_win_5term; -------------------------------------------------------------------------------- /src/tb/tb_windows.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : tb_windows 4 | -- Design : Blackman-Harris Windows 5 | -- Author : Kapitanov Alexander 6 | -- Company : 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | -- Description : Simple model for calculating window functions (upto 7 terms) 10 | -- 11 | ------------------------------------------------------------------------------- 12 | ------------------------------------------------------------------------------- 13 | -- 14 | -- GNU GENERAL PUBLIC LICENSE 15 | -- Version 3, 29 June 2007 16 | -- 17 | -- Copyright (c) 2018 Kapitanov Alexander 18 | -- 19 | -- This program is free software: you can redistribute it and/or modify 20 | -- it under the terms of the GNU General Public License as published by 21 | -- the Free Software Foundation, either version 3 of the License, or 22 | -- (at your option) any later version. 23 | -- 24 | -- You should have received a copy of the GNU General Public License 25 | -- along with this program. If not, see . 26 | -- 27 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 28 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 29 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 30 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 31 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 32 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 33 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 34 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 35 | -- 36 | ------------------------------------------------------------------------------- 37 | ------------------------------------------------------------------------------- 38 | 39 | library ieee; 40 | use ieee.std_logic_1164.all; 41 | use IEEE.std_logic_arith.all; 42 | use IEEE.std_logic_unsigned.all; 43 | 44 | entity tb_windows is 45 | end tb_windows; 46 | 47 | 48 | architecture testbench of tb_windows is 49 | 50 | -------- Common Constants -------- 51 | constant CLK_PERIOD : time := 10 ns; 52 | constant CLK_TD : time := 0.5 ns; 53 | 54 | -------- Phase & Data width -------- 55 | constant PHASE_WIDTH : integer:=11; 56 | constant DATA_WIDTH : integer:=16; 57 | 58 | -------- Signal declaration -------- 59 | signal clk : std_logic:='0'; 60 | signal rst : std_logic:='0'; 61 | signal ph_in : std_logic_vector(PHASE_WIDTH-1 downto 0); 62 | signal ph_en : std_logic; 63 | 64 | -------- Windows constants declaration -------- 65 | constant CONST_WIDTH : integer:=16; 66 | -------- 7-term -------- 67 | constant CNT7_FLT0 : real:=0.271220360585039; 68 | constant CNT7_FLT1 : real:=0.433444612327442; 69 | constant CNT7_FLT2 : real:=0.218004122892930; 70 | constant CNT7_FLT3 : real:=0.065785343295606; 71 | constant CNT7_FLT4 : real:=0.010761867305342; 72 | constant CNT7_FLT5 : real:=0.000770012710581; 73 | constant CNT7_FLT6 : real:=0.000013680883060; 74 | 75 | constant CNT7_STD0 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT7_FLT0*(2.0**(CONST_WIDTH-1)-1.0)), CONST_WIDTH); 76 | constant CNT7_STD1 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT7_FLT1*(2.0**(CONST_WIDTH-1)-1.0)), CONST_WIDTH); 77 | constant CNT7_STD2 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT7_FLT2*(2.0**(CONST_WIDTH-1)-1.0)), CONST_WIDTH); 78 | constant CNT7_STD3 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT7_FLT3*(2.0**(CONST_WIDTH-1)-1.0)), CONST_WIDTH); 79 | constant CNT7_STD4 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT7_FLT4*(2.0**(CONST_WIDTH-1)-1.0)), CONST_WIDTH); 80 | constant CNT7_STD5 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT7_FLT5*(2.0**(CONST_WIDTH-1)-1.0)), CONST_WIDTH); 81 | constant CNT7_STD6 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT7_FLT6*(2.0**(CONST_WIDTH-1)-1.0)), CONST_WIDTH); 82 | 83 | -------- 5-term -------- 84 | -- constant CNT5_FLT0 : real:=0.3232153788877343; 85 | -- constant CNT5_FLT1 : real:=0.4714921439576260; 86 | -- constant CNT5_FLT2 : real:=0.1755341299601972; 87 | -- constant CNT5_FLT3 : real:=0.0284969901061499; 88 | -- constant CNT5_FLT4 : real:=0.0012613570882927; 89 | -------- Flat-top -------- 90 | constant CNT5_FLT0 : real:=1.000; 91 | constant CNT5_FLT1 : real:=1.930; 92 | constant CNT5_FLT2 : real:=1.290; 93 | constant CNT5_FLT3 : real:=0.388; 94 | constant CNT5_FLT4 : real:=0.030; 95 | 96 | constant CNT5_STD0 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT5_FLT0*(2.0**(CONST_WIDTH-2)-1.0)), CONST_WIDTH); 97 | constant CNT5_STD1 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT5_FLT1*(2.0**(CONST_WIDTH-2)-1.0)), CONST_WIDTH); 98 | constant CNT5_STD2 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT5_FLT2*(2.0**(CONST_WIDTH-2)-1.0)), CONST_WIDTH); 99 | constant CNT5_STD3 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT5_FLT3*(2.0**(CONST_WIDTH-2)-1.0)), CONST_WIDTH); 100 | constant CNT5_STD4 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT5_FLT4*(2.0**(CONST_WIDTH-2)-1.0)), CONST_WIDTH); 101 | 102 | -------- 4-term -------- 103 | constant CNT4_FLT0 : real:= 0.35875; 104 | constant CNT4_FLT1 : real:= 0.48829; 105 | constant CNT4_FLT2 : real:= 0.14128; 106 | constant CNT4_FLT3 : real:= 0.01168; 107 | 108 | constant CNT4_STD0 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT4_FLT0*(2.0**(CONST_WIDTH)-1.0)), CONST_WIDTH); 109 | constant CNT4_STD1 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT4_FLT1*(2.0**(CONST_WIDTH)-1.0)), CONST_WIDTH); 110 | constant CNT4_STD2 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT4_FLT2*(2.0**(CONST_WIDTH)-1.0)), CONST_WIDTH); 111 | constant CNT4_STD3 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT4_FLT3*(2.0**(CONST_WIDTH)-1.0)), CONST_WIDTH); 112 | 113 | -------- 3-term -------- 114 | constant CNT3_FLT0 : real:=0.42; 115 | constant CNT3_FLT1 : real:=0.5; 116 | constant CNT3_FLT2 : real:=0.08; 117 | 118 | constant CNT3_STD0 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT3_FLT0*(2.0**(CONST_WIDTH)-16.0)), CONST_WIDTH); 119 | constant CNT3_STD1 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT3_FLT1*(2.0**(CONST_WIDTH)-16.0)), CONST_WIDTH); 120 | constant CNT3_STD2 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT3_FLT2*(2.0**(CONST_WIDTH)-16.0)), CONST_WIDTH); 121 | 122 | -------- 2-term -------- 123 | constant CNT2_FLT0 : real:=0.5434783; 124 | constant CNT2_FLT1 : real:=1.0-CNT2_FLT0; 125 | 126 | constant CNT2_STD0 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT2_FLT0*(2.0**(CONST_WIDTH-1)-1.0)), CONST_WIDTH); 127 | constant CNT2_STD1 : std_logic_vector(CONST_WIDTH-1 downto 0):=conv_std_logic_vector(integer(CNT2_FLT1*(2.0**(CONST_WIDTH-1)-1.0)), CONST_WIDTH); 128 | 129 | signal idl_cos : std_logic_vector(DATA_WIDTH-1 downto 0); 130 | signal idl_sin : std_logic_vector(DATA_WIDTH-1 downto 0); 131 | 132 | signal tst_cos : std_logic_vector(DATA_WIDTH-1 downto 0); 133 | signal tst_sin : std_logic_vector(DATA_WIDTH-1 downto 0); 134 | 135 | type std_array_RxN is array (15 downto 0) of std_logic_vector(DATA_WIDTH-1 downto 0); 136 | 137 | signal del_cos : std_array_RxN; 138 | signal del_sin : std_array_RxN; 139 | 140 | signal res_cos : std_logic_vector(DATA_WIDTH-1 downto 0); 141 | signal res_sin : std_logic_vector(DATA_WIDTH-1 downto 0); 142 | 143 | signal xor_cos : std_logic_vector(DATA_WIDTH-1 downto 0); 144 | signal xor_sin : std_logic_vector(DATA_WIDTH-1 downto 0); 145 | 146 | signal abs_cos : std_logic_vector(DATA_WIDTH-1 downto 0); 147 | signal abs_sin : std_logic_vector(DATA_WIDTH-1 downto 0); 148 | 149 | constant LUT_SIZE : integer:=10; 150 | constant PHI_WIDTH : integer:=14; 151 | 152 | 153 | begin 154 | 155 | ------------------------------------------------------------------------------- 156 | ---------------- Clock and Reset Processes ------------------------------------ 157 | ------------------------------------------------------------------------------- 158 | clk_gen: process 159 | begin 160 | clk <= '1'; 161 | wait for clk_period/2; 162 | clk <= '0'; 163 | wait for clk_period/2; 164 | end process; 165 | 166 | rst_gen: process 167 | begin 168 | rst <= '1'; 169 | wait for clk_period * 4; 170 | rst <= '0'; 171 | wait; 172 | end process; 173 | 174 | ------------------------------------------------------------------------------- 175 | ---------------- Phase Increment for CORDIC and WIN components ---------------- 176 | ------------------------------------------------------------------------------- 177 | clk_phase: process(clk) is 178 | begin 179 | if rising_edge(clk) then 180 | if (rst = '1') then 181 | ph_in <= (others=>'0'); 182 | ph_en <= '0'; 183 | else 184 | ph_en <= '1' after CLK_TD; 185 | if (ph_en = '1') then 186 | ph_in <= ph_in + '1' after CLK_TD; 187 | end if; 188 | end if; 189 | end if; 190 | end process; 191 | 192 | ------------------------------------------------------------------------------- 193 | ---------------- Window function: 7-term Blackman-Harris ---------------------- 194 | ------------------------------------------------------------------------------- 195 | -- xWIN7: entity work.bh_win_7term 196 | -- generic map( 197 | -- PHI_WIDTH => PHASE_WIDTH, 198 | -- DAT_WIDTH => CONST_WIDTH 199 | -- ) 200 | -- port map ( 201 | -- RESET => rst, 202 | -- CLK => clk, 203 | 204 | -- AA0 => CNT7_STD0, 205 | -- AA1 => CNT7_STD1, 206 | -- AA2 => CNT7_STD2, 207 | -- AA3 => CNT7_STD3, 208 | -- AA4 => CNT7_STD4, 209 | -- AA5 => CNT7_STD5, 210 | -- AA6 => CNT7_STD6, 211 | -- ENABLE => ph_en 212 | -- ); 213 | 214 | ------------------------------------------------------------------------------- 215 | ---------------- Window function: 5-term Blackman-Harris ---------------------- 216 | ------------------------------------------------------------------------------- 217 | -- xWIN5: entity work.bh_win_5term 218 | -- generic map( 219 | -- PHI_WIDTH => PHASE_WIDTH, 220 | -- DAT_WIDTH => CONST_WIDTH 221 | -- ) 222 | -- port map ( 223 | -- RESET => rst, 224 | -- CLK => clk, 225 | 226 | -- AA0 => CNT5_STD0, 227 | -- AA1 => CNT5_STD1, 228 | -- AA2 => CNT5_STD2, 229 | -- AA3 => CNT5_STD3, 230 | -- AA4 => CNT5_STD4, 231 | -- ENABLE => ph_en 232 | -- ); 233 | 234 | ------------------------------------------------------------------------------- 235 | ---------------- Window function: 4-term Blackman-Harris ---------------------- 236 | ------------------------------------------------------------------------------- 237 | -- xWIN4: entity work.bh_win_4term 238 | -- generic map ( 239 | -- PHI_WIDTH => PHASE_WIDTH, 240 | -- DAT_WIDTH => CONST_WIDTH 241 | -- ) 242 | -- port map ( 243 | -- RESET => rst, 244 | -- CLK => clk, 245 | 246 | -- AA0 => CNT4_STD0, 247 | -- AA1 => CNT4_STD1, 248 | -- AA2 => CNT4_STD2, 249 | -- AA3 => CNT4_STD3, 250 | -- ENABLE => ph_en 251 | -- ); 252 | 253 | ------------------------------------------------------------------------------- 254 | ---------------- Window function: 3-term Blackman-Harris ---------------------- 255 | ------------------------------------------------------------------------------- 256 | -- xWIN3: entity work.bh_win_3term 257 | -- generic map ( 258 | -- PHI_WIDTH => PHASE_WIDTH, 259 | -- DAT_WIDTH => CONST_WIDTH 260 | -- ) 261 | -- port map ( 262 | -- RESET => rst, 263 | -- CLK => clk, 264 | 265 | -- AA0 => CNT3_STD0, 266 | -- AA1 => CNT3_STD1, 267 | -- AA2 => CNT3_STD2, 268 | -- ENABLE => ph_en 269 | -- ); 270 | 271 | ------------------------------------------------------------------------------- 272 | ---------------- Window function: 2-term Hann & Hamming ----------------------- 273 | ------------------------------------------------------------------------------- 274 | -- xWIN2: entity work.hamming_win 275 | -- generic map ( 276 | -- PHI_WIDTH => PHASE_WIDTH, 277 | -- DAT_WIDTH => CONST_WIDTH 278 | -- ) 279 | -- port map ( 280 | -- RESET => rst, 281 | -- CLK => clk, 282 | 283 | -- AA0 => CNT2_STD0, 284 | -- AA1 => CNT2_STD1, 285 | -- ENABLE => ph_en 286 | -- ); 287 | 288 | -- UUT: entity work.cordic_dds 289 | -- generic map ( 290 | -- PHASE_WIDTH => PHASE_WIDTH, 291 | -- DATA_WIDTH => DATA_WIDTH 292 | -- ) 293 | -- port map ( 294 | -- clk => clk, 295 | -- reset => rst, 296 | -- ph_in => ph_in, 297 | -- ph_en => ph_en, 298 | -- dt_sin => sine, 299 | -- dt_cos => cosine 300 | -- ); 301 | 302 | ------------------------------------------------------------------------------- 303 | ---------------- Taylor generator for sine and cosine ------------------------- 304 | ------------------------------------------------------------------------------- 305 | xTAY: entity work.taylor_sincos 306 | generic map ( 307 | TAY_ORDER => 1, 308 | LUT_SIZE => LUT_SIZE, 309 | PHASE_WIDTH => PHI_WIDTH, 310 | DATA_WIDTH => DATA_WIDTH 311 | ) 312 | port map ( 313 | RST => rst, 314 | CLK => clk, 315 | PHI_ENA => ph_en, 316 | OUT_SIN => tst_sin, 317 | OUT_COS => tst_cos 318 | ); 319 | 320 | xCOM: entity work.taylor_sincos 321 | generic map ( 322 | TAY_ORDER => 1, 323 | LUT_SIZE => PHI_WIDTH-2, 324 | PHASE_WIDTH => PHI_WIDTH, 325 | DATA_WIDTH => DATA_WIDTH 326 | ) 327 | port map ( 328 | RST => rst, 329 | CLK => clk, 330 | PHI_ENA => ph_en, 331 | OUT_SIN => idl_sin, 332 | OUT_COS => idl_cos 333 | ); 334 | 335 | del_cos <= del_cos(del_cos'left-1 downto 0) & idl_sin when rising_edge(clk) and ph_en = '1'; 336 | del_sin <= del_sin(del_sin'left-1 downto 0) & idl_cos when rising_edge(clk) and ph_en = '1'; 337 | 338 | res_cos <= del_cos(3) when rst = '0' else (others=>'0'); 339 | res_sin <= del_sin(3) when rst = '0' else (others=>'0'); 340 | 341 | xor_cos <= res_cos - tst_cos; 342 | xor_sin <= res_sin - tst_sin; 343 | 344 | xFOR: for ii in 0 to DATA_WIDTH-2 generate 345 | abs_cos(ii) <= xor_cos(ii) xor xor_cos(DATA_WIDTH-1); 346 | abs_sin(ii) <= xor_sin(ii) xor xor_sin(DATA_WIDTH-1); 347 | end generate; 348 | 349 | abs_cos(DATA_WIDTH-1) <= '0'; 350 | abs_sin(DATA_WIDTH-1) <= '0'; 351 | 352 | 353 | end testbench; -------------------------------------------------------------------------------- /src/bh_win_7term.vhd: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | -- 3 | -- Title : bh_win_7term 4 | -- Design : Blackman-Harris Windows 5 | -- Author : Kapitanov Alexander 6 | -- Company : 7 | -- E-mail : sallador@bk.ru 8 | -- 9 | -- Description : Simple Blackman-Harris window function: 7- term 10 | -- Configurable data length and number of terms. 11 | -- 12 | -- Constants {0-6} (gain for harmonics): type - REAL (float IEEE-754) 13 | -- 14 | -- > Blackman-Harris: 15 | -- a0 = 0.271220360585039; 16 | -- a1 = 0.433444612327442; 17 | -- a2 = 0.218004122892930; 18 | -- a3 = 0.065785343295606; 19 | -- a4 = 0.010761867305342; 20 | -- a5 = 0.000770012710581; 21 | -- a6 = 0.000013680883060; 22 | -- 23 | ------------------------------------------------------------------------------- 24 | ------------------------------------------------------------------------------- 25 | -- 26 | -- GNU GENERAL PUBLIC LICENSE 27 | -- Version 3, 29 June 2007 28 | -- 29 | -- Copyright (c) 2018 Kapitanov Alexander 30 | -- 31 | -- This program is free software: you can redistribute it and/or modify 32 | -- it under the terms of the GNU General Public License as published by 33 | -- the Free Software Foundation, either version 3 of the License, or 34 | -- (at your option) any later version. 35 | -- 36 | -- You should have received a copy of the GNU General Public License 37 | -- along with this program. If not, see . 38 | -- 39 | -- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 40 | -- APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 41 | -- HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 42 | -- OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 43 | -- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 44 | -- PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 45 | -- IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 46 | -- ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 47 | -- 48 | ------------------------------------------------------------------------------- 49 | library ieee; 50 | use ieee.std_logic_1164.all; 51 | use ieee.std_logic_arith.all; 52 | use ieee.std_logic_signed.all; 53 | 54 | -- library unisim; 55 | -- use unisim.vcomponents.DSP48E1; 56 | -- use unisim.vcomponents.DSP48E2; 57 | 58 | entity bh_win_7term is 59 | generic( 60 | TD : time:=0.5ns; --! Time delay 61 | PHI_WIDTH : integer:=10; --! Signal period = 2^PHI_WIDTH 62 | DAT_WIDTH : integer:=16 --! Output data width 63 | ); 64 | port( 65 | RESET : in std_logic; --! Global reset 66 | CLK : in std_logic; --! System clock 67 | 68 | AA0 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A0 69 | AA1 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A1 70 | AA2 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A2 71 | AA3 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A3 72 | AA4 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A4 73 | AA5 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A4 74 | AA6 : in std_logic_vector(DAT_WIDTH-1 downto 0); -- Constant A4 75 | 76 | ENABLE : in std_logic; --! Input data enable block = NFFT clocks 77 | DT_WIN : out std_logic_vector(DAT_WIDTH-1 downto 0); --! Output (cos) 78 | DT_VLD : out std_logic --! Output data valid 79 | ); 80 | end bh_win_7term; 81 | 82 | architecture bh_win_7term of bh_win_7term is 83 | 84 | ---------------- Cordic signals ---------------- 85 | signal cos1 : std_logic_vector(DAT_WIDTH-1 downto 0); 86 | signal cos2 : std_logic_vector(DAT_WIDTH-1 downto 0); 87 | signal cos3 : std_logic_vector(DAT_WIDTH-1 downto 0); 88 | signal cos4 : std_logic_vector(DAT_WIDTH-1 downto 0); 89 | signal cos5 : std_logic_vector(DAT_WIDTH-1 downto 0); 90 | signal cos6 : std_logic_vector(DAT_WIDTH-1 downto 0); 91 | 92 | signal ph_in1 : std_logic_vector(PHI_WIDTH-1 downto 0); 93 | signal ph_in2 : std_logic_vector(PHI_WIDTH-1 downto 0); 94 | signal ph_in3 : std_logic_vector(PHI_WIDTH-1 downto 0); 95 | signal ph_in4 : std_logic_vector(PHI_WIDTH-1 downto 0); 96 | signal ph_in5 : std_logic_vector(PHI_WIDTH-1 downto 0); 97 | signal ph_in6 : std_logic_vector(PHI_WIDTH-1 downto 0); 98 | 99 | ---------------- Multiplier signals ---------------- 100 | signal mult_a1 : std_logic_vector(DAT_WIDTH-1 downto 0); 101 | signal mult_a2 : std_logic_vector(DAT_WIDTH-1 downto 0); 102 | signal mult_a3 : std_logic_vector(DAT_WIDTH-1 downto 0); 103 | signal mult_a4 : std_logic_vector(DAT_WIDTH-1 downto 0); 104 | signal mult_a5 : std_logic_vector(DAT_WIDTH-1 downto 0); 105 | signal mult_a6 : std_logic_vector(DAT_WIDTH-1 downto 0); 106 | 107 | signal mult_b1 : std_logic_vector(DAT_WIDTH-1 downto 0); 108 | signal mult_b2 : std_logic_vector(DAT_WIDTH-1 downto 0); 109 | signal mult_b3 : std_logic_vector(DAT_WIDTH-1 downto 0); 110 | signal mult_b4 : std_logic_vector(DAT_WIDTH-1 downto 0); 111 | signal mult_b5 : std_logic_vector(DAT_WIDTH-1 downto 0); 112 | signal mult_b6 : std_logic_vector(DAT_WIDTH-1 downto 0); 113 | 114 | 115 | signal mult_p1 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 116 | signal mult_p2 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 117 | signal mult_p3 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 118 | signal mult_p4 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 119 | signal mult_p5 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 120 | signal mult_p6 : std_logic_vector(2*DAT_WIDTH-1 downto 0); 121 | 122 | ---------------- Product signals ---------------- 123 | signal dsp_b0 : std_logic_vector(DAT_WIDTH-1 downto 0); 124 | signal dsp_b1 : std_logic_vector(DAT_WIDTH-1 downto 0); 125 | signal dsp_b2 : std_logic_vector(DAT_WIDTH-1 downto 0); 126 | signal dsp_b3 : std_logic_vector(DAT_WIDTH-1 downto 0); 127 | signal dsp_b4 : std_logic_vector(DAT_WIDTH-1 downto 0); 128 | signal dsp_b5 : std_logic_vector(DAT_WIDTH-1 downto 0); 129 | signal dsp_b6 : std_logic_vector(DAT_WIDTH-1 downto 0); 130 | 131 | signal dsp_r1 : std_logic_vector(DAT_WIDTH downto 0); 132 | signal dsp_r2 : std_logic_vector(DAT_WIDTH downto 0); 133 | signal dsp_r3 : std_logic_vector(DAT_WIDTH downto 0); 134 | signal dsp_r4 : std_logic_vector(DAT_WIDTH downto 0); 135 | signal dsp_r5 : std_logic_vector(DAT_WIDTH downto 0); 136 | signal dsp_r6 : std_logic_vector(DAT_WIDTH downto 0); 137 | 138 | ---------------- DSP48 signals ---------------- 139 | signal dsp_p1 : std_logic_vector(DAT_WIDTH+1 downto 0); 140 | signal dsp_p2 : std_logic_vector(DAT_WIDTH+1 downto 0); 141 | signal dsp_p3 : std_logic_vector(DAT_WIDTH+1 downto 0); 142 | signal dsp_pp : std_logic_vector(DAT_WIDTH+1 downto 0); 143 | signal dsp_pz : std_logic_vector(DAT_WIDTH+1 downto 0); 144 | signal dsp_q1 : std_logic_vector(DAT_WIDTH+1 downto 0); 145 | signal dsp_q2 : std_logic_vector(DAT_WIDTH+1 downto 0); 146 | 147 | signal ena_zz : std_logic_vector(DAT_WIDTH+9 downto 0); 148 | 149 | attribute USE_DSP : string; 150 | attribute USE_DSP of dsp_pp : signal is "YES"; 151 | attribute USE_DSP of dsp_p1 : signal is "YES"; 152 | attribute USE_DSP of dsp_p2 : signal is "YES"; 153 | attribute USE_DSP of dsp_p3 : signal is "YES"; 154 | attribute USE_DSP of dsp_pz : signal is "YES"; 155 | attribute USE_DSP of dsp_q1 : signal is "YES"; 156 | attribute USE_DSP of dsp_q2 : signal is "YES"; 157 | 158 | begin 159 | 160 | ---------------- Multiplier ---------------- 161 | mult_a1 <= AA1 after td when rising_edge(clk); 162 | mult_a2 <= AA2 after td when rising_edge(clk); 163 | mult_a3 <= AA3 after td when rising_edge(clk); 164 | mult_a4 <= AA4 after td when rising_edge(clk); 165 | mult_a5 <= AA5 after td when rising_edge(clk); 166 | mult_a6 <= AA6 after td when rising_edge(clk); 167 | 168 | mult_b1 <= cos1 after td when rising_edge(clk); 169 | mult_b2 <= cos2 after td when rising_edge(clk); 170 | mult_b3 <= cos3 after td when rising_edge(clk); 171 | mult_b4 <= cos4 after td when rising_edge(clk); 172 | mult_b5 <= cos5 after td when rising_edge(clk); 173 | mult_b6 <= cos6 after td when rising_edge(clk); 174 | 175 | ---------------- Counter for phase ---------------- 176 | PR_CNT1: process(clk) is 177 | begin 178 | if rising_edge(clk) then 179 | if (reset = '1') then 180 | ph_in1 <= (others => '0') after TD; 181 | ph_in2 <= (others => '0') after TD; 182 | ph_in3 <= (others => '0') after TD; 183 | ph_in4 <= (others => '0') after TD; 184 | ph_in5 <= (others => '0') after TD; 185 | ph_in6 <= (others => '0') after TD; 186 | else 187 | if (ENABLE = '1') then 188 | ph_in1 <= ph_in1 + 1 after TD; 189 | ph_in2 <= ph_in2 + 2 after TD; 190 | ph_in3 <= ph_in3 + 3 after TD; 191 | ph_in4 <= ph_in4 + 4 after TD; 192 | ph_in5 <= ph_in5 + 5 after TD; 193 | ph_in6 <= ph_in6 + 6 after TD; 194 | end if; 195 | end if; 196 | end if; 197 | end process; 198 | 199 | ---------------- Twiddle part 1 ---------------- 200 | xCRD1: entity work.cordic_dds 201 | generic map ( 202 | DATA_WIDTH => DAT_WIDTH, 203 | PHASE_WIDTH => PHI_WIDTH 204 | ) 205 | port map ( 206 | RESET => reset, 207 | CLK => clk, 208 | PH_IN => ph_in1, 209 | PH_EN => ENABLE, 210 | DT_COS => cos1, 211 | DT_VAL => open 212 | ); 213 | 214 | xMLT1: entity work.int_multNxN_dsp48 215 | generic map ( DTW => DAT_WIDTH) 216 | port map ( 217 | DAT_A => mult_a1, 218 | DAT_B => mult_b1, 219 | DAT_Q => mult_p1, 220 | CLK => clk, 221 | RST => reset 222 | ); 223 | 224 | ---------------- Twiddle part 2 ---------------- 225 | xCRD2: entity work.cordic_dds 226 | generic map ( 227 | DATA_WIDTH => DAT_WIDTH, 228 | PHASE_WIDTH => PHI_WIDTH 229 | ) 230 | port map ( 231 | RESET => reset, 232 | CLK => clk, 233 | PH_IN => ph_in2, 234 | PH_EN => ENABLE, 235 | DT_COS => cos2, 236 | DT_VAL => open 237 | ); 238 | 239 | 240 | xMLT2: entity work.int_multNxN_dsp48 241 | generic map ( DTW => DAT_WIDTH) 242 | port map ( 243 | DAT_A => mult_a2, 244 | DAT_B => mult_b2, 245 | DAT_Q => mult_p2, 246 | CLK => clk, 247 | RST => reset 248 | ); 249 | 250 | ---------------- Twiddle part 3 ---------------- 251 | xCRD3: entity work.cordic_dds 252 | generic map ( 253 | DATA_WIDTH => DAT_WIDTH, 254 | PHASE_WIDTH => PHI_WIDTH 255 | ) 256 | port map ( 257 | RESET => reset, 258 | CLK => clk, 259 | PH_IN => ph_in3, 260 | PH_EN => ENABLE, 261 | DT_COS => cos3, 262 | DT_VAL => open 263 | ); 264 | 265 | xMLT3: entity work.int_multNxN_dsp48 266 | generic map ( DTW => DAT_WIDTH) 267 | port map ( 268 | DAT_A => mult_a3, 269 | DAT_B => mult_b3, 270 | DAT_Q => mult_p3, 271 | CLK => clk, 272 | RST => reset 273 | ); 274 | 275 | ---------------- Twiddle part 4 ---------------- 276 | xCRD4: entity work.cordic_dds 277 | generic map ( 278 | DATA_WIDTH => DAT_WIDTH, 279 | PHASE_WIDTH => PHI_WIDTH 280 | ) 281 | port map ( 282 | RESET => reset, 283 | CLK => clk, 284 | PH_IN => ph_in4, 285 | PH_EN => ENABLE, 286 | DT_COS => cos4, 287 | DT_VAL => open 288 | ); 289 | 290 | xMLT4: entity work.int_multNxN_dsp48 291 | generic map ( DTW => DAT_WIDTH) 292 | port map ( 293 | DAT_A => mult_a4, 294 | DAT_B => mult_b4, 295 | DAT_Q => mult_p4, 296 | CLK => clk, 297 | RST => reset 298 | ); 299 | 300 | ---------------- Twiddle part 5 ---------------- 301 | xCRD5: entity work.cordic_dds 302 | generic map ( 303 | DATA_WIDTH => DAT_WIDTH, 304 | PHASE_WIDTH => PHI_WIDTH 305 | ) 306 | port map ( 307 | RESET => reset, 308 | CLK => clk, 309 | PH_IN => ph_in5, 310 | PH_EN => ENABLE, 311 | DT_COS => cos5, 312 | DT_VAL => open 313 | ); 314 | 315 | xMLT5: entity work.int_multNxN_dsp48 316 | generic map ( DTW => DAT_WIDTH) 317 | port map ( 318 | DAT_A => mult_a5, 319 | DAT_B => mult_b5, 320 | DAT_Q => mult_p5, 321 | CLK => clk, 322 | RST => reset 323 | ); 324 | 325 | ---------------- Twiddle part 6 ---------------- 326 | xCRD6: entity work.cordic_dds 327 | generic map ( 328 | DATA_WIDTH => DAT_WIDTH, 329 | PHASE_WIDTH => PHI_WIDTH 330 | ) 331 | port map ( 332 | RESET => reset, 333 | CLK => clk, 334 | PH_IN => ph_in6, 335 | PH_EN => ENABLE, 336 | DT_COS => cos6, 337 | DT_VAL => open 338 | ); 339 | 340 | xMLT6: entity work.int_multNxN_dsp48 341 | generic map ( DTW => DAT_WIDTH) 342 | port map ( 343 | DAT_A => mult_a6, 344 | DAT_B => mult_b6, 345 | DAT_Q => mult_p6, 346 | CLK => clk, 347 | RST => reset 348 | ); 349 | 350 | ---------------- DSP48E2 1-2 ---------------- 351 | dsp_b0 <= AA0 after td when rising_edge(clk); 352 | 353 | dsp_r1 <= mult_p1(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 354 | dsp_r2 <= mult_p2(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 355 | dsp_r3 <= mult_p3(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 356 | dsp_r4 <= mult_p4(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 357 | dsp_r5 <= mult_p5(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 358 | dsp_r6 <= mult_p6(2*DAT_WIDTH-2 downto DAT_WIDTH-2) after td when rising_edge(clk); 359 | 360 | ---------------- Round data from 25 to 24 bits ---------------- 361 | pr_rnd: process(clk) is 362 | begin 363 | if rising_edge(clk) then 364 | ---- Round 1 ---- 365 | if (dsp_r1(0) = '0') then 366 | dsp_b1 <= dsp_r1(DAT_WIDTH downto 1) after td; 367 | else 368 | dsp_b1 <= dsp_r1(DAT_WIDTH downto 1) + 1 after td; 369 | end if; 370 | ---- Round 2 ---- 371 | if (dsp_r2(0) = '0') then 372 | dsp_b2 <= dsp_r2(DAT_WIDTH downto 1) after td; 373 | else 374 | dsp_b2 <= dsp_r2(DAT_WIDTH downto 1) + 1 after td; 375 | end if; 376 | ---- Round 3 ---- 377 | if (dsp_r3(0) = '0') then 378 | dsp_b3 <= dsp_r3(DAT_WIDTH downto 1) after td; 379 | else 380 | dsp_b3 <= dsp_r3(DAT_WIDTH downto 1) + 1 after td; 381 | end if; 382 | ---- Round 4 ---- 383 | if (dsp_r4(0) = '0') then 384 | dsp_b4 <= dsp_r4(DAT_WIDTH downto 1) after td; 385 | else 386 | dsp_b4 <= dsp_r4(DAT_WIDTH downto 1) + 1 after td; 387 | end if; 388 | ---- Round 5 ---- 389 | if (dsp_r5(0) = '0') then 390 | dsp_b5 <= dsp_r5(DAT_WIDTH downto 1) after td; 391 | else 392 | dsp_b5 <= dsp_r5(DAT_WIDTH downto 1) + 1 after td; 393 | end if; 394 | 395 | ---- Round 6 ---- 396 | if (dsp_r6(0) = '0') then 397 | dsp_b6 <= dsp_r6(DAT_WIDTH downto 1) after td; 398 | else 399 | dsp_b6 <= dsp_r6(DAT_WIDTH downto 1) + 1 after td; 400 | end if; 401 | end if; 402 | end process; 403 | 404 | ---------------- DSP48 signal mapping ---------------- 405 | pr_add: process(clk) is 406 | begin 407 | if rising_edge(clk) then 408 | ---- Firts stage of addition ---- 409 | dsp_p1 <= (dsp_b0(DAT_WIDTH-1) & dsp_b0(DAT_WIDTH-1) & dsp_b0) - 410 | (dsp_b1(DAT_WIDTH-1) & dsp_b1(DAT_WIDTH-1) & dsp_b1) after td; 411 | dsp_p2 <= (dsp_b2(DAT_WIDTH-1) & dsp_b2(DAT_WIDTH-1) & dsp_b2) - 412 | (dsp_b3(DAT_WIDTH-1) & dsp_b3(DAT_WIDTH-1) & dsp_b3) after td; 413 | dsp_p3 <= (dsp_b4(DAT_WIDTH-1) & dsp_b4(DAT_WIDTH-1) & dsp_b4) - 414 | (dsp_b5(DAT_WIDTH-1) & dsp_b5(DAT_WIDTH-1) & dsp_b5) after td; 415 | 416 | dsp_pz <= (dsp_b6(DAT_WIDTH-1) & dsp_b6(DAT_WIDTH-1) & dsp_b6) after td; 417 | ---- Second stage of addition ---- 418 | dsp_q1 <= dsp_p1 + dsp_p2 after td; 419 | dsp_q2 <= dsp_p3 + dsp_pz after td; 420 | ---- Last stage of addition ---- 421 | dsp_pp <= dsp_q1 + dsp_q2 after td; 422 | end if; 423 | end process; 424 | 425 | ena_zz <= ena_zz(ena_zz'left-1 downto 0) & enable after td when rising_edge(clk); 426 | ---------------- Round output data from N+1 to N bits ---------------- 427 | pr_out: process(clk) is 428 | begin 429 | if rising_edge(clk) then 430 | ---- Round 1 ---- 431 | if (dsp_pp(1) = '0') then 432 | DT_WIN <= dsp_pp(DAT_WIDTH+1 downto 2) after td; 433 | else 434 | DT_WIN <= dsp_pp(DAT_WIDTH+1 downto 2) + 1 after td; 435 | end if; 436 | DT_VLD <= ena_zz(ena_zz'left) after td; 437 | end if; 438 | end process; 439 | 440 | end bh_win_7term; --------------------------------------------------------------------------------