├── 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;
--------------------------------------------------------------------------------