├── .gitignore
├── Makefile
├── README.md
├── bench
└── cpp
│ ├── .gitignore
│ ├── Makefile
│ ├── cordic_tb.cpp
│ ├── fft.h
│ ├── fftw.c
│ ├── quadtbl_ctbl.hex
│ ├── quadtbl_ltbl.hex
│ ├── quadtbl_qtbl.hex
│ ├── quadtbl_tb.cpp
│ ├── quarterwav.hex
│ ├── testb.h
│ └── topolar_tb.cpp
├── doc
├── Makefile
├── gpl-3.0.pdf
├── lgpl-3.0.pdf
└── src
│ ├── gpl-3.0.tex
│ └── lgpl-3.0.tex
├── rtl
├── Makefile
├── cordic.h
├── cordic.v
├── quadtbl.h
├── quadtbl.v
├── quadtbl_ctbl.hex
├── quadtbl_ltbl.hex
├── quadtbl_qtbl.hex
├── quarterwav.hex
├── quarterwav.v
├── seqcordic.h
├── seqcordic.v
├── seqpolar.h
├── seqpolar.v
├── sintable.hex
├── sintable.v
├── topolar.h
└── topolar.v
└── sw
├── .gitignore
├── Makefile
├── basiccordic.cpp
├── basiccordic.h
├── cordiclib.cpp
├── cordiclib.h
├── hexfile.cpp
├── hexfile.h
├── legal.cpp
├── legal.h
├── main.cpp
├── quadtbl.cpp
├── quadtbl.h
├── seqcordic.cpp
├── seqcordic.h
├── seqpolar.cpp
├── seqpolar.h
├── sintable.cpp
├── sintable.h
├── topolar.cpp
└── topolar.h
/.gitignore:
--------------------------------------------------------------------------------
1 | legal.txt
2 | .svn
3 | xilinx
4 | obj_dir
5 | obj-pc
6 | obj-zip
7 | *.o
8 | *.a
9 | *.vcd
10 | .swp
11 | .*.swp
12 | .*.swo
13 | svn-commit*
14 | *_tb
15 | *_tb.dbl
16 | *dbg.txt
17 | *dump.txt
18 | *debug.txt
19 | tags
20 | cpudefs.h
21 | design.h
22 | octave-workspace
23 | core
24 | *.32t
25 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | ##
3 | ## Filename: Makefile
4 | ## {{{
5 | ## Project: A series of CORDIC related projects
6 | ##
7 | ## Purpose: Provides a master Makefile for the project, coordinating the
8 | ## build of the core generator, documents, test benches, and
9 | ## Verilog code.
10 | ##
11 | ## The core generator is highly configurable. You can adjust the
12 | ## configuration parameters in the sw/Makefile, or run it outside of any
13 | ## Makefile context.
14 | ##
15 | ## Targets include:
16 | ## all Builds everything
17 | ## clean Removes all build products
18 | ## doc Builds the documentation (licenses)
19 | ## rtl Runs Verilator on the Verilog files
20 | ## sw Builds the core generator
21 | ## bench Builds the bench testing software
22 | ##
23 | ## Creator: Dan Gisselquist, Ph.D.
24 | ## Gisselquist Technology, LLC
25 | ##
26 | ################################################################################
27 | ## }}}
28 | ## Copyright (C) 2017-2024, Gisselquist Technology, LLC
29 | ## {{{
30 | ## This program is free software (firmware): you can redistribute it and/or
31 | ## modify it under the terms of the GNU General Public License as published
32 | ## by the Free Software Foundation, either version 3 of the License, or (at
33 | ## your option) any later version.
34 | ##
35 | ## This program is distributed in the hope that it will be useful, but WITHOUT
36 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
37 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
38 | ## for more details.
39 | ##
40 | ## You should have received a copy of the GNU General Public License along
41 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no
42 | ## target there if the PDF file isn't present.) If not, see
43 | ## for a copy.
44 | ## }}}
45 | ## License: GPL, v3, as defined and found on www.gnu.org,
46 | ## {{{
47 | ## http://www.gnu.org/licenses/gpl.html
48 | ##
49 | ##
50 | ################################################################################
51 | ##
52 | ## }}}
53 | .PHONY: all clean doc rtl sw bench
54 | all: sw rtl bench
55 | SUBMAKE := make --no-print-directory -C
56 |
57 | sw:
58 | $(SUBMAKE) sw
59 |
60 | rtl: sw
61 | $(SUBMAKE) rtl
62 |
63 | bench: rtl
64 | $(SUBMAKE) bench/cpp
65 |
66 | test: bench
67 | $(SUBMAKE) bench/cpp test
68 |
69 | clean:
70 | $(SUBMAKE) sw clean
71 | $(SUBMAKE) rtl clean
72 | $(SUBMAKE) bench/cpp clean
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | This repository is designed to hold a variety of demonstration sinewave
2 | generators. These sinewave generators have been discussed and used as examples
3 | as part of the [ZipCPU Blog on zipcpu.com](http://zipcpu.com). If you watch
4 | carefully, you may find examples here before they are posted, as I'm going to
5 | be doing my development here.
6 |
7 | The basic approach in this project is that of a software core generator,
8 | found in the [sw](sw/) directory. This generator can be used to make
9 | logic in the [rtl](rtl/) directory.
10 |
11 | The reference that I have used to build the CORDIC algorithms within this
12 | repository comes from a [Cordic
13 | Survey](http://www.andraka.com/files/crdcsrvy.pdf), by Ray Andraka.
14 |
15 | ## Blog posts
16 |
17 | There have been several blog posts based upon the code within this repository.
18 | These include:
19 |
20 | 1. [No PI for you!](http://zipcpu.com/dsp/2017/06/15/no-pi-for-you.html), a
21 | discussion of the ideal units of phase within an FPGA.
22 |
23 | 1. How to build the simplest sine-wave in Verilog, based upon a [table-based generator](http://zipcpu.com/dsp/2017/07/11/simplest-sinewave-generator.html)
24 |
25 | 1. How to do the same thing, but with only a [Quarter-Wave sine table](http://zipcpu.com/dsp/2017/08/26/quarterwave.html).
26 |
27 | 1. How to use a [CORDIC to generate both sines and cosines](http://zipcpu.com/dsp/2017/08/30/cordic.html). Ultimately this is about how to convert from polar to rectangular coordinates as well.
28 |
29 | 1. How to use a [CORDIC to calculate an arctan](http://zipcpu.com/dsp/2017/09/01/topolar.html). This is also known as the rectangular to polar conversion mode of the CORDIC.
30 |
31 | 1. A [CORDIC testbench](http://zipcpu.com/dsp/2017/10/02/cordic-tb.html) for
32 | the [sine/cosine generation capability](http://zipcpu.com/dsp/2017/08/30/cordic.html)
33 |
34 | - This [test bench](bench/cpp/cordic_tb.cpp) depends upon the discussion of [statistical quantization effects](http://zipcpu.com/dsp/2017/09/27/quantization.html) that will hinder the performance of the CORDIC.
35 |
36 | Another post on [the ZipCPU blog](http://zipcpu.com) discussed [how a CORDIC can be used](http://zipcpu.com/dsp/2017/09/16/pwm-demo.html) to evaluate an [improved(?) PWM signal](http://zipcpu.com/dsp/2017/09/04/pwm-reinvention.html).
37 |
38 | If time permits, I have another sine wave generator that uses fewer
39 | logic resources than the CORDIC above, but that requires two multiplies and
40 | three RAM's--yet doesn't suffer from the phase truncation effects of the CORDIC.
41 | I look forward to having the opportunity to post this in the future.
42 |
43 | ## License
44 |
45 | All of the software (Makefile, C++) code in this repository is released under
46 | the [GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html). The Verilog RTL
47 | code generated by this core generator is licensed under
48 | [LGPLv3](https://www.gnu.org/licenses/lgpl-3.0.en.html). If these conditions
49 | are not sufficient for your needs, other licenses terms may be purchased.
50 |
--------------------------------------------------------------------------------
/bench/cpp/.gitignore:
--------------------------------------------------------------------------------
1 | *.PASS
2 |
--------------------------------------------------------------------------------
/bench/cpp/Makefile:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | ##
3 | ## Filename: bench/cpp/Makefile
4 | ## {{{
5 | ## Project: A series of CORDIC related projects
6 | ##
7 | ## Purpose: This file directs the build of a Verilator-based test bench to
8 | ## prove that the cordic generator's outputs work. This build
9 | ## must be called after building in bench/rtl, since it depends upon the
10 | ## products of that build.
11 | ## }}}
12 | ## Targets:
13 | ## {{{
14 | ## all: Builds cordic_tb
15 | ##
16 | ## clean: Cleans up all of the build products, together with the .vcd
17 | ## files, so you can start over from scratch.
18 | ##
19 | ## cordic_tb: A test bench for the basic (polar to rectangular)
20 | ## cordic. Prints success or failure on the last line.
21 | ##
22 | ## This program depends upon having FFTW installed.
23 | ##
24 | ## seqcordic_tb: This is almost identical to cordic_tb above, save that
25 | ## the CORDIC is of a sequential (not pipelined)
26 | ## implementation. It shares code with cordic_tb.
27 | ##
28 | ## topolar_tb: A test bench for the rectangular to polar coordinate
29 | ## conversion form of the cordic. Prints success or
30 | ## failure on the last line.
31 | ##
32 | ## seqpolar_tb: As with seqcordic_tb, this is almost identical to
33 | ## topolar_tb, save that this is a test of the sequential
34 | ## implementation rather than the parallel one.
35 | ##
36 | ## quadtbl_tb: Test the quadratic interpolation sinewave generator.
37 | ##
38 | ## test: Runs all testbenches
39 | ##
40 | ## Creator: Dan Gisselquist, Ph.D.
41 | ## Gisselquist Technology, LLC
42 | ##
43 | ################################################################################
44 | ## }}}
45 | ## Copyright (C) 2017-2024, Gisselquist Technology, LLC
46 | ## {{{
47 | ## This program is free software (firmware): you can redistribute it and/or
48 | ## modify it under the terms of the GNU General Public License as published
49 | ## by the Free Software Foundation, either version 3 of the License, or (at
50 | ## your option) any later version.
51 | ##
52 | ## This program is distributed in the hope that it will be useful, but WITHOUT
53 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
54 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
55 | ## for more details.
56 | ##
57 | ## You should have received a copy of the GNU General Public License along
58 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no
59 | ## target there if the PDF file isn't present.) If not, see
60 | ## for a copy.
61 | ## }}}
62 | ## License: GPL, v3, as defined and found on www.gnu.org,
63 | ## {{{
64 | ## http://www.gnu.org/licenses/gpl.html
65 | ##
66 | ##
67 | ################################################################################
68 | ##
69 | ## }}}
70 | all: cordic_tb topolar_tb quadtbl_tb seqcordic_tb seqpolar_tb
71 | ## Flags
72 | ## {{{
73 | CXX := g++
74 | RTLD := ../../rtl
75 | ROBJD:= $(RTLD)/obj_dir
76 | VERILATOR := verilator
77 | VERILATOR_ROOT ?= $(shell bash -c '$(VERILATOR) -V|grep VERILATOR_ROOT| head -1|sed -e " s/^.*=\s*//"')
78 | VROOT:= $(VERILATOR_ROOT)
79 | INCS := -I$(VROOT)/include -I$(RTLD) -I$(ROBJD)
80 | VSRCS := $(VROOT)/include/verilated.cpp $(VROOT)/include/verilated_vcd_c.cpp $(VROOT)/include/verilated_threads.cpp
81 | TBOBJ := $(ROBJD)/Vcordic__ALL.a
82 | STBOBJ := $(ROBJD)/Vseqcordic__ALL.a
83 | PLOBJ := $(ROBJD)/Vtopolar__ALL.a
84 | SPLOBJ := $(ROBJD)/Vseqpolar__ALL.a
85 | QTOBJ := $(ROBJD)/Vquadtbl__ALL.a
86 | CFLAGS := -faligned-new -g -Og -Wall $(INCS) # -faligned-new
87 | ## }}}
88 |
89 | ## Build the various test benches
90 | ## {{{
91 | cordic_tb: cordic_tb.cpp $(TBOBJ) $(ROBJD)/Vcordic.h testb.h fft.h fftw.c
92 | $(CXX) $(CFLAGS) cordic_tb.cpp fftw.c $(VSRCS) $(TBOBJ) -lfftw3 -lpthread -o $@
93 |
94 | seqcordic_tb: cordic_tb.cpp $(STBOBJ) $(ROBJD)/Vseqcordic.h testb.h fft.h fftw.c
95 | $(CXX) $(CFLAGS) -D CLOCKS_PER_OUTPUT cordic_tb.cpp fftw.c $(VSRCS) $(STBOBJ) -lfftw3 -lpthread -o $@
96 |
97 | topolar_tb: topolar_tb.cpp $(PLOBJ) $(ROBJD)/Vtopolar.h testb.h
98 | $(CXX) $(CFLAGS) topolar_tb.cpp $(VSRCS) $(PLOBJ) -lpthread -o $@
99 |
100 | seqpolar_tb: topolar_tb.cpp $(SPLOBJ) $(ROBJD)/Vseqpolar.h testb.h
101 | $(CXX) $(CFLAGS) -DCLOCKS_PER_OUTPUT topolar_tb.cpp $(VSRCS) $(SPLOBJ) -lpthread -o $@
102 |
103 | quadtbl_tb: quadtbl_tb.cpp $(PLOBJ) $(ROBJD)/Vquadtbl.h testb.h fft.h fftw.c
104 | $(CXX) $(CFLAGS) quadtbl_tb.cpp fftw.c $(VSRCS) $(QTOBJ) -lfftw3 -lpthread -o $@
105 | ## }}}
106 |
107 | ## Test target
108 | .PHONY: test
109 | ## {{{
110 | test: cordic_tb.PASS topolar_tb.PASS quadtbl_tb.PASS seqcordic_tb.PASS seqpolar_tb.PASS
111 |
112 | cordic_tb.PASS: cordic_tb
113 | ./cordic_tb
114 | touch cordic_tb.PASS
115 |
116 | topolar_tb.PASS: topolar_tb
117 | ./topolar_tb
118 | touch topolar_tb.PASS
119 |
120 | quadtbl_tb.PASS: quadtbl_tb
121 | ./quadtbl_tb
122 | touch quadtbl_tb.PASS
123 |
124 | seqcordic_tb.PASS: seqcordic_tb
125 | ./seqcordic_tb
126 | touch seqcordic_tb.PASS
127 |
128 | seqpolar_tb.PASS: seqpolar_tb
129 | ./seqpolar_tb
130 | touch seqpolar_tb.PASS
131 | ## }}}
132 |
133 | .PHONY: clean
134 | ## {{{
135 | clean:
136 | rm -f cordic_tb topolar_tb quadtbl_tb
137 | rm -f cordic_tb.vcd topolar_tb.vcd quadtbl_tb.vcd
138 | rm -f seqcordic_tb seqpolar_tb
139 | rm -f seqcordic_tb.vcd seqpolar_tb.vcd
140 | ## }}}
141 |
142 |
--------------------------------------------------------------------------------
/bench/cpp/cordic_tb.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: bench/cpp/cordic_tb.cpp
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: A quick test bench to determine if the basic cordic module
8 | // works.
9 | //
10 | // Creator: Dan Gisselquist, Ph.D.
11 | // Gisselquist Technology, LLC
12 | //
13 | ////////////////////////////////////////////////////////////////////////////////
14 | // }}}
15 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
16 | // {{{
17 | // This program is free software (firmware): you can redistribute it and/or
18 | // modify it under the terms of the GNU General Public License as published
19 | // by the Free Software Foundation, either version 3 of the License, or (at
20 | // your option) any later version.
21 | //
22 | // This program is distributed in the hope that it will be useful, but WITHOUT
23 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
24 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 | // for more details.
26 | //
27 | // You should have received a copy of the GNU General Public License along
28 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
29 | // target there if the PDF file isn't present.) If not, see
30 | // for a copy.
31 | // }}}
32 | // License: GPL, v3, as defined and found on www.gnu.org,
33 | // {{{
34 | // http://www.gnu.org/licenses/gpl.html
35 | //
36 | //
37 | ////////////////////////////////////////////////////////////////////////////////
38 | //
39 | // }}}
40 | #include
41 |
42 | #include
43 | #include
44 | #ifdef CLOCKS_PER_OUTPUT
45 | # include "Vseqcordic.h"
46 | # include "seqcordic.h"
47 | # define BASECLASS Vseqcordic
48 | #else
49 | # include "Vcordic.h"
50 | # include "cordic.h"
51 | # define BASECLASS Vcordic
52 | #endif
53 | #include "fft.h"
54 | #include "testb.h"
55 |
56 | class CORDIC_TB : public TESTB {
57 | bool m_debug;
58 | public:
59 | // CORDIC_TB constructor
60 | // {{{
61 | CORDIC_TB(void) {
62 | m_debug = true;
63 | #ifdef CLOCKS_PER_OUTPUT
64 | m_core->i_stb = 0;
65 | #else // CLOCKS_PER_OUTPUT
66 | m_core->i_ce = 1;
67 | #endif // CLOCKS_PER_OUTPUT
68 | m_core->i_xval = (1ul<<(IW-1))-1;
69 | m_core->i_yval = 0;
70 | m_core->i_phase = 0;
71 | m_core->i_aux = 0;
72 | #ifdef HAS_RESET_WIRE
73 | #ifdef ASYNC_RESET
74 | m_core->i_areset_n = 0;
75 | #else
76 | m_core->i_reset = 1;
77 | #endif
78 | tick();
79 | #endif
80 | }
81 | // }}}
82 | };
83 |
84 | const int LGNSAMPLES=PW;
85 | const int NSAMPLES=(1ul<opentrace("seqcordic_tb.vcd");
107 | #else
108 | tb->opentrace("cordic_tb.vcd");
109 | #endif
110 | // }}}
111 |
112 | // Reset the design
113 | // {{{
114 | tb->reset();
115 | // }}}
116 |
117 | // scale
118 | // {{{
119 | scale = tb->m_core->i_xval * (double)tb->m_core->i_xval;
120 | scale += tb->m_core->i_yval * (double)tb->m_core->i_yval;
121 | scale = sqrt(scale);
122 | // }}}
123 |
124 | // Simulation loop for NSAMPLES time steps
125 | // {{{
126 | idx = 0;
127 | for(int i=0; im_core->i_phase = sv >> (-shift);
137 | } else
138 | tb->m_core->i_phase = i << shift;
139 | pdata[i] = tb->m_core->i_phase;
140 | ixval[i] = tb->m_core->i_xval;
141 | iyval[i] = tb->m_core->i_yval;
142 | tb->m_core->i_aux = 1;
143 |
144 | // Step the clock
145 | // {{{
146 | #ifdef CLOCKS_PER_OUTPUT
147 | // Step by CLOCKS_PER_OUTPUT clock ticks
148 | // {{{
149 | tb->m_core->i_stb = 1;
150 | for(int j=0; jtick();
152 | tb->m_core->i_stb = 0;
153 | assert(!tb->m_core->o_done);
154 | }
155 |
156 | tb->tick();
157 | assert(tb->m_core->o_done);
158 | assert(tb->m_core->o_aux);
159 | // }}}
160 | #else
161 | tb->tick();
162 | #endif
163 | // }}}
164 |
165 | // Copy the results to an array for later analysis
166 | // {{{
167 | if (tb->m_core->o_aux) {
168 | shift = (8*sizeof(int)-OW);
169 | // Make our values signed..
170 | xval[idx] = tb->m_core->o_xval << (shift);
171 | yval[idx] = tb->m_core->o_yval << (shift);
172 | xval[idx] >>= shift;
173 | yval[idx] >>= shift;
174 | // printf("%08x<<%d: %08x %08x\n", (unsigned)pdata[i], shift, xval[idx], yval[idx]);
175 | idx++;
176 | }
177 | // }}}
178 | }
179 | // }}}
180 |
181 | // Flush any final data through the system
182 | // {{{
183 | #ifndef CLOCKS_PER_OUTPUT
184 | tb->m_core->i_aux = 0;
185 | while(tb->m_core->o_aux) {
186 | int shift = (8*sizeof(int)-OW);
187 | tb->m_core->i_aux = 0;
188 | tb->tick();
189 |
190 | if (tb->m_core->o_aux) {
191 | xval[idx] = tb->m_core->o_xval << (shift);
192 | yval[idx] = tb->m_core->o_yval << (shift);
193 | xval[idx] >>= shift;
194 | yval[idx] >>= shift;
195 | // printf("%08x %08x\n", xval[idx], yval[idx]);
196 | idx++;
197 | assert(idx <= NSAMPLES);
198 | }
199 | }
200 | #endif
201 | // }}}
202 |
203 | if (false) { // Dump data for offline analysis
204 | // {{{
205 | FILE *fdbg = fopen("cordicdbg.dbl","w");
206 | for(int k=0; k OW) {
243 | dxval *= 1./(double)(1u< IW+1) {
246 | dxval *= 1./(double)(1u>>(-shift));
247 | dyval *= 1./(double)(1u>>(-shift));
248 | }
249 |
250 |
251 | // Solve min_a sum (d-a*v)^2
252 | // min_a sum d^2 + a*d*v + a^2 v*v
253 | // 0 = d*v + 2*a*v*v
254 | // a = sumxw / 2 / sumsq
255 | //
256 | // Measure the magnitude of what we placed into the input
257 | imag+=ixval[i] *(double)ixval[i] +iyval[i] *(double)iyval[i];
258 | // The magnitude we get on the output
259 | mag += xval[i] * (double)xval[i] + yval[i] * (double)yval[i];
260 | // The error between the value requested and the value resulting
261 | err = (dxval - xval[i]) * (dxval - xval[i]);
262 | err+= (dyval - yval[i]) * (dyval - yval[i]);
263 |
264 | // Let's run some other tests, to see if we managed to get the
265 | // gain right
266 | sumxy += dxval * xval[i];
267 | sumxy += dyval * yval[i];
268 | sumsq += xval[i] * (double)xval[i] + yval[i]*(double)yval[i];
269 | sumd += dxval *dxval +dyval * dyval;
270 | averr += err;
271 |
272 | if (PW<10) {
273 | printf("%6d %6d -> %9.2f %9.2f (predicted) -> %f err (%f), mag=%f\n",
274 | xval[i], yval[i], dxval, dyval, err, averr, mag);
275 | }
276 | err = sqrt(err);
277 | if (err > mxerr)
278 | mxerr = err;
279 | }
280 | // }}}
281 |
282 | bool failed = false;
283 | double expected_err;
284 |
285 | expected_err = QUANTIZATION_VARIANCE
286 | + PHASE_VARIANCE_RAD*scale*scale*GAIN*GAIN;
287 |
288 | // Scale the error to a per-sample error
289 | // {{{
290 | // Error _magnitude_ should *never* be negative--a simple internal check
291 | averr /= (NSAMPLES);
292 | averr = sqrt(averr);
293 | if (mag <= 0) {
294 | printf("ERR: Negative magnitude, %f\n", mag);
295 | goto test_failed;
296 | }
297 | mag /= (NSAMPLES);
298 | mag = sqrt(mag);
299 | if (imag <= 0) {
300 | printf("ERR: Negative i-magnitude, %f\n", imag);
301 | goto test_failed;
302 | }
303 | imag /= (NSAMPLES);
304 | imag = sqrt(imag);
305 | // }}}
306 |
307 | // What average error do we expect? and did we pass?
308 |
309 | // Report on the results
310 | // {{{
311 | // int_-1/2^1/2 x^2 dx
312 | // = x^3/3 |_-1/2^1/2
313 | // = 1/24 + 1/24 = 1/12
314 | // Two of these added together is 2/12 per item
315 | printf("AVG Err: %.6f Units (%.6f Relative, %.4f Units expected)\n",
316 | averr, averr / mag, sqrt(expected_err));
317 | if (averr > 1.5 * sqrt(expected_err))
318 | failed = true;
319 | printf("MAX Err: %.6f Units (%.6f Relative, %.6f threshold)\n", mxerr,
320 | mxerr / mag, 5.2*sqrt(expected_err));
321 | if (mxerr > 5.2 * sqrt(expected_err)) {
322 | printf("ERR: Maximum error is out of bounds\n");
323 | failed = true;
324 | }
325 | printf(" Mag : %.6f\n", mag);
326 | printf("(Gain) : %.6f\n", GAIN);
327 | printf("(alpha): %.6f\n", sumxy / sumsq);
328 | scale *= GAIN;
329 | printf("CNR : %.2f dB (expected %.2f dB)\n",
330 | 10.0*log(scale * scale
331 | / (averr * averr))/log(10.0),
332 | BEST_POSSIBLE_CNR);
333 | if (fabs(sumxy / sumsq - 1.0) > 0.01) {
334 | printf("(alpha)is out of bounds!\n");
335 | goto test_failed;
336 | } if (failed)
337 | goto test_failed;
338 | // }}}
339 |
340 | // Estimate and check the spurious free dynamic range
341 | // {{{
342 | if ((PW < 26)&&(NSAMPLES == (1ul << PW))) {
343 | typedef std::complex COMPLEX;
344 | COMPLEX *outpt;
345 | const unsigned long FFTLEN=(1ul< spur)
367 | spur = tmp;
368 | }
369 |
370 | printf("SFDR = %7.2f dBc\n",
371 | 10*log(master / spur)/log(10.));
372 | } else if (PW >= 26)
373 | printf("Too many phase bits ... skipping SFDR calculation\n");
374 | // }}}
375 |
376 | printf("SUCCESS!!\n");
377 | exit(EXIT_SUCCESS);
378 |
379 | test_failed:
380 | printf("TEST FAILURE\n");
381 | exit(EXIT_FAILURE);
382 | }
383 |
384 |
--------------------------------------------------------------------------------
/bench/cpp/fft.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: bench/cpp/fft.h
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: To provide a wrapper around generic access to the FFTW FFT
8 | // routines.
9 | //
10 | // Creator: Dan Gisselquist, Ph.D.
11 | // Gisselquist Technology, LLC
12 | //
13 | ////////////////////////////////////////////////////////////////////////////////
14 | // }}}
15 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
16 | // {{{
17 | // This program is free software (firmware): you can redistribute it and/or
18 | // modify it under the terms of the GNU General Public License as published
19 | // by the Free Software Foundation, either version 3 of the License, or (at
20 | // your option) any later version.
21 | //
22 | // This program is distributed in the hope that it will be useful, but WITHOUT
23 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
24 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 | // for more details.
26 | //
27 | // You should have received a copy of the GNU General Public License along
28 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
29 | // target there if the PDF file isn't present.) If not, see
30 | // for a copy.
31 | // }}}
32 | // License: GPL, v3, as defined and found on www.gnu.org,
33 | // {{{
34 | // http://www.gnu.org/licenses/gpl.html
35 | //
36 | //
37 | ////////////////////////////////////////////////////////////////////////////////
38 | //
39 | // }}}
40 | #ifndef FFT_H
41 | #define FFT_H
42 |
43 | #include
44 |
45 | #ifdef __cplusplus
46 | extern "C" {
47 | // We'll provide the same basic access interfaces that Numerical recipes used.
48 | // The actual method may, or may not therefore, be Numerical Recipes based
49 | extern void numer_fft(double *data, unsigned nn, int isign);
50 | extern unsigned nextlg(unsigned long vl);
51 | }
52 | #endif
53 |
54 | #ifndef M_PI
55 | #define M_PI (3.1415926535897932384626433832795028841971693993751)
56 | #endif
57 |
58 | #ifdef __cplusplus
59 | typedef std::complex COMPLEX;
60 | inline void cfft(double *cdata, unsigned clen) { numer_fft(cdata, clen, -1); }
61 | inline void icfft(double *cdata, unsigned clen) { numer_fft(cdata, clen, 1); }
62 | inline void cfft(COMPLEX *cdata, unsigned clen) { numer_fft((double *)cdata, clen, -1); }
63 | inline void icfft(COMPLEX *cdata, unsigned clen) { numer_fft((double *)cdata, clen, 1); }
64 | #else
65 | extern void cfft(double *cdata, unsigned clen);
66 | extern void icfft(double *cdata, unsigned clen);
67 | #endif
68 |
69 | #endif
70 |
71 |
--------------------------------------------------------------------------------
/bench/cpp/fftw.c:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: bench/cpp/fftw.c
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: To call the Fastest Fourier Transform in the West library
8 | // for generic FFT requests.
9 | //
10 | // Creator: Dan Gisselquist, Ph.D.
11 | // Gisselquist Technology, LLC
12 | //
13 | ////////////////////////////////////////////////////////////////////////////////
14 | // }}}
15 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
16 | // {{{
17 | // This program is free software (firmware): you can redistribute it and/or
18 | // modify it under the terms of the GNU General Public License as published
19 | // by the Free Software Foundation, either version 3 of the License, or (at
20 | // your option) any later version.
21 | //
22 | // This program is distributed in the hope that it will be useful, but WITHOUT
23 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
24 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 | // for more details.
26 | //
27 | // You should have received a copy of the GNU General Public License along
28 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
29 | // target there if the PDF file isn't present.) If not, see
30 | // for a copy.
31 | // }}}
32 | // License: GPL, v3, as defined and found on www.gnu.org,
33 | // {{{
34 | // http://www.gnu.org/licenses/gpl.html
35 | //
36 | //
37 | ////////////////////////////////////////////////////////////////////////////////
38 | //
39 | // }}}
40 | #include
41 | #include "fft.h"
42 | #include
43 | // #include
44 |
45 | #include
46 |
47 | unsigned nextlg(unsigned long vl) {
48 | unsigned long r;
49 | static unsigned long lstv=-1, lstr = 0;
50 |
51 | if (vl == lstv) return lstr;
52 |
53 | assert(vl > 0);
54 | for(r=1; r for a copy.
31 | // }}}
32 | // License: GPL, v3, as defined and found on www.gnu.org,
33 | // {{{
34 | // http://www.gnu.org/licenses/gpl.html
35 | //
36 | //
37 | ////////////////////////////////////////////////////////////////////////////////
38 | //
39 | // }}}
40 | #include
41 |
42 | #include
43 | #include
44 | #include "Vquadtbl.h"
45 | #include "quadtbl.h"
46 | #include "fft.h"
47 | #include "testb.h"
48 |
49 | #ifndef HAS_AUX_WIRES
50 | #error "This test-bench depends upon the quadtbl component having\n\tbeen configured for an aux wire."
51 | #endif
52 |
53 | class QUADTBL_TB : public TESTB {
54 | bool m_debug;
55 | public:
56 | // QUADTBL_TB() constructor
57 | // {{{
58 | QUADTBL_TB(void) {
59 | m_debug = true;
60 | m_core->i_ce = 1;
61 | m_core->i_phase = 0;
62 | m_core->i_aux = 0;
63 | #ifdef HAS_RESET_WIRE
64 | #ifdef ASYNC_RESET
65 | m_core->i_areset_n = 0;
66 | #else
67 | m_core->i_reset = 1;
68 | #endif
69 | tick();
70 | #endif
71 | }
72 | // }}}
73 | };
74 |
75 | const long LGNSAMPLES=(PW>26)?26:PW;
76 | const long NSAMPLES=(1ul<opentrace("quadtbl_tb.vcd");
92 | tb->reset();
93 |
94 | // Main simulation loop
95 | // {{{
96 | idx = 0;
97 | for(long i=0; im_core->i_phase = sv >> (-shift);
107 | } else
108 | tb->m_core->i_phase = ((long)i) << shift;
109 | pdata[i] = (long)tb->m_core->i_phase;
110 | tb->m_core->i_aux = 1;
111 | tb->tick();
112 |
113 | if (tb->m_core->o_aux) {
114 | shift = (8*sizeof(sdata[0])-OW);
115 | // Make our values signed..
116 | sdata[idx] = tb->m_core->o_sin;
117 | sdata[idx] <<= shift;
118 | sdata[idx] >>= shift;
119 | idx++;
120 | }
121 | }
122 | // }}}
123 |
124 | // Flush any last data from the core
125 | // {{{
126 | tb->m_core->i_aux = 0;
127 | shift = (8*sizeof(sdata[0])-OW);
128 | while(tb->m_core->o_aux) {
129 | tb->m_core->i_aux = 0;
130 | tb->tick();
131 |
132 | if (tb->m_core->o_aux) {
133 | sdata[idx] = tb->m_core->o_sin;
134 | sdata[idx] <<= shift;
135 | sdata[idx] >>= shift;
136 | idx++;
137 | assert(idx <= NSAMPLES);
138 | }
139 | }
140 | // }}}
141 |
142 | // Computer and write out some debugging outputs
143 | // {{{
144 | FILE *fdbg = fopen("quadtbl.32t","w");
145 |
146 | double mxerr = 0.0;
147 | int imxv = 0, imnv = 0;
148 | for(int i=0; imxerr)
165 | mxerr = fabs(dsin-sdata[i]);
166 | if (sdata[i] > imxv)
167 | imxv = sdata[i];
168 | else if (sdata[i] < imnv)
169 | imnv = sdata[i];
170 | } fclose(fdbg);
171 | // }}}
172 |
173 | // Report on the results
174 | // {{{
175 | printf("MXERR: %f (Expected %f)\n", mxerr, TBL_ERR);
176 | if (fabs(mxerr) > fabs(TBL_ERR) + 2.)
177 | failed = true;
178 | printf("MXVAL: 0x%08x\n", imxv);
179 | printf("MNVAL: 0x%08x\n", imnv);
180 | // }}}
181 |
182 | if (failed)
183 | goto test_failed;
184 |
185 | // Estimate the spurious free dynamic range
186 | // {{{
187 | if ((PW < 26)&&(NSAMPLES == (1ul << PW))) {
188 | typedef std::complex COMPLEX;
189 | COMPLEX *outpt;
190 | const unsigned long FFTLEN=(1ul< spur)
212 | spur = tmp;
213 | }
214 |
215 | printf("SFDR = %7.2f dBc\n",
216 | 10*log(master / spur)/log(10.));
217 | } else if (PW >= 26)
218 | printf("Too many phase bits ... skipping SFDR calculation\n");
219 | // }}}
220 |
221 | printf("SUCCESS!!\n");
222 | exit(EXIT_SUCCESS);
223 |
224 | test_failed:
225 | printf("TEST FAILURE\n");
226 | exit(EXIT_FAILURE);
227 | }
228 |
229 |
--------------------------------------------------------------------------------
/bench/cpp/quarterwav.hex:
--------------------------------------------------------------------------------
1 | ../../rtl/quarterwav.hex
--------------------------------------------------------------------------------
/bench/cpp/testb.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: bench/cpp/testb.h
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: A wrapper for a common interface to a clocked FPGA core
8 | // begin exercised in Verilator.
9 | //
10 | // Creator: Dan Gisselquist, Ph.D.
11 | // Gisselquist Technology, LLC
12 | //
13 | ////////////////////////////////////////////////////////////////////////////////
14 | // }}}
15 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
16 | // {{{
17 | // This program is free software (firmware): you can redistribute it and/or
18 | // modify it under the terms of the GNU General Public License as published
19 | // by the Free Software Foundation, either version 3 of the License, or (at
20 | // your option) any later version.
21 | //
22 | // This program is distributed in the hope that it will be useful, but WITHOUT
23 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
24 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 | // for more details.
26 | //
27 | // You should have received a copy of the GNU General Public License along
28 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
29 | // target there if the PDF file isn't present.) If not, see
30 | // for a copy.
31 | // }}}
32 | // License: GPL, v3, as defined and found on www.gnu.org,
33 | // {{{
34 | // http://www.gnu.org/licenses/gpl.html
35 | //
36 | //
37 | ////////////////////////////////////////////////////////////////////////////////
38 | //
39 | // }}}
40 | #ifndef TESTB_H
41 | #define TESTB_H
42 |
43 | #include
44 | #include
45 | #include
46 |
47 | #define TBASSERT(TB,A) do { if (!(A)) { (TB).closetrace(); } assert(A); } while(0);
48 |
49 | template class TESTB {
50 | public:
51 | VA *m_core;
52 | VerilatedVcdC* m_trace;
53 | unsigned long m_tickcount;
54 |
55 | TESTB(void) : m_trace(NULL), m_tickcount(0l) {
56 | m_core = new VA;
57 | Verilated::traceEverOn(true);
58 | m_core->i_clk = 0;
59 | eval(); // Get our initial values set properly.
60 | }
61 | virtual ~TESTB(void) {
62 | closetrace();
63 | delete m_core;
64 | m_core = NULL;
65 | }
66 |
67 | virtual void opentrace(const char *vcdname) {
68 | if (!m_trace) {
69 | m_trace = new VerilatedVcdC;
70 | m_core->trace(m_trace, 99);
71 | m_trace->open(vcdname);
72 | }
73 | }
74 |
75 | virtual void closetrace(void) {
76 | if (m_trace) {
77 | m_trace->close();
78 | delete m_trace;
79 | m_trace = NULL;
80 | }
81 | }
82 |
83 | virtual void eval(void) {
84 | m_core->eval();
85 | }
86 |
87 | virtual void tick(void) {
88 | m_tickcount++;
89 |
90 | // Make sure we have our evaluations straight before the top
91 | // of the clock. This is necessary since some of the
92 | // connection modules may have made changes, for which some
93 | // logic depends. This forces that logic to be recalculated
94 | // before the top of the clock.
95 | eval();
96 | if (m_trace) m_trace->dump(10*m_tickcount-2);
97 | m_core->i_clk = 1;
98 | eval();
99 | if (m_trace) m_trace->dump(10*m_tickcount);
100 | m_core->i_clk = 0;
101 | eval();
102 | if (m_trace) {
103 | m_trace->dump(10*m_tickcount+5);
104 | m_trace->flush();
105 | }
106 | }
107 |
108 | virtual void reset(void) {
109 | #ifdef HAS_RESET_WIRE
110 | #ifdef ASYNC_RESET
111 | m_core->i_areset_n = 0;
112 | #else
113 | m_core->i_reset = 1;
114 | #endif
115 | #ifdef HAS_AUX_WIRE
116 | m_core->i_aux = 0;
117 | #endif
118 | tick();
119 | #ifdef ASYNC_RESET
120 | m_core->i_areset_n = 1;
121 | #else
122 | m_core->i_reset = 0;
123 | #endif
124 | // printf("RESET\n");
125 | #else
126 | #ifdef HAS_AUX_WIRE
127 | m_core->i_aux = 0;
128 | tick();
129 | #endif
130 | #endif
131 | }
132 |
133 | unsigned long tickcount(void) {
134 | return m_tickcount;
135 | }
136 | };
137 |
138 | #endif
139 |
--------------------------------------------------------------------------------
/bench/cpp/topolar_tb.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: bench/cpp/topolar_tb.cpp
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: A quick test bench to determine if the rectangular to polar
8 | // cordic module works.
9 | //
10 | // Creator: Dan Gisselquist, Ph.D.
11 | // Gisselquist Technology, LLC
12 | //
13 | ////////////////////////////////////////////////////////////////////////////////
14 | // }}}
15 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
16 | // {{{
17 | // This program is free software (firmware): you can redistribute it and/or
18 | // modify it under the terms of the GNU General Public License as published
19 | // by the Free Software Foundation, either version 3 of the License, or (at
20 | // your option) any later version.
21 | //
22 | // This program is distributed in the hope that it will be useful, but WITHOUT
23 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
24 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 | // for more details.
26 | //
27 | // You should have received a copy of the GNU General Public License along
28 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
29 | // target there if the PDF file isn't present.) If not, see
30 | // for a copy.
31 | // }}}
32 | // License: GPL, v3, as defined and found on www.gnu.org,
33 | // {{{
34 | // http://www.gnu.org/licenses/gpl.html
35 | //
36 | //
37 | ////////////////////////////////////////////////////////////////////////////////
38 | //
39 | // }}}
40 | #include
41 |
42 | #include
43 | #include
44 | #ifdef CLOCKS_PER_OUTPUT
45 | # include "Vseqpolar.h"
46 | # include "seqpolar.h"
47 | # define BASECLASS Vseqpolar
48 | #else
49 | # include "Vtopolar.h"
50 | # include "topolar.h"
51 | # define BASECLASS Vtopolar
52 | #endif
53 | #include "testb.h"
54 |
55 | // TOPOLAR_TB
56 | // {{{
57 | class TOPOLAR_TB : public TESTB {
58 | bool m_debug;
59 | public:
60 |
61 | TOPOLAR_TB(void) {
62 | // {{{
63 | m_debug = true;
64 | #ifdef WITH_RESET
65 | #ifdef ASYNC_RESET
66 | m_core->i_areset_n = 0;
67 | #else
68 | m_core->i_reset = 1;
69 | #endif
70 | #endif
71 | #ifdef CLOCKS_PER_OUTPUT
72 | m_core->i_stb = 0;
73 | #else
74 | m_core->i_ce = 1;
75 | #endif
76 | m_core->i_xval = 0;
77 | m_core->i_yval = 0;
78 | m_core->i_aux = 0;
79 | tick();
80 | // }}}
81 | }
82 | };
83 | // }}}
84 |
85 | const int LGNSAMPLES=PW;
86 | const int NSAMPLES=(1<opentrace("seqpolar_tb.vcd");
115 | #else
116 | tb->opentrace("topolar_tb.vcd");
117 | #endif
118 | // }}}
119 |
120 | tb->reset();
121 |
122 | // Run the simulation
123 | // {{{
124 | shift = (8*sizeof(long)-OW);
125 | pshift = (8*sizeof(long)-PW);
126 | idx = 0;
127 | for(int i=0; im_core->i_xval = ixval[i];
146 | tb->m_core->i_yval = iyval[i];
147 | tb->m_core->i_aux = 1;
148 |
149 | #ifdef CLOCKS_PER_OUTPUT
150 | // Wait for the result to be ready
151 | // {{{
152 | tb->m_core->i_stb = 1;
153 | for(int j=0; jtick();
155 | tb->m_core->i_stb = 0;
156 | assert(!tb->m_core->o_done);
157 | assert( tb->m_core->o_busy);
158 | }
159 |
160 | tb->tick();
161 | assert(!tb->m_core->o_busy);
162 | assert(tb->m_core->o_done);
163 | assert(tb->m_core->o_aux);
164 | // }}}
165 | #else
166 | // One data input per clock
167 | tb->tick();
168 | #endif
169 |
170 | if (tb->m_core->o_aux) {
171 | // {{{
172 | long lv;
173 | lv = (long)tb->m_core->o_mag;
174 | lv <<= shift;
175 | lv >>= shift;
176 | omag[idx] = (int)lv;
177 |
178 | lv = tb->m_core->o_phase;
179 | lv <<= pshift;
180 | lv >>= pshift;
181 | ophase[idx] = (int)lv;
182 | //printf("%08x %08x -> %08x %08x\n",
183 | // ixval[idx], iyval[idx],
184 | // omag[idx], ophase[idx]);
185 | idx++;
186 | // }}}
187 | }
188 | // }}}
189 | }
190 |
191 | #ifndef CLOCKS_PER_OUTPUT
192 | // {{{
193 | tb->m_core->i_aux = 0;
194 | while(tb->m_core->o_aux) {
195 | tb->m_core->i_aux = 0;
196 | tb->tick();
197 |
198 | if (tb->m_core->o_aux) {
199 | long lv;
200 | lv = (long)tb->m_core->o_mag;
201 | lv <<= shift;
202 | lv >>= shift;
203 | omag[idx] = (int)lv;
204 |
205 | lv = tb->m_core->o_phase;
206 | lv <<= pshift;
207 | lv >>= pshift;
208 | ophase[idx] = (int)lv;
209 | //printf("%08x %08x -> %08x %08x\n",
210 | // ixval[idx], iyval[idx],
211 | // omag[idx], ophase[idx]);
212 | idx++;
213 | }
214 | }
215 | // }}}
216 | #endif
217 | // }}}
218 |
219 | // Get some statistics on the results
220 | // {{{
221 | double mxperr = 0.0, mxverr = 0.0;
222 | for(int i=0; i MAXPHASE/2.)
230 | dperr -= MAXPHASE;
231 | while (dperr < -MAXPHASE/2.)
232 | dperr += MAXPHASE;
233 | if (fabs(dperr) > mxperr)
234 | mxperr = fabs(dperr);
235 | sum_perr += dperr * dperr;
236 |
237 | emag = imag[i] * GAIN;// * sqrt(2);
238 | // if (IW+1 > OW)
239 | // emag = emag / pow(2.,(IW-1-OW));
240 | // else if (OW > IW+1)
241 | // emag = emag * pow(2.,(IW-1-OW));
242 | emag = imag[i] * pow(2.,(IW-1-OW));
243 |
244 | // omag should equal imag * GAIN
245 | mgerr = fabs(omag[i] - emag * GAIN);
246 | if (mgerr > mxverr)
247 | mxverr = mgerr;
248 |
249 | if (epdata > MAXPHASE/2)
250 | epdata -= MAXPHASE;
251 | //printf("%08x %08x -> %6d %08x/%12d [%9.6f %12.1f],[%9.6f %13.1f]\n",
252 | // ixval[i], iyval[i],
253 | // omag[i], ophase[i],ophase[i],
254 | // emag, epdata,
255 | // mgerr, dperr);
256 | }
257 | // }}}
258 |
259 | if(false) {
260 | // Generate an Octave-readable file for debugging (if necessary)
261 | // {{{
262 | FILE *dbgfp;
263 | dbgfp = fopen("topolar.32t", "w");
264 | assert(dbgfp);
265 |
266 | for(int k=0; k MAXPHASE/2.)
277 | dperr -= MAXPHASE;
278 | while (dperr < -MAXPHASE/2.)
279 | dperr += MAXPHASE;
280 | ovals[4] = (int)dperr;
281 | fwrite(ovals, sizeof(ovals[0]), sizeof(ovals)/sizeof(ovals[0]), dbgfp);
282 | }
283 |
284 | fclose(dbgfp);
285 | // }}}
286 | }
287 |
288 | sum_perr /= NSAMPLES;
289 |
290 | bool failed_test = false;
291 | double expected_phase_err;
292 |
293 | // First phase error: based upon the smallest arctan difference
294 | // between samples.
295 | //
296 | // expected_phase_err = atan2(1,(1<<(IW-1))) * RAD_TO_PHASE;
297 | // expected_phase_err *= expected_phase_err;
298 | //
299 | // expected_phase_err=pow((1<<(IW-1)),-2)*RAD_TO_PHASE*RAD_TO_PHASE/12.;
300 | //
301 | // expected_phase_err += QUANTIZATION_VARIANCE;
302 | // expected_phase_err *= (1./12.);
303 | expected_phase_err = 0.0;
304 | // Plus any truncation error in the in the phase values
305 | // Swap the units from radians to integer phase units
306 | expected_phase_err += PHASE_VARIANCE_RAD
307 | * RAD_TO_PHASE * RAD_TO_PHASE;
308 | expected_phase_err = sqrt(expected_phase_err);
309 | if (expected_phase_err < 1.0)
310 | expected_phase_err = 1.0;
311 | if (mxperr > 3.4 * expected_phase_err)
312 | failed_test = true;
313 |
314 | if (mxverr > 2.0 * sqrt(QUANTIZATION_VARIANCE))
315 | failed_test = true;
316 |
317 | printf("Max phase error: %.2f (%.6f Rel)\n", mxperr,
318 | mxperr / (2.0 * (1<<(PW-1))));
319 | printf("Max magnitude error: %9.6f, expect %.2f\n", mxverr,
320 | 2.0 * sqrt(QUANTIZATION_VARIANCE));
321 | printf("Avg phase err: %9.6f, expect %.2f\n", sqrt(sum_perr),
322 | sqrt(PHASE_VARIANCE_RAD) * RAD_TO_PHASE);
323 |
324 | if (failed_test) {
325 | printf("TEST FAILED!!\n");
326 | exit(EXIT_FAILURE);
327 | } else {
328 | printf("SUCCESS\n");
329 | exit(EXIT_SUCCESS);
330 | }
331 | }
332 |
--------------------------------------------------------------------------------
/doc/Makefile:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | ##
3 | ## Filename: doc/Makefile
4 | ## {{{
5 | ## Project: A series of CORDIC related projects
6 | ##
7 | ## Purpose: To coordinate the build of documentation PDFs from their
8 | ## LaTeX sources.
9 | ##
10 | ## Targets include:
11 | ## all Builds all documents
12 | ##
13 | ## lgpl-3.0.pdf Builds the LGPL license these files are released
14 | ## under.
15 | ##
16 | ## Creator: Dan Gisselquist, Ph.D.
17 | ## Gisselquist Technology, LLC
18 | ##
19 | ################################################################################
20 | ## }}}
21 | ## Copyright (C) 2017-2024, Gisselquist Technology, LLC
22 | ## {{{
23 | ## This program is free software (firmware): you can redistribute it and/or
24 | ## modify it under the terms of the GNU General Public License as published
25 | ## by the Free Software Foundation, either version 3 of the License, or (at
26 | ## your option) any later version.
27 | ##
28 | ## This program is distributed in the hope that it will be useful, but WITHOUT
29 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
30 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
31 | ## for more details.
32 | ##
33 | ## You should have received a copy of the GNU General Public License along
34 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no
35 | ## target there if the PDF file isn't present.) If not, see
36 | ## for a copy.
37 | ## }}}
38 | ## License: GPL, v3, as defined and found on www.gnu.org,
39 | ## {{{
40 | ## http://www.gnu.org/licenses/gpl.html
41 | ##
42 | ##
43 | ################################################################################
44 | ##
45 | ## }}}
46 | all: pdf
47 | pdf: lgpl gpl
48 | DSRC := src
49 |
50 | LGPL=lgpl-3.0
51 | .PHONY: lgpl
52 | lgpl: $(LGPL).pdf
53 |
54 | $(LGPL).pdf: $(DSRC)/$(LGPL).tex
55 | latex $(DSRC)/$(LGPL).tex
56 | latex $(DSRC)/$(LGPL).tex
57 | dvips -q -z -t letter -P pdf -o $(LGPL).ps $(LGPL).dvi
58 | ps2pdf -dAutoRotatePages=/All $(LGPL).ps $(LGPL).pdf
59 | rm $(LGPL).dvi $(LGPL).log $(LGPL).aux $(LGPL).ps
60 |
61 | GPL=gpl-3.0
62 | .PHONY: gpl
63 | gpl: $(GPL).pdf
64 |
65 | $(GPL).pdf: $(DSRC)/$(GPL).tex
66 | latex $(DSRC)/$(GPL).tex
67 | latex $(DSRC)/$(GPL).tex
68 | dvips -q -z -t letter -P pdf -o $(GPL).ps $(GPL).dvi
69 | ps2pdf -dAutoRotatePages=/All $(GPL).ps $(GPL).pdf
70 | rm $(GPL).dvi $(GPL).log $(GPL).aux $(GPL).ps
71 |
72 | .PHONY: clean
73 | clean:
74 | rm -f $(DSRC)/*.dvi $(DSRC)/*.log
75 | rm -f $(DSRC)/*.aux $(DSRC)/*.toc
76 | rm -f $(DSRC)/*.lot $(DSRC)/*.lof
77 | rm -f $(DSRC)/*.out spec.ps spec.pdf
78 | rm -f $(LGPL).pdf $(GPL).pdf
79 |
80 |
--------------------------------------------------------------------------------
/doc/gpl-3.0.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZipCPU/cordic/8ede08a1865d87a357a3a2c188206e843dd9bde6/doc/gpl-3.0.pdf
--------------------------------------------------------------------------------
/doc/lgpl-3.0.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ZipCPU/cordic/8ede08a1865d87a357a3a2c188206e843dd9bde6/doc/lgpl-3.0.pdf
--------------------------------------------------------------------------------
/doc/src/lgpl-3.0.tex:
--------------------------------------------------------------------------------
1 | \documentclass[11pt]{article}
2 |
3 | % match lgpl-3.0.txt
4 | \renewcommand{\labelenumii}{\alph{enumii})}
5 | \renewcommand{\labelenumiii}{\arabic{enumiii})}
6 |
7 | \title{GNU LESSER GENERAL PUBLIC LICENSE}
8 | \date{Version 3, 29 June 2007}
9 |
10 | \begin{document}
11 | \maketitle
12 |
13 | \begin{center}
14 | {\parindent 0in
15 |
16 | Copyright \copyright\ 2007 Free Software Foundation, Inc. \texttt{http://fsf.org/}
17 |
18 | \bigskip
19 | Everyone is permitted to copy and distribute verbatim copies of this
20 |
21 | license document, but changing it is not allowed.}
22 |
23 | \end{center}
24 |
25 |
26 | This version of the GNU Lesser General Public License incorporates
27 | the terms and conditions of version 3 of the GNU General Public
28 | License, supplemented by the additional permissions listed below.
29 |
30 | \begin{enumerate}
31 | \addtocounter{enumi}{-1} % start at 0
32 |
33 | \item Additional Definitions.
34 |
35 | As used herein, ``this License'' refers to version 3 of the GNU Lesser
36 | General Public License, and the ``GNU GPL'' refers to version 3 of the GNU
37 | General Public License.
38 |
39 | ``The Library'' refers to a covered work governed by this License,
40 | other than an Application or a Combined Work as defined below.
41 |
42 | An ``Application'' is any work that makes use of an interface provided
43 | by the Library, but which is not otherwise based on the Library.
44 | Defining a subclass of a class defined by the Library is deemed a mode
45 | of using an interface provided by the Library.
46 |
47 | A ``Combined Work'' is a work produced by combining or linking an
48 | Application with the Library. The particular version of the Library
49 | with which the Combined Work was made is also called the ``Linked
50 | Version''.
51 |
52 | The ``Minimal Corresponding Source'' for a Combined Work means the
53 | Corresponding Source for the Combined Work, excluding any source code
54 | for portions of the Combined Work that, considered in isolation, are
55 | based on the Application, and not on the Linked Version.
56 |
57 | The ``Corresponding Application Code'' for a Combined Work means the
58 | object code and/or source code for the Application, including any data
59 | and utility programs needed for reproducing the Combined Work from the
60 | Application, but excluding the System Libraries of the Combined Work.
61 |
62 | \item Exception to Section 3 of the GNU GPL.
63 |
64 | You may convey a covered work under sections 3 and 4 of this License
65 | without being bound by section 3 of the GNU GPL.
66 |
67 | \item Conveying Modified Versions.
68 |
69 | If you modify a copy of the Library, and, in your modifications, a
70 | facility refers to a function or data to be supplied by an Application
71 | that uses the facility (other than as an argument passed when the
72 | facility is invoked), then you may convey a copy of the modified
73 | version:
74 |
75 | \begin{enumerate}
76 | \item under this License, provided that you make a good faith effort to
77 | ensure that, in the event an Application does not supply the
78 | function or data, the facility still operates, and performs
79 | whatever part of its purpose remains meaningful, or
80 |
81 | \item under the GNU GPL, with none of the additional permissions of
82 | this License applicable to that copy.
83 | \end{enumerate}
84 |
85 | \item Object Code Incorporating Material from Library Header Files.
86 |
87 | The object code form of an Application may incorporate material from
88 | a header file that is part of the Library. You may convey such object
89 | code under terms of your choice, provided that, if the incorporated
90 | material is not limited to numerical parameters, data structure
91 | layouts and accessors, or small macros, inline functions and templates
92 | (ten or fewer lines in length), you do both of the following:
93 |
94 | \begin{enumerate}
95 | \item Give prominent notice with each copy of the object code that the
96 | Library is used in it and that the Library and its use are
97 | covered by this License.
98 |
99 | \item Accompany the object code with a copy of the GNU GPL and this license
100 | document.
101 | \end{enumerate}
102 |
103 | \item Combined Works.
104 |
105 | You may convey a Combined Work under terms of your choice that,
106 | taken together, effectively do not restrict modification of the
107 | portions of the Library contained in the Combined Work and reverse
108 | engineering for debugging such modifications, if you also do each of
109 | the following:
110 |
111 | \begin{enumerate}
112 | \item Give prominent notice with each copy of the Combined Work that
113 | the Library is used in it and that the Library and its use are
114 | covered by this License.
115 |
116 | \item Accompany the Combined Work with a copy of the GNU GPL and this license
117 | document.
118 |
119 | \item For a Combined Work that displays copyright notices during
120 | execution, include the copyright notice for the Library among
121 | these notices, as well as a reference directing the user to the
122 | copies of the GNU GPL and this license document.
123 |
124 | \item Do one of the following:
125 |
126 | \begin{enumerate}
127 | \addtocounter{enumiii}{-1} % start at 0
128 | \item Convey the Minimal Corresponding Source under the terms of this
129 | License, and the Corresponding Application Code in a form
130 | suitable for, and under terms that permit, the user to
131 | recombine or relink the Application with a modified version of
132 | the Linked Version to produce a modified Combined Work, in the
133 | manner specified by section 6 of the GNU GPL for conveying
134 | Corresponding Source.
135 |
136 | \item Use a suitable shared library mechanism for linking with the
137 | Library. A suitable mechanism is one that (a) uses at run time
138 | a copy of the Library already present on the user's computer
139 | system, and (b) will operate properly with a modified version
140 | of the Library that is interface-compatible with the Linked
141 | Version.
142 | \end{enumerate}
143 |
144 | \item Provide Installation Information, but only if you would otherwise
145 | be required to provide such information under section 6 of the
146 | GNU GPL, and only to the extent that such information is
147 | necessary to install and execute a modified version of the
148 | Combined Work produced by recombining or relinking the
149 | Application with a modified version of the Linked Version. (If
150 | you use option 4d0, the Installation Information must accompany
151 | the Minimal Corresponding Source and Corresponding Application
152 | Code. If you use option 4d1, you must provide the Installation
153 | Information in the manner specified by section 6 of the GNU GPL
154 | for conveying Corresponding Source.)
155 | \end{enumerate}
156 |
157 | \item Combined Libraries.
158 |
159 | You may place library facilities that are a work based on the
160 | Library side by side in a single library together with other library
161 | facilities that are not Applications and are not covered by this
162 | License, and convey such a combined library under terms of your
163 | choice, if you do both of the following:
164 |
165 | \begin{enumerate}
166 | \item Accompany the combined library with a copy of the same work based
167 | on the Library, uncombined with any other library facilities,
168 | conveyed under the terms of this License.
169 |
170 | \item Give prominent notice with the combined library that part of it
171 | is a work based on the Library, and explaining where to find the
172 | accompanying uncombined form of the same work.
173 | \end{enumerate}
174 |
175 | \item Revised Versions of the GNU Lesser General Public License.
176 |
177 | The Free Software Foundation may publish revised and/or new versions
178 | of the GNU Lesser General Public License from time to time. Such new
179 | versions will be similar in spirit to the present version, but may
180 | differ in detail to address new problems or concerns.
181 |
182 | Each version is given a distinguishing version number. If the
183 | Library as you received it specifies that a certain numbered version
184 | of the GNU Lesser General Public License ``or any later version''
185 | applies to it, you have the option of following the terms and
186 | conditions either of that published version or of any later version
187 | published by the Free Software Foundation. If the Library as you
188 | received it does not specify a version number of the GNU Lesser
189 | General Public License, you may choose any version of the GNU Lesser
190 | General Public License ever published by the Free Software Foundation.
191 |
192 | If the Library as you received it specifies that a proxy can decide
193 | whether future versions of the GNU Lesser General Public License shall
194 | apply, that proxy's public statement of acceptance of any version is
195 | permanent authorization for you to choose that version for the
196 | Library.
197 |
198 | \end{enumerate}
199 |
200 | \end{document}
201 |
202 | %%% Local Variables:
203 | %%% mode: latex
204 | %%% TeX-master: t
205 | %%% End:
206 |
207 |
--------------------------------------------------------------------------------
/rtl/Makefile:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | ##
3 | ## Filename: rtl/Makefile
4 | ## {{{
5 | ## Project: A series of CORDIC related projects
6 | ##
7 | ## Purpose: To direct the Verilator build of the CORDIC demo sources. The
8 | ## result is C++ code (built by Verilator), that is then built
9 | ## (herein) into an executable library.
10 | ##
11 | ## Targets: The default target, all, builds the target test, which includes
12 | ## the libraries necessary for Verilator testing.
13 | ##
14 | ## Creator: Dan Gisselquist, Ph.D.
15 | ## Gisselquist Technology, LLC
16 | ##
17 | ################################################################################
18 | ## }}}
19 | ## Copyright (C) 2017-2024, Gisselquist Technology, LLC
20 | ## {{{
21 | ## This program is free software (firmware): you can redistribute it and/or
22 | ## modify it under the terms of the GNU General Public License as published
23 | ## by the Free Software Foundation, either version 3 of the License, or (at
24 | ## your option) any later version.
25 | ##
26 | ## This program is distributed in the hope that it will be useful, but WITHOUT
27 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
28 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
29 | ## for more details.
30 | ##
31 | ## You should have received a copy of the GNU General Public License along
32 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no
33 | ## target there if the PDF file isn't present.) If not, see
34 | ## for a copy.
35 | ## }}}
36 | ## License: GPL, v3, as defined and found on www.gnu.org,
37 | ## {{{
38 | ## http://www.gnu.org/licenses/gpl.html
39 | ##
40 | ##
41 | ################################################################################
42 | ##
43 | ## }}}
44 | all: test
45 | FBDIR := .
46 | VDIRFB:= $(FBDIR)/obj_dir
47 |
48 | .PHONY: test topolar cordic sintable quarterwav quadtbl
49 | ## Target pseudonymns
50 | ## {{{
51 | test: topolar cordic sintable quarterwav quadtbl seqcordic seqpolar
52 | topolar: $(VDIRFB)/Vtopolar__ALL.a
53 | cordic: $(VDIRFB)/Vcordic__ALL.a
54 | sintable: $(VDIRFB)/Vsintable__ALL.a
55 | quarterwav: $(VDIRFB)/Vquarterwav__ALL.a
56 | quadtbl: $(VDIRFB)/Vquadtbl__ALL.a
57 | seqcordic: $(VDIRFB)/Vseqcordic__ALL.a
58 | seqpolar: $(VDIRFB)/Vseqpolar__ALL.a
59 | ## }}}
60 |
61 | VOBJ := obj_dir
62 | SUBMAKE := $(MAKE) --no-print-directory --directory=$(VOBJ) -f
63 | ifeq ($(VERILATOR_ROOT),)
64 | VERILATOR := verilator
65 | else
66 | VERILATOR := $(VERILATOR_ROOT)/bin/verilator
67 | endif
68 | VFLAGS := -Wall -MMD --trace -cc
69 |
70 | ## Dependencies
71 | ## {{{
72 | $(VDIRFB)/Vcordic__ALL.a: $(VDIRFB)/Vcordic.h $(VDIRFB)/Vcordic.cpp
73 | $(VDIRFB)/Vcordic__ALL.a: $(VDIRFB)/Vcordic.mk
74 | $(VDIRFB)/Vcordic.h $(VDIRFB)/Vcordic.cpp $(VDIRFB)/Vcordic.mk: cordic.v
75 |
76 | $(VDIRFB)/Vtopolar__ALL.a: $(VDIRFB)/Vtopolar.h $(VDIRFB)/Vtopolar.cpp
77 | $(VDIRFB)/Vtopolar__ALL.a: $(VDIRFB)/Vtopolar.mk
78 | $(VDIRFB)/Vtopolar.h $(VDIRFB)/Vtopolar.cpp $(VDIRFB)/Vtopolar.mk: topolar.v
79 |
80 | $(VDIRFB)/Vsintable__ALL.a: $(VDIRFB)/Vsintable.h $(VDIRFB)/Vsintable.cpp
81 | $(VDIRFB)/Vsintable__ALL.a: $(VDIRFB)/Vsintable.mk
82 | $(VDIRFB)/Vsintable.h $(VDIRFB)/Vsintable.cpp $(VDIRFB)/Vsintable.mk: sintable.v
83 |
84 | $(VDIRFB)/Vquarterwav__ALL.a: $(VDIRFB)/Vquarterwav.h $(VDIRFB)/Vquarterwav.cpp
85 | $(VDIRFB)/Vquarterwav__ALL.a: $(VDIRFB)/Vquarterwav.mk
86 | $(VDIRFB)/Vquarterwav.h $(VDIRFB)/Vquarterwav.cpp $(VDIRFB)/Vquarterwav.mk: quarterwav.v
87 |
88 | $(VDIRFB)/Vquadtbl__ALL.a: $(VDIRFB)/Vquadtbl.h $(VDIRFB)/Vquadtbl.cpp
89 | $(VDIRFB)/Vquadtbl__ALL.a: $(VDIRFB)/Vquadtbl.mk
90 | $(VDIRFB)/Vquadtbl.h $(VDIRFB)/Vquadtbl.cpp $(VDIRFB)/Vquadtbl.mk: quadtbl.v
91 |
92 | $(VDIRFB)/Vseqcordic__ALL.a: $(VDIRFB)/Vseqcordic.h $(VDIRFB)/Vseqcordic.cpp
93 | $(VDIRFB)/Vseqcordic__ALL.a: $(VDIRFB)/Vseqcordic.mk
94 | $(VDIRFB)/Vseqcordic.h $(VDIRFB)/Vseqcordic.cpp $(VDIRFB)/Vseqcordic.mk: seqcordic.v
95 |
96 | $(VDIRFB)/Vseqpolar__ALL.a: $(VDIRFB)/Vseqpolar.h $(VDIRFB)/Vseqpolar.cpp
97 | $(VDIRFB)/Vseqpolar__ALL.a: $(VDIRFB)/Vseqpolar.mk
98 | $(VDIRFB)/Vseqpolar.h $(VDIRFB)/Vseqpolar.cpp $(VDIRFB)/Vseqpolar.mk: seqpolar.v
99 | ## }}}
100 |
101 | ## Verilate
102 | ## {{{
103 | $(VDIRFB)/V%.cpp $(VDIRFB)/V%.h $(VDIRFB)/V%.mk: $(FBDIR)/%.v
104 | $(VERILATOR) $(VFLAGS) $*.v
105 | ## }}}
106 |
107 | ## Build the library
108 | ## {{{
109 | $(VDIRFB)/V%__ALL.a: $(VDIRFB)/V%.mk
110 | $(SUBMAKE) V$*.mk
111 | ## }}}
112 |
113 | .PHONY: clean
114 | ## {{{
115 | clean:
116 | rm -rf $(VDIRFB)/
117 | ## }}}
118 |
119 | ## Automatic dependency handling
120 | ## {{{
121 | #
122 | # Note Verilator's dependency created information, and include it here if we
123 | # can
124 | DEPS := $(wildcard $(VDIRFB)/*.d)
125 |
126 | ifneq ($(MAKECMDGOALS),clean)
127 | ifneq ($(DEPS),)
128 | include $(DEPS)
129 | endif
130 | endif
131 | ## }}}
132 |
--------------------------------------------------------------------------------
/rtl/cordic.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: rtl/cordic.h
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: This .h file notes the default parameter values from
8 | // within the generated file. It is used to communicate
9 | // information about the design to the bench testing code.
10 | //
11 | // This core was generated via a core generator using the following command
12 | // line:
13 | //
14 | // % (Not given)
15 | //
16 | // Creator: Dan Gisselquist, Ph.D.
17 | // Gisselquist Technology, LLC
18 | //
19 | ////////////////////////////////////////////////////////////////////////////////
20 | // }}}
21 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
22 | // {{{
23 | // This file is part of the CORDIC related project set.
24 | //
25 | // The CORDIC related project set is free software (firmware): you can
26 | // redistribute it and/or modify it under the terms of the GNU Lesser General
27 | // Public License as published by the Free Software Foundation, either version
28 | // 3 of the License, or (at your option) any later version.
29 | //
30 | // The CORDIC related project set is distributed in the hope that it will be
31 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | // MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
33 | // General Public License for more details.
34 | //
35 | // You should have received a copy of the GNU Lesser General Public License
36 | // along with this program. (It's in the $(ROOT)/doc directory. Run make
37 | // with no target there if the PDF file isn't present.) If not, see
38 | // License: LGPL, v3, as defined and found on www.gnu.org,
39 | // http://www.gnu.org/licenses/lgpl.html
40 | //
41 | ////////////////////////////////////////////////////////////////////////////////
42 | //
43 | // }}}
44 | #ifndef CORDIC_H
45 | #define CORDIC_H
46 | const int IW = 13;
47 | const int OW = 13;
48 | const int NEXTRA = 3;
49 | const int WW = 16;
50 | const int PW = 20;
51 | const int NSTAGES = 16;
52 | const double QUANTIZATION_VARIANCE = 2.8025e-01; // (Units^2)
53 | const double PHASE_VARIANCE_RAD = 2.1773e-10; // (Radians^2)
54 | const double GAIN = 1.1644353454607288;
55 | const double BEST_POSSIBLE_CNR = 78.92;
56 | const bool HAS_RESET = true;
57 | const bool HAS_AUX = true;
58 | #define HAS_RESET_WIRE
59 | #define HAS_AUX_WIRES
60 | #endif // CORDIC_H
61 |
--------------------------------------------------------------------------------
/rtl/cordic.v:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: rtl/cordic.v
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: This file executes a vector rotation on the values
8 | // (i_xval, i_yval). This vector is rotated left by
9 | // i_phase. i_phase is given by the angle, in radians, multiplied by
10 | // 2^32/(2pi). In that fashion, a two pi value is zero just as a zero
11 | // angle is zero.
12 | //
13 | // This core was generated via a core generator using the following command
14 | // line:
15 | //
16 | // % ./gencordic -vca -f ../rtl/cordic.v -v -i 13 -o 13 -t p2r -x 2 -c
17 | //
18 | // Creator: Dan Gisselquist, Ph.D.
19 | // Gisselquist Technology, LLC
20 | //
21 | ////////////////////////////////////////////////////////////////////////////////
22 | // }}}
23 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
24 | // {{{
25 | // This file is part of the CORDIC related project set.
26 | //
27 | // The CORDIC related project set is free software (firmware): you can
28 | // redistribute it and/or modify it under the terms of the GNU Lesser General
29 | // Public License as published by the Free Software Foundation, either version
30 | // 3 of the License, or (at your option) any later version.
31 | //
32 | // The CORDIC related project set is distributed in the hope that it will be
33 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
34 | // MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
35 | // General Public License for more details.
36 | //
37 | // You should have received a copy of the GNU Lesser General Public License
38 | // along with this program. (It's in the $(ROOT)/doc directory. Run make
39 | // with no target there if the PDF file isn't present.) If not, see
40 | // License: LGPL, v3, as defined and found on www.gnu.org,
41 | // http://www.gnu.org/licenses/lgpl.html
42 | //
43 | ////////////////////////////////////////////////////////////////////////////////
44 | //
45 | // }}}
46 | `default_nettype none
47 | module cordic#(
48 | // {{{
49 | localparam IW=13, // The number of bits in our inputs
50 | OW=13, // The number of output bits to produce
51 | NSTAGES=16,
52 | // XTRA= 3,// Extra bits for internal precision
53 | WW=16, // Our working bit-width
54 | PW=20 // Bits in our phase variables
55 | // }}}
56 | ) (
57 | // {{{
58 | input wire i_clk, i_reset, i_ce,
59 | input wire signed [(IW-1):0] i_xval, i_yval,
60 | input wire [(PW-1):0] i_phase,
61 | output reg signed [(OW-1):0] o_xval, o_yval,
62 | input wire i_aux,
63 | output reg o_aux
64 | // }}}
65 | );
66 |
67 | // Declare variables for all of the separate stages
68 | // {{{
69 | wire signed [(WW-1):0] e_xval, e_yval;
70 | reg signed [(WW-1):0] xv [0:(NSTAGES)];
71 | reg signed [(WW-1):0] yv [0:(NSTAGES)];
72 | reg [(PW-1):0] ph [0:(NSTAGES)];
73 | reg [(NSTAGES):0] ax;
74 | // }}}
75 |
76 | // Sign extend our inputs
77 | // {{{
78 | // First step: expand our input to our working width.
79 | // This is going to involve extending our input by one
80 | // (or more) bits in addition to adding any xtra bits on
81 | // bits on the right. The one bit extra on the left is to
82 | // allow for any accumulation due to the cordic gain
83 | // within the algorithm.
84 | //
85 | assign e_xval = { {i_xval[(IW-1)]}, i_xval, {(WW-IW-1){1'b0}} };
86 | assign e_yval = { {i_yval[(IW-1)]}, i_yval, {(WW-IW-1){1'b0}} };
87 |
88 | // }}}
89 | //
90 | // Handle the auxilliary logic.
91 | // {{{
92 | // The auxilliary bit is designed so that you can place a valid bit into
93 | // the CORDIC function, and see when it comes out. While the bit is
94 | // allowed to be anything, the requirement of this bit is that it *must*
95 | // be aligned with the output when done. That is, if i_xval and i_yval
96 | // are input together with i_aux, then when o_xval and o_yval are set
97 | // to this value, o_aux *must* contain the value that was in i_aux.
98 | //
99 |
100 | initial ax = 0;
101 | always @(posedge i_clk)
102 | if (i_reset)
103 | ax <= 0;
104 | else if (i_ce)
105 | ax <= { ax[(NSTAGES-1):0], i_aux };
106 | // }}}
107 |
108 | // Pre-CORDIC rotation
109 | // {{{
110 | // First stage, get rid of all but 45 degrees
111 | // The resulting phase needs to be between -45 and 45
112 | // degrees but in units of normalized phase
113 | initial begin
114 | xv[0] = 0;
115 | yv[0] = 0;
116 | ph[0] = 0;
117 | end
118 | always @(posedge i_clk)
119 | if (i_reset)
120 | begin
121 | xv[0] <= 0;
122 | yv[0] <= 0;
123 | ph[0] <= 0;
124 | end else if (i_ce)
125 | begin
126 | // {{{
127 | // Walk through all possible quick phase shifts necessary
128 | // to constrain the input to within +/- 45 degrees.
129 | // This is a zero-gain operation, involving only sign
130 | // adjustments.
131 | case(i_phase[(PW-1):(PW-3)])
132 | 3'b000: begin // 0 .. 45, No change
133 | // {{{
134 | xv[0] <= e_xval;
135 | yv[0] <= e_yval;
136 | ph[0] <= i_phase;
137 | end
138 | // }}}
139 | 3'b001: begin // 45 .. 90
140 | // {{{
141 | xv[0] <= -e_yval;
142 | yv[0] <= e_xval;
143 | ph[0] <= i_phase - 20'h40000;
144 | end
145 | // }}}
146 | 3'b010: begin // 90 .. 135
147 | // {{{
148 | xv[0] <= -e_yval;
149 | yv[0] <= e_xval;
150 | ph[0] <= i_phase - 20'h40000;
151 | end
152 | // }}}
153 | 3'b011: begin // 135 .. 180
154 | // {{{
155 | xv[0] <= -e_xval;
156 | yv[0] <= -e_yval;
157 | ph[0] <= i_phase - 20'h80000;
158 | end
159 | // }}}
160 | 3'b100: begin // 180 .. 225
161 | // {{{
162 | xv[0] <= -e_xval;
163 | yv[0] <= -e_yval;
164 | ph[0] <= i_phase - 20'h80000;
165 | end
166 | // }}}
167 | 3'b101: begin // 225 .. 270
168 | // {{{
169 | xv[0] <= e_yval;
170 | yv[0] <= -e_xval;
171 | ph[0] <= i_phase - 20'hc0000;
172 | end
173 | // }}}
174 | 3'b110: begin // 270 .. 315
175 | // {{{
176 | xv[0] <= e_yval;
177 | yv[0] <= -e_xval;
178 | ph[0] <= i_phase - 20'hc0000;
179 | end
180 | // }}}
181 | 3'b111: begin // 315 .. 360, No change
182 | // {{{
183 | xv[0] <= e_xval;
184 | yv[0] <= e_yval;
185 | ph[0] <= i_phase;
186 | end
187 | // }}}
188 | endcase
189 | // }}}
190 | end
191 | // }}}
192 | // Cordic angle table
193 | // {{{
194 | // In many ways, the key to this whole algorithm lies in the angles
195 | // necessary to do this. These angles are also our basic reason for
196 | // building this CORDIC in C++: Verilog just can't parameterize this
197 | // much. Further, these angle's risk becoming unsupportable magic
198 | // numbers, hence we define these and set them in C++, based upon
199 | // the needs of our problem, specifically the number of stages and
200 | // the number of bits required in our phase accumulator
201 | //
202 | wire [19:0] cordic_angle [0:(NSTAGES-1)];
203 |
204 | assign cordic_angle[ 0] = 20'h1_2e40; // 26.565051 deg
205 | assign cordic_angle[ 1] = 20'h0_9fb3; // 14.036243 deg
206 | assign cordic_angle[ 2] = 20'h0_5111; // 7.125016 deg
207 | assign cordic_angle[ 3] = 20'h0_28b0; // 3.576334 deg
208 | assign cordic_angle[ 4] = 20'h0_145d; // 1.789911 deg
209 | assign cordic_angle[ 5] = 20'h0_0a2f; // 0.895174 deg
210 | assign cordic_angle[ 6] = 20'h0_0517; // 0.447614 deg
211 | assign cordic_angle[ 7] = 20'h0_028b; // 0.223811 deg
212 | assign cordic_angle[ 8] = 20'h0_0145; // 0.111906 deg
213 | assign cordic_angle[ 9] = 20'h0_00a2; // 0.055953 deg
214 | assign cordic_angle[10] = 20'h0_0051; // 0.027976 deg
215 | assign cordic_angle[11] = 20'h0_0028; // 0.013988 deg
216 | assign cordic_angle[12] = 20'h0_0014; // 0.006994 deg
217 | assign cordic_angle[13] = 20'h0_000a; // 0.003497 deg
218 | assign cordic_angle[14] = 20'h0_0005; // 0.001749 deg
219 | assign cordic_angle[15] = 20'h0_0002; // 0.000874 deg
220 | // {{{
221 | // Std-Dev : 0.00 (Units)
222 | // Phase Quantization: 0.000015 (Radians)
223 | // Gain is 1.164435
224 | // You can annihilate this gain by multiplying by 32'hdbd95b16
225 | // and right shifting by 32 bits.
226 | // }}}
227 | // }}}
228 |
229 | // CORDIC rotations
230 | // {{{
231 | genvar i;
232 | generate for(i=0; i= WW))
254 | begin // Do nothing but move our outputs
255 | // forward one stage, since we have more
256 | // stages than valid data
257 | // {{{
258 | xv[i+1] <= xv[i];
259 | yv[i+1] <= yv[i];
260 | ph[i+1] <= ph[i];
261 | // }}}
262 | end else if (ph[i][(PW-1)]) // Negative phase
263 | begin
264 | // {{{
265 | // If the phase is negative, rotate by the
266 | // CORDIC angle in a clockwise direction.
267 | xv[i+1] <= xv[i] + (yv[i]>>>(i+1));
268 | yv[i+1] <= yv[i] - (xv[i]>>>(i+1));
269 | ph[i+1] <= ph[i] + cordic_angle[i];
270 | // }}}
271 | end else begin
272 | // {{{
273 | // On the other hand, if the phase is
274 | // positive ... rotate in the
275 | // counter-clockwise direction
276 | xv[i+1] <= xv[i] - (yv[i]>>>(i+1));
277 | yv[i+1] <= yv[i] + (xv[i]>>>(i+1));
278 | ph[i+1] <= ph[i] - cordic_angle[i];
279 | // }}}
280 | end
281 | // }}}
282 | end
283 | end endgenerate
284 | // }}}
285 |
286 | // Round our result towards even
287 | // {{{
288 | wire [(WW-1):0] pre_xval, pre_yval;
289 |
290 | assign pre_xval = xv[NSTAGES] + $signed({ {(OW){1'b0}},
291 | xv[NSTAGES][(WW-OW)],
292 | {(WW-OW-1){!xv[NSTAGES][WW-OW]}} });
293 | assign pre_yval = yv[NSTAGES] + $signed({ {(OW){1'b0}},
294 | yv[NSTAGES][(WW-OW)],
295 | {(WW-OW-1){!yv[NSTAGES][WW-OW]}} });
296 |
297 |
298 | initial begin
299 | o_xval = 0;
300 | o_yval = 0;
301 | o_aux = 0;
302 | end
303 | always @(posedge i_clk)
304 | if (i_reset)
305 | begin
306 | o_xval <= 0;
307 | o_yval <= 0;
308 | o_aux <= 0;
309 | end else if (i_ce)
310 | begin
311 | o_xval <= pre_xval[(WW-1):(WW-OW)];
312 | o_yval <= pre_yval[(WW-1):(WW-OW)];
313 | o_aux <= ax[NSTAGES];
314 | end
315 | // }}}
316 | // Make Verilator happy with pre_.val
317 | // {{{
318 | // verilator lint_off UNUSED
319 | wire unused_val;
320 | assign unused_val = &{ 1'b0,
321 | pre_xval[(WW-OW-1):0],
322 | pre_yval[(WW-OW-1):0]
323 | };
324 | // }}}
325 | // verilator lint_on UNUSED
326 | endmodule
327 |
--------------------------------------------------------------------------------
/rtl/quadtbl.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: rtl/quadtbl.h
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: This .h file notes the default parameter values from
8 | // within the generated file. It is used to communicate
9 | // information about the design to the bench testing code.
10 | //
11 | // This core was generated via a core generator using the following command
12 | // line:
13 | //
14 | // % (Not given)
15 | //
16 | // Creator: Dan Gisselquist, Ph.D.
17 | // Gisselquist Technology, LLC
18 | //
19 | ////////////////////////////////////////////////////////////////////////////////
20 | // }}}
21 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
22 | // {{{
23 | // This file is part of the CORDIC related project set.
24 | //
25 | // The CORDIC related project set is free software (firmware): you can
26 | // redistribute it and/or modify it under the terms of the GNU Lesser General
27 | // Public License as published by the Free Software Foundation, either version
28 | // 3 of the License, or (at your option) any later version.
29 | //
30 | // The CORDIC related project set is distributed in the hope that it will be
31 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | // MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
33 | // General Public License for more details.
34 | //
35 | // You should have received a copy of the GNU Lesser General Public License
36 | // along with this program. (It's in the $(ROOT)/doc directory. Run make
37 | // with no target there if the PDF file isn't present.) If not, see
38 | // License: LGPL, v3, as defined and found on www.gnu.org,
39 | // http://www.gnu.org/licenses/lgpl.html
40 | //
41 | ////////////////////////////////////////////////////////////////////////////////
42 | //
43 | // }}}
44 | #ifndef QUADTBL_H
45 | #define QUADTBL_H
46 | const int OW = 13; // bits
47 | const int NEXTRA = 3; // bits
48 | const int PW = 18; // bits
49 | const long TBL_LGSZ = 6; // (Units)
50 | const long TBL_SZ = 64; // (Units)
51 | const long SCALE = 4094; // (Units)
52 | const double ITBL_ERR = -0.25; // (OW Units)
53 | const double TBL_ERR = -0.0000037981536051; // (sin Units)
54 | const double SPURDB = -107.97; // dB
55 | const bool HAS_RESET = true;
56 | const bool HAS_AUX = true;
57 | #define HAS_RESET_WIRE
58 | #define HAS_AUX_WIRES
59 | #endif // QUADTBL_H
60 |
--------------------------------------------------------------------------------
/rtl/quadtbl.v:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: rtl/quadtbl.v
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: This is a sine-wave table lookup algorithm, coupled with a
8 | // quadratic interpolation of the result. It's purpose is both
9 | // to trade off logic, as well as to lower the phase noise associated
10 | // with any phase truncation.
11 | //
12 | // This core was generated via a core generator using the following command
13 | // line:
14 | //
15 | // % ./gencordic -vca -f ../rtl/quadtbl.v -p 18 -o 13 -t qtbl
16 | //
17 | // Creator: Dan Gisselquist, Ph.D.
18 | // Gisselquist Technology, LLC
19 | //
20 | ////////////////////////////////////////////////////////////////////////////////
21 | // }}}
22 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
23 | // {{{
24 | // This file is part of the CORDIC related project set.
25 | //
26 | // The CORDIC related project set is free software (firmware): you can
27 | // redistribute it and/or modify it under the terms of the GNU Lesser General
28 | // Public License as published by the Free Software Foundation, either version
29 | // 3 of the License, or (at your option) any later version.
30 | //
31 | // The CORDIC related project set is distributed in the hope that it will be
32 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
33 | // MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
34 | // General Public License for more details.
35 | //
36 | // You should have received a copy of the GNU Lesser General Public License
37 | // along with this program. (It's in the $(ROOT)/doc directory. Run make
38 | // with no target there if the PDF file isn't present.) If not, see
39 | // License: LGPL, v3, as defined and found on www.gnu.org,
40 | // http://www.gnu.org/licenses/lgpl.html
41 | //
42 | ////////////////////////////////////////////////////////////////////////////////
43 | //
44 | // }}}
45 | `default_nettype none
46 | //
47 | module quadtbl #(
48 | // {{{
49 | localparam PW=18, // Bits in our phase variable
50 | OW=13, // The number of output bits to produce
51 | XTRA= 3 // Extra bits for internal precision
52 | // }}}
53 | ) (
54 | // {{{
55 | input wire i_clk, i_reset, i_ce, i_aux,
56 | //
57 | input wire signed [(PW-1):0] i_phase,
58 | output reg signed [(OW-1):0] o_sin,
59 | output reg o_aux
60 | // }}}
61 | );
62 |
63 | // Declarations
64 | // {{{
65 | localparam LGTBL=6,
66 | DXBITS = (PW-LGTBL)+1, // 13
67 | TBLENTRIES = (1<>> state);
282 | yv <= yv - (xv >>> state);
283 | ph <= ph + (cangle);
284 | // }}}
285 | end else begin
286 | // {{{
287 | xv <= xv - (yv >>> state);
288 | yv <= yv + (xv >>> state);
289 | ph <= ph - (cangle);
290 | // }}}
291 | end
292 | // }}}
293 |
294 | // Round our result towards even
295 | // {{{
296 | wire [(WW-1):0] final_xv, final_yv;
297 |
298 | assign final_xv = xv + $signed({{(OW){1'b0}},
299 | xv[(WW-OW)],
300 | {(WW-OW-1){!xv[WW-OW]}} });
301 | assign final_yv = yv + $signed({{(OW){1'b0}},
302 | yv[(WW-OW)],
303 | {(WW-OW-1){!yv[WW-OW]}} });
304 | // }}}
305 | // o_done
306 | // {{{
307 | initial o_done = 1'b0;
308 | always @(posedge i_clk)
309 | if (i_reset)
310 | o_done <= 1'b0;
311 | else
312 | o_done <= (state >= 15);
313 | // }}}
314 |
315 | // Output assignments: o_xval, o_yval, o_aux
316 | // {{{
317 | initial o_aux = 0;
318 | always @(posedge i_clk)
319 | if (state >= 15)
320 | begin
321 | o_xval <= final_xv[WW-1:WW-OW];
322 | o_yval <= final_yv[WW-1:WW-OW];
323 | o_aux <= aux;
324 | end
325 | // }}}
326 |
327 | assign o_busy = !idle;
328 |
329 | // Make Verilator happy with pre_.val
330 | // {{{
331 | // verilator lint_off UNUSED
332 | wire unused_val;
333 | assign unused_val = &{ 1'b0, final_xv[WW-OW-1:0], final_yv[WW-OW-1:0] };
334 | // verilator lint_on UNUSED
335 | // }}}
336 | endmodule
337 |
--------------------------------------------------------------------------------
/rtl/seqpolar.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: rtl/seqpolar.h
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: This .h file notes the default parameter values from
8 | // within the generated file. It is used to communicate
9 | // information about the design to the bench testing code.
10 | //
11 | // This core was generated via a core generator using the following command
12 | // line:
13 | //
14 | // % (Not given)
15 | //
16 | // Creator: Dan Gisselquist, Ph.D.
17 | // Gisselquist Technology, LLC
18 | //
19 | ////////////////////////////////////////////////////////////////////////////////
20 | // }}}
21 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
22 | // {{{
23 | // This file is part of the CORDIC related project set.
24 | //
25 | // The CORDIC related project set is free software (firmware): you can
26 | // redistribute it and/or modify it under the terms of the GNU Lesser General
27 | // Public License as published by the Free Software Foundation, either version
28 | // 3 of the License, or (at your option) any later version.
29 | //
30 | // The CORDIC related project set is distributed in the hope that it will be
31 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | // MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
33 | // General Public License for more details.
34 | //
35 | // You should have received a copy of the GNU Lesser General Public License
36 | // along with this program. (It's in the $(ROOT)/doc directory. Run make
37 | // with no target there if the PDF file isn't present.) If not, see
38 | // License: LGPL, v3, as defined and found on www.gnu.org,
39 | // http://www.gnu.org/licenses/lgpl.html
40 | //
41 | ////////////////////////////////////////////////////////////////////////////////
42 | //
43 | // }}}
44 | #ifndef SEQPOLAR_H
45 | #define SEQPOLAR_H
46 | #ifdef CLOCKS_PER_OUTPUT
47 | #undef CLOCKS_PER_OUTPUT
48 | #endif // CLOCKS_PER_OUTPUT
49 | #define CLOCKS_PER_OUTPUT 21
50 | const int IW = 13;
51 | const int OW = 13;
52 | const int NEXTRA = 4;
53 | const int WW = 21;
54 | const int PW = 21;
55 | const int NSTAGES = 18;
56 | const double QUANTIZATION_VARIANCE = 0.1964179315931617; // (Units^2)
57 | const double PHASE_VARIANCE_RAD = 0.0000000000669195; // (Radians^2)
58 | const double GAIN = 0.8233801290585359;
59 | const bool HAS_RESET = true;
60 | const bool HAS_AUX = true;
61 | #define HAS_RESET_WIRE
62 | #define HAS_AUX_WIRES
63 | #endif // SEQPOLAR_H
64 |
--------------------------------------------------------------------------------
/rtl/seqpolar.v:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: rtl/seqpolar.v
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: This is a rectangular to polar conversion routine based upon an
8 | // internal CORDIC implementation. Basically, the input is
9 | // provided in i_xval and i_yval. The internal CORDIC rotator will rotate
10 | // (i_xval, i_yval) until i_yval is approximately zero. The resulting
11 | // xvalue and phase will be placed into o_xval and o_phase respectively.
12 | //
13 | // This particular version of the polar to rectangular CORDIC converter
14 | // converter processes a somple one at a time. It is completely
15 | // sequential, not parallel at all.
16 | //
17 | //
18 | // This core was generated via a core generator using the following command
19 | // line:
20 | //
21 | // % ./gencordic -vca -f ../rtl/seqpolar.v -i 13 -o 13 -t sr2p -x 2
22 | //
23 | // Creator: Dan Gisselquist, Ph.D.
24 | // Gisselquist Technology, LLC
25 | //
26 | ////////////////////////////////////////////////////////////////////////////////
27 | // }}}
28 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
29 | // {{{
30 | // This file is part of the CORDIC related project set.
31 | //
32 | // The CORDIC related project set is free software (firmware): you can
33 | // redistribute it and/or modify it under the terms of the GNU Lesser General
34 | // Public License as published by the Free Software Foundation, either version
35 | // 3 of the License, or (at your option) any later version.
36 | //
37 | // The CORDIC related project set is distributed in the hope that it will be
38 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
39 | // MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
40 | // General Public License for more details.
41 | //
42 | // You should have received a copy of the GNU Lesser General Public License
43 | // along with this program. (It's in the $(ROOT)/doc directory. Run make
44 | // with no target there if the PDF file isn't present.) If not, see
45 | // License: LGPL, v3, as defined and found on www.gnu.org,
46 | // http://www.gnu.org/licenses/lgpl.html
47 | //
48 | ////////////////////////////////////////////////////////////////////////////////
49 | //
50 | // }}}
51 | `default_nettype none
52 | //
53 | module seqpolar #(
54 | // {{{
55 | localparam IW=13, // The number of bits in our inputs
56 | OW=13,// The number of output bits to produce
57 | // NSTAGES=18,
58 | // XTRA= 4,// Extra bits for internal precision
59 | WW=21, // Our working bit-width
60 | PW=21 // Bits in our phase variables
61 | // }}}
62 | ) (
63 | // {{{
64 | input wire i_clk, i_reset, i_stb,
65 | input wire signed [(IW-1):0] i_xval, i_yval,
66 | input wire i_aux,
67 | output wire o_busy,
68 | output reg o_done,
69 | output reg signed [(OW-1):0] o_mag,
70 | output reg [(PW-1):0] o_phase,
71 | output reg o_aux
72 | // }}}
73 | );
74 |
75 | // First step: expand our input to our working width.
76 | // {{{
77 | // This is going to involve extending our input by one
78 | // (or more) bits in addition to adding any xtra bits on
79 | // bits on the right. The one bit extra on the left is to
80 | // allow for any accumulation due to the cordic gain
81 | // within the algorithm.
82 | //
83 | wire signed [(WW-1):0] e_xval, e_yval;
84 | assign e_xval = { {(2){i_xval[(IW-1)]}}, i_xval, {(WW-IW-2){1'b0}} };
85 | assign e_yval = { {(2){i_yval[(IW-1)]}}, i_yval, {(WW-IW-2){1'b0}} };
86 |
87 | // }}}
88 | // Declare variables for all of the separate stages
89 | // {{{
90 | reg signed [(WW-1):0] xv, yv, prex, prey;
91 | reg [(PW-1):0] ph, preph;
92 |
93 | reg aux;
94 | reg idle, pre_valid;
95 | reg [4:0] state;
96 |
97 | wire last_state;
98 | // }}}
99 |
100 | //
101 | // Handle the auxilliary logic.
102 | // {{{
103 | // The auxilliary bit is designed so that you can place a valid bit into
104 | // the CORDIC function, and see when it comes out. While the bit is
105 | // allowed to be anything, the requirement of this bit is that it *must*
106 | // be aligned with the output when done. That is, if i_xval and i_yval
107 | // are input together with i_aux, then when o_xval and o_yval are set
108 | // to this value, o_aux *must* contain the value that was in i_aux.
109 | //
110 | initial aux = 0;
111 | always @(posedge i_clk)
112 | if (i_reset)
113 | aux <= 0;
114 | else if ((i_stb)&&(!o_busy))
115 | aux <= i_aux;
116 | // }}}
117 |
118 | // First stage, map to within +/- 45 degrees
119 | // {{{
120 | always @(posedge i_clk)
121 | case({i_xval[IW-1], i_yval[IW-1]})
122 | 2'b01: begin // Rotate by -315 degrees
123 | // {{{
124 | prex <= e_xval - e_yval;
125 | prey <= e_xval + e_yval;
126 | preph <= 21'h1c0000;
127 | end
128 | // }}}
129 | 2'b10: begin // Rotate by -135 degrees
130 | // {{{
131 | prex <= -e_xval + e_yval;
132 | prey <= -e_xval - e_yval;
133 | preph <= 21'hc0000;
134 | end
135 | // }}}
136 | 2'b11: begin // Rotate by -225 degrees
137 | // {{{
138 | prex <= -e_xval - e_yval;
139 | prey <= e_xval - e_yval;
140 | preph <= 21'h140000;
141 | end
142 | // }}}
143 | // 2'b00:
144 | default: begin // Rotate by -45 degrees
145 | // {{{
146 | prex <= e_xval + e_yval;
147 | prey <= -e_xval + e_yval;
148 | preph <= 21'h40000;
149 | end
150 | // }}}
151 | endcase
152 | // }}}
153 |
154 | // Cordic angle table
155 | // {{{
156 | // In many ways, the key to this whole algorithm lies in the angles
157 | // necessary to do this. These angles are also our basic reason for
158 | // building this CORDIC in C++: Verilog just can't parameterize this
159 | // much. Further, these angle's risk becoming unsupportable magic
160 | // numbers, hence we define these and set them in C++, based upon
161 | // the needs of our problem, specifically the number of stages and
162 | // the number of bits required in our phase accumulator
163 | //
164 | reg [20:0] cordic_angle [0:31];
165 | reg [20:0] cangle;
166 |
167 | initial cordic_angle[ 0] = 21'h02_5c80; // 26.565051 deg
168 | initial cordic_angle[ 1] = 21'h01_3f67; // 14.036243 deg
169 | initial cordic_angle[ 2] = 21'h00_a222; // 7.125016 deg
170 | initial cordic_angle[ 3] = 21'h00_5161; // 3.576334 deg
171 | initial cordic_angle[ 4] = 21'h00_28ba; // 1.789911 deg
172 | initial cordic_angle[ 5] = 21'h00_145e; // 0.895174 deg
173 | initial cordic_angle[ 6] = 21'h00_0a2f; // 0.447614 deg
174 | initial cordic_angle[ 7] = 21'h00_0517; // 0.223811 deg
175 | initial cordic_angle[ 8] = 21'h00_028b; // 0.111906 deg
176 | initial cordic_angle[ 9] = 21'h00_0145; // 0.055953 deg
177 | initial cordic_angle[10] = 21'h00_00a2; // 0.027976 deg
178 | initial cordic_angle[11] = 21'h00_0051; // 0.013988 deg
179 | initial cordic_angle[12] = 21'h00_0028; // 0.006994 deg
180 | initial cordic_angle[13] = 21'h00_0014; // 0.003497 deg
181 | initial cordic_angle[14] = 21'h00_000a; // 0.001749 deg
182 | initial cordic_angle[15] = 21'h00_0005; // 0.000874 deg
183 | initial cordic_angle[16] = 21'h00_0002; // 0.000437 deg
184 | initial cordic_angle[17] = 21'h00_0001; // 0.000219 deg
185 | initial cordic_angle[18] = 21'h00_0000; // 0.000109 deg
186 | initial cordic_angle[19] = 21'h00_0000; // 0.000055 deg
187 | initial cordic_angle[20] = 21'h00_0000; // 0.000027 deg
188 | initial cordic_angle[21] = 21'h00_0000; // 0.000014 deg
189 | initial cordic_angle[22] = 21'h00_0000; // 0.000007 deg
190 | initial cordic_angle[23] = 21'h00_0000; // 0.000003 deg
191 | initial cordic_angle[24] = 21'h00_0000; // 0.000002 deg
192 | initial cordic_angle[25] = 21'h00_0000; // 0.000001 deg
193 | initial cordic_angle[26] = 21'h00_0000; // 0.000000 deg
194 | initial cordic_angle[27] = 21'h00_0000; // 0.000000 deg
195 | initial cordic_angle[28] = 21'h00_0000; // 0.000000 deg
196 | initial cordic_angle[29] = 21'h00_0000; // 0.000000 deg
197 | initial cordic_angle[30] = 21'h00_0000; // 0.000000 deg
198 | initial cordic_angle[31] = 21'h00_0000; // 0.000000 deg
199 | // {{{
200 | // Std-Dev : 0.00 (Units)
201 | // Phase Quantization: 0.000008 (Radians)
202 | // Gain is 1.164435
203 | // You can annihilate this gain by multiplying by 32'hdbd95b16
204 | // and right shifting by 32 bits.
205 | // }}}
206 | // }}}
207 |
208 | assign last_state = (state >= 19);
209 |
210 | // idle
211 | // {{{
212 | initial idle = 1'b1;
213 | always @(posedge i_clk)
214 | if (i_reset)
215 | idle <= 1'b1;
216 | else if (i_stb)
217 | idle <= 1'b0;
218 | else if (last_state)
219 | idle <= 1'b1;
220 | // }}}
221 | // pre_valid
222 | // {{{
223 | initial pre_valid = 1'b0;
224 | always @(posedge i_clk)
225 | if (i_reset)
226 | pre_valid <= 1'b0;
227 | else
228 | pre_valid <= (i_stb)&&(idle);
229 | // }}}
230 |
231 | // state
232 | // {{{
233 | initial state = 0;
234 | always @(posedge i_clk)
235 | if (i_reset)
236 | state <= 0;
237 | else if (idle)
238 | state <= 0;
239 | else if (last_state)
240 | state <= 0;
241 | else
242 | state <= state + 1;
243 | // }}}
244 | // cangle -- table lookup
245 | // {{{
246 | always @(posedge i_clk)
247 | cangle <= cordic_angle[state[4:0]];
248 | // }}}
249 | // Actual CORDIC rotation
250 | // {{{
251 | // Here's where we are going to put the actual CORDIC
252 | // rectangular to polar loop. Everything up to this
253 | // point has simply been necessary preliminaries.
254 | always @(posedge i_clk)
255 | if (pre_valid)
256 | begin
257 | // {{{
258 | xv <= prex;
259 | yv <= prey;
260 | ph <= preph;
261 | // }}}
262 | end else if (yv[(WW-1)]) // Below the axis
263 | begin
264 | // {{{
265 | // If the vector is below the x-axis, rotate by
266 | // the CORDIC angle in a positive direction.
267 | xv <= xv - (yv>>>state);
268 | yv <= yv + (xv>>>state);
269 | ph <= ph - cangle;
270 | // }}}
271 | end else begin
272 | // {{{
273 | // On the other hand, if the vector is above the
274 | // x-axis, then rotate in the other direction
275 | xv <= xv + (yv>>>state);
276 | yv <= yv - (xv>>>state);
277 | ph <= ph + cangle;
278 | // }}}
279 | end
280 | // }}}
281 |
282 | // o_done
283 | // {{{
284 | always @(posedge i_clk)
285 | if (i_reset)
286 | o_done <= 1'b0;
287 | else
288 | o_done <= (last_state);
289 | // }}}
290 | // Round our magnitude towards even
291 | // {{{
292 | wire [(WW-1):0] final_mag;
293 |
294 | assign final_mag = xv + $signed({{(OW){1'b0}},
295 | xv[(WW-OW)],
296 | {(WW-OW-1){!xv[WW-OW]}} });
297 | // }}}
298 |
299 | // Output assignments: o_mag, o_phase, and o_aux
300 | // {{{
301 | initial o_aux = 0;
302 | always @(posedge i_clk)
303 | if (last_state)
304 | begin
305 | o_mag <= final_mag[(WW-1):(WW-OW)];
306 | o_phase <= ph;
307 | o_aux <= aux;
308 | end
309 | // }}}
310 | assign o_busy = !idle;
311 |
312 | // Make Verilator happy with pre_.val
313 | // {{{
314 | // verilator lint_off UNUSED
315 | wire unused_val;
316 | assign unused_val = &{ 1'b0, final_mag[WW-1],
317 | final_mag[(WW-OW-1):0] };
318 | // verilator lint_on UNUSED
319 | // }}}
320 | endmodule
321 |
--------------------------------------------------------------------------------
/rtl/sintable.v:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: rtl/sintable.v
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: This is a very simple sinewave table lookup approach
8 | // approach to generating a sine wave. It has the lowest latency
9 | // among all sinewave generation alternatives.
10 | //
11 | // This core was generated via a core generator using the following command
12 | // line:
13 | //
14 | // % (Not given)
15 | //
16 | // Creator: Dan Gisselquist, Ph.D.
17 | // Gisselquist Technology, LLC
18 | //
19 | ////////////////////////////////////////////////////////////////////////////////
20 | // }}}
21 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
22 | // {{{
23 | // This file is part of the CORDIC related project set.
24 | //
25 | // The CORDIC related project set is free software (firmware): you can
26 | // redistribute it and/or modify it under the terms of the GNU Lesser General
27 | // Public License as published by the Free Software Foundation, either version
28 | // 3 of the License, or (at your option) any later version.
29 | //
30 | // The CORDIC related project set is distributed in the hope that it will be
31 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
32 | // MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
33 | // General Public License for more details.
34 | //
35 | // You should have received a copy of the GNU Lesser General Public License
36 | // along with this program. (It's in the $(ROOT)/doc directory. Run make
37 | // with no target there if the PDF file isn't present.) If not, see
38 | // License: LGPL, v3, as defined and found on www.gnu.org,
39 | // http://www.gnu.org/licenses/lgpl.html
40 | //
41 | ////////////////////////////////////////////////////////////////////////////////
42 | //
43 | // }}}
44 | `default_nettype none
45 | //
46 | module sintable #(
47 | // {{{
48 | parameter PW =17, // Number of bits in the input phase
49 | OW =13 // Number of output bits
50 | // }}}
51 | ) (
52 | // {{{
53 | input wire i_clk, i_reset, i_ce,
54 | input wire [(PW-1):0] i_phase,
55 | output reg [(OW-1):0] o_val,
56 | //
57 | input wire i_aux,
58 | output reg o_aux
59 | // }}}
60 | );
61 |
62 | // Declare variables
63 | // {{{
64 | reg [(OW-1):0] tbl [0:((1<= WW))
218 | begin // Do nothing but move our vector
219 | // forward one stage, since we have more
220 | // stages than valid data
221 | // {{{
222 | xv[i+1] <= xv[i];
223 | yv[i+1] <= yv[i];
224 | ph[i+1] <= ph[i];
225 | // }}}
226 | end else if (yv[i][(WW-1)]) // Below the axis
227 | begin
228 | // {{{
229 | // If the vector is below the x-axis, rotate by
230 | // the CORDIC angle in a positive direction.
231 | xv[i+1] <= xv[i] - (yv[i]>>>(i+1));
232 | yv[i+1] <= yv[i] + (xv[i]>>>(i+1));
233 | ph[i+1] <= ph[i] - cordic_angle[i];
234 | // }}}
235 | end else begin
236 | // {{{
237 | // On the other hand, if the vector is above the
238 | // x-axis, then rotate in the other direction
239 | xv[i+1] <= xv[i] + (yv[i]>>>(i+1));
240 | yv[i+1] <= yv[i] - (xv[i]>>>(i+1));
241 | ph[i+1] <= ph[i] + cordic_angle[i];
242 | // }}}
243 | end
244 | // }}}
245 | end
246 | end endgenerate
247 | // }}}
248 |
249 | // Round our magnitude towards even
250 | // {{{
251 | wire [(WW-1):0] pre_mag;
252 |
253 | assign pre_mag = xv[NSTAGES] + $signed({ {(OW){1'b0}},
254 | xv[NSTAGES][(WW-OW)],
255 | {(WW-OW-1){!xv[NSTAGES][WW-OW]}} });
256 |
257 | initial o_mag = 0;
258 | initial o_phase = 0;
259 | initial o_aux = 0;
260 | always @(posedge i_clk)
261 | if (i_reset)
262 | begin
263 | o_mag <= 0;
264 | o_phase <= 0;
265 | o_aux <= 0;
266 | end else if (i_ce)
267 | begin
268 | o_mag <= pre_mag[(WW-1):(WW-OW)];
269 | o_phase <= ph[NSTAGES];
270 | o_aux <= ax[NSTAGES];
271 | end
272 |
273 | // Make Verilator happy with pre_.val
274 | // verilator lint_off UNUSED
275 | wire unused_val;
276 | assign unused_val = &{ 1'b0, pre_mag[WW-1], pre_mag[(WW-OW-1):0] };
277 | // verilator lint_on UNUSED
278 | // }}}
279 | endmodule
280 |
--------------------------------------------------------------------------------
/sw/.gitignore:
--------------------------------------------------------------------------------
1 | gencordic
2 |
--------------------------------------------------------------------------------
/sw/Makefile:
--------------------------------------------------------------------------------
1 | ################################################################################
2 | ##
3 | ## Filename: sw/Makefile
4 | ## {{{
5 | ## Project: A series of CORDIC related projects
6 | ##
7 | ## Purpose: This file directs the build of a variety of Verilog cordic
8 | ## demonstration files:
9 | ## }}}
10 | ## Targets:
11 | ## {{{
12 | ## all: Builds the cordic generator program, gencordic, and uses it to
13 | ## build two demonstration files in the rtl/ directory: cordic.v
14 | ## and topolar.v
15 | ##
16 | ## clean: Cleans up all of the build products, so that you can start
17 | ## over from scratch.
18 | ##
19 | ## gencordic: Builds a cordic generation program--the main program
20 | ## build with these instructions
21 | ##
22 | ## topolar: Builds a rectangular to polar converter in the rtl/ directory
23 | ##
24 | ## basiccordic: Builds a polar to rectangular converter slash exponential
25 | ## multiplier, and places it in the rtl/ directory
26 | ##
27 | ## quadtbl: Builds a sine-wave calculator based upon a quadratic table
28 | ## interpolation
29 | ##
30 | ## depends: Caclulates dependencies, places a dependency file into
31 | ## the obj-pc sub-directory
32 | ##
33 | ## Creator: Dan Gisselquist, Ph.D.
34 | ## Gisselquist Technology, LLC
35 | ##
36 | ################################################################################
37 | ## }}}
38 | ## Copyright (C) 2017-2024, Gisselquist Technology, LLC
39 | ## {{{
40 | ## This program is free software (firmware): you can redistribute it and/or
41 | ## modify it under the terms of the GNU General Public License as published
42 | ## by the Free Software Foundation, either version 3 of the License, or (at
43 | ## your option) any later version.
44 | ##
45 | ## This program is distributed in the hope that it will be useful, but WITHOUT
46 | ## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
47 | ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
48 | ## for more details.
49 | ##
50 | ## You should have received a copy of the GNU General Public License along
51 | ## with this program. (It's in the $(ROOT)/doc directory. Run make with no
52 | ## target there if the PDF file isn't present.) If not, see
53 | ## for a copy.
54 | ## }}}
55 | ## License: GPL, v3, as defined and found on www.gnu.org,
56 | ## {{{
57 | ## http://www.gnu.org/licenses/gpl.html
58 | ##
59 | ##
60 | ################################################################################
61 | ##
62 | ## }}}
63 | all:
64 | ## {{{
65 | CXX := g++
66 | OBJDIR := obj-pc
67 | VSRCD := ../rtl
68 | SOURCES:= main.cpp legal.cpp basiccordic.cpp topolar.cpp \
69 | sintable.cpp quadtbl.cpp hexfile.cpp seqcordic.cpp seqpolar.cpp \
70 | cordiclib.cpp
71 | HEADERS:= $(wildcard $(subst .cpp,.h,$(SOURCES)))
72 | OBJECTS:= $(addprefix $(OBJDIR)/,$(subst .cpp,.o,$(SOURCES)))
73 | VSRC := topolar.v cordic.v sintable.v quarterwav.v quadtbl.v \
74 | seqcordic.v seqpolar.v
75 | CFLAGS := -g -Og -Wall
76 | PROGRAMS:= gencordic
77 | ## }}}
78 | all: $(PROGRAMS) $(VSRC)
79 | ## Default arguments
80 | ## {{{
81 | INCS :=
82 | PB := 18 # Phase bits
83 | NB := 13
84 | XTRA := 2
85 | CRDCARGS := -vca
86 | ## }}}
87 |
88 | ## .o: Build object files
89 | ## {{{
90 | %.o: $(OBJDIR)/%.o
91 | $(OBJDIR)/%.o: %.cpp
92 | $(mk-objdir)
93 | $(CXX) $(CFLAGS) -c $< -o $@
94 | ## }}}
95 |
96 | ## gencordic -- the main software core-generator target
97 | ## {{{
98 | gencordic: $(OBJECTS)
99 | rm -f $(VSRCD)/topolar.v
100 | rm -f $(VSRCD)/cordic.v
101 | rm -f $(VSRCD)/sintable.v
102 | rm -f $(VSRCD)/quarterwav.v
103 | rm -f $(VSRCD)/quadtbl.v
104 | rm -f $(VSRCD)/seqcordic.v
105 | rm -f $(VSRCD)/seqpolar.v
106 | $(CXX) $(OBJECTS) -o $@
107 | ## }}}
108 |
109 | .PHONY: topolar topolar.v
110 | ## {{{
111 | topolar: $(VSRCD)/topolar.v
112 | topolar.v: topolar
113 | $(VSRCD)/topolar.v: gencordic
114 | $(mk-rtldir)
115 | ./gencordic $(CRDCARGS) -f $(VSRCD)/topolar.v -i $(NB) -o $(NB) -t r2p -x $(XTRA)
116 | ## }}}
117 |
118 | .PHONY: seqpolar seqpolar.v
119 | ## {{{
120 | seqpolar: $(VSRCD)/seqpolar.v
121 | seqpolar.v: seqpolar
122 | $(VSRCD)/seqpolar.v: gencordic
123 | $(mk-rtldir)
124 | ./gencordic $(CRDCARGS) -f $(VSRCD)/seqpolar.v -i $(NB) -o $(NB) -t sr2p -x $(XTRA)
125 | ## }}}
126 |
127 | .PHONY: basiccordic cordic.v cordic
128 | ## {{{
129 | basiccordic: $(VSRCD)/cordic.v
130 | cordic: basiccordic
131 | cordic.v: basiccordic
132 | $(VSRCD)/cordic.v: gencordic
133 | $(mk-rtldir)
134 | ./gencordic $(CRDCARGS) -f $(VSRCD)/cordic.v -v -i $(NB) -o $(NB) -t p2r -x 2 -c
135 | ## }}}
136 |
137 | .PHONY: seqcordic cordic.v cordic
138 | ## {{{
139 | seqcordic: $(VSRCD)/seqcordic.v
140 | scordic: seqcordic
141 | seqcordic.v: seqcordic
142 | $(VSRCD)/seqcordic.v: gencordic
143 | $(mk-rtldir)
144 | ./gencordic $(CRDCARGS) -f $(VSRCD)/seqcordic.v -v -i $(NB) -o $(NB) -t sp2r -x $(XTRA) -c
145 | ## }}}
146 |
147 | .PHONY: sintable sintable.v
148 | ## {{{
149 | sintable: $(VSRCD)/sintable.v
150 | sintable.v: sintable
151 | $(VSRCD)/sintable.v: gencordic
152 | $(mk-rtldir)
153 | ./gencordic $(CRDCARGS) -f $(VSRCD)/sintable.v -o $(NB) -t tbl
154 | ## }}}
155 |
156 | .PHONY: quarterwav quarterwav.v
157 | ## {{{
158 | quarterwav: $(VSRCD)/quarterwav.v
159 | quarterwav.v: quarterwav
160 | $(VSRCD)/quarterwav.v: gencordic
161 | $(mk-rtldir)
162 | ./gencordic $(CRDCARGS) -f $(VSRCD)/quarterwav.v -p $(PB) -t qtr -x $(XTRA)
163 | ## }}}
164 |
165 | .PHONY: quadtbl quadtbl.v
166 | ## {{{
167 | quadtbl: $(VSRCD)/quadtbl.v
168 | quadtbl.v: quadtbl
169 | $(VSRCD)/quadtbl.v: gencordic
170 | $(mk-rtldir)
171 | ./gencordic $(CRDCARGS) -f $(VSRCD)/quadtbl.v -p $(PB) -o $(NB) -t qtbl
172 | ## }}}
173 |
174 | .PHONY: clean
175 | ## {{{
176 | clean:
177 | rm -f $(PROGRAMS) tags
178 | rm -rf $(OBJDIR)/
179 | rm -f $(VSRCD)/topolar.v $(VSRCD)/cordic.v $(VSRCD)/seqcordic.v
180 | rm -f $(VSRCD)/sintable.v $(VSRCD)/sintable.hex
181 | rm -f $(VSRCD)/quarterwav.v $(VSRCD)/quarterwav.hex
182 | rm -f $(VSRCD)/quadtbl.v $(VSRCD)/quadtbl_ctbl.hex $(VSRCD)/quadtbl_ltbl.hex $(VSRCD)/quadtbl_qtbl.hex
183 | ## }}}
184 |
185 | ## mk-rtldir
186 | ## {{{
187 | define mk-rtldir
188 | bash -c "if [ ! -e $(VSRCD) ]; then mkdir -p $(VSRCD); fi"
189 | endef
190 | ## }}}
191 |
192 | ## mk-objdir
193 | ## {{{
194 | define mk-objdir
195 | bash -c "if [ ! -e $(OBJDIR) ]; then mkdir -p $(OBJDIR); fi"
196 | endef
197 | ## }}}
198 |
199 | ## build-depends
200 | ## {{{
201 | define build-depends
202 | @echo "Building dependency file(s)"
203 | $(mk-objdir)
204 | $(CXX) $(CFLAGS) -MM $(SOURCES) > $(OBJDIR)/xdepends.txt
205 | @sed -e 's/^.*.o: /$(OBJDIR)\/&/' < $(OBJDIR)/xdepends.txt > $(OBJDIR)/depends.txt
206 | @rm $(OBJDIR)/xdepends.txt
207 | endef
208 | ## }}}
209 |
210 | ## Tags
211 | ## {{{
212 | tags: $(SOURCES) $(HEADERS)
213 | @echo "Generating tags"
214 | @ctags $(SOURCES) $(HEADERS)
215 | ## }}}
216 |
217 | .PHONY: depends
218 | ## {{{
219 | depends: tags
220 | $(build-depends)
221 | ## }}}
222 |
223 | $(OBJDIR)/depends.txt: $(SOURCES) $(HEADERS)
224 | $(build-depends)
225 |
226 | -include $(OBJDIR)/depends.txt
227 |
--------------------------------------------------------------------------------
/sw/basiccordic.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: sw/basiccordic.h
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose:
8 | //
9 | // Creator: Dan Gisselquist, Ph.D.
10 | // Gisselquist Technology, LLC
11 | //
12 | ////////////////////////////////////////////////////////////////////////////////
13 | // }}}
14 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
15 | // {{{
16 | // This program is free software (firmware): you can redistribute it and/or
17 | // modify it under the terms of the GNU General Public License as published
18 | // by the Free Software Foundation, either version 3 of the License, or (at
19 | // your option) any later version.
20 | //
21 | // This program is distributed in the hope that it will be useful, but WITHOUT
22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 | // for more details.
25 | //
26 | // You should have received a copy of the GNU General Public License along
27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
28 | // target there if the PDF file isn't present.) If not, see
29 | // for a copy.
30 | // }}}
31 | // License: GPL, v3, as defined and found on www.gnu.org,
32 | // {{{
33 | // http://www.gnu.org/licenses/gpl.html
34 | //
35 | //
36 | ////////////////////////////////////////////////////////////////////////////////
37 | //
38 | // }}}
39 | #ifndef BASICCORDIC_H
40 | #define BASICCORDIC_H
41 |
42 | #include
43 |
44 | #include "basiccordic.h"
45 |
46 | void basiccordic(FILE *fp, FILE *fhp, const char *cmdline, const char *fname,
47 | int nstages, int iw, int ow, int nxtra,
48 | int phase_bits=32,
49 | bool with_reset=true, bool with_aux = true,
50 | bool async_reset=false);
51 |
52 | #endif // BASICCORDIC_H
53 |
--------------------------------------------------------------------------------
/sw/cordiclib.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: sw/cordiclib.cpp
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose:
8 | //
9 | // Creator: Dan Gisselquist, Ph.D.
10 | // Gisselquist Technology, LLC
11 | //
12 | ////////////////////////////////////////////////////////////////////////////////
13 | // }}}
14 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
15 | // {{{
16 | // This program is free software (firmware): you can redistribute it and/or
17 | // modify it under the terms of the GNU General Public License as published
18 | // by the Free Software Foundation, either version 3 of the License, or (at
19 | // your option) any later version.
20 | //
21 | // This program is distributed in the hope that it will be useful, but WITHOUT
22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 | // for more details.
25 | //
26 | // You should have received a copy of the GNU General Public License along
27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
28 | // target there if the PDF file isn't present.) If not, see
29 | // for a copy.
30 | // }}}
31 | // License: GPL, v3, as defined and found on www.gnu.org,
32 | // {{{
33 | // http://www.gnu.org/licenses/gpl.html
34 | //
35 | //
36 | ////////////////////////////////////////////////////////////////////////////////
37 | //
38 | // }}}
39 | #include
40 | #include
41 | #include
42 | #include
43 |
44 | #include "cordiclib.h"
45 |
46 | // nextlg
47 | // {{{
48 | // Returns the ceiling of the log_2 of vl. Hence,
49 | // for 3 the result will be 2
50 | // for 4 the result will be 2
51 | // for 5 the result will be 3
52 | // ...
53 | // for 7 the result will be 3
54 | // for 8 the result will be 3
55 | // for 9 the result will be 4
56 | //
57 | int nextlg(unsigned vl) {
58 | unsigned r, lg=0;
59 |
60 | for(r=1; r 0)
127 | current_variance = pow(2,-2*dropped_bits)*current_variance + 1/12.;
128 | return current_variance;
129 | // }}}
130 | }
131 |
132 | void cordic_angles(FILE *fp, int nstages, int phase_bits, bool mem) {
133 | // {{{
134 | fprintf(fp,
135 | "\t// Cordic angle table\n"
136 | "\t// {{{\n"
137 | "\t// In many ways, the key to this whole algorithm lies in the angles\n"
138 | "\t// necessary to do this. These angles are also our basic reason for\n"
139 | "\t// building this CORDIC in C++: Verilog just can't parameterize this\n"
140 | "\t// much. Further, these angle\'s risk becoming unsupportable magic\n"
141 | "\t// numbers, hence we define these and set them in C++, based upon\n"
142 | "\t// the needs of our problem, specifically the number of stages and\n"
143 | "\t// the number of bits required in our phase accumulator\n"
144 | "\t//\n");
145 | if (mem) {
146 | nstages = (1<> 16);
185 |
186 | if (mem) {
187 | fprintf(fp, "\tinitial\tcordic_angle[%2d] "
188 | "= %2d\'h%0*lx_%04lx; //%11.6f deg\n",
189 | k, phase_bits, (phase_bits-16+3)/4,
190 | hibits, lobits, deg);
191 | } else {
192 | fprintf(fp, "\tassign\tcordic_angle[%2d] "
193 | "= %2d\'h%0*lx_%04lx; //%11.6f deg\n",
194 | k, phase_bits, (phase_bits-16+3)/4,
195 | hibits, lobits, deg);
196 | }
197 | }
198 | }
199 |
200 | fprintf(fp, "\t// {{{\n");
201 | fprintf(fp, "\t// Std-Dev : %.2f (Units)\n",
202 | phase_variance(nstages, phase_bits));
203 | fprintf(fp, "\t// Phase Quantization: %.6f (Radians)\n",
204 | sqrt(phase_variance(nstages, phase_bits)));
205 | fprintf(fp, "\t// Gain is %.6f\n", cordic_gain(nstages));
206 | fprintf(fp, "\t// You can annihilate this gain by multiplying by 32\'h%08x\n",
207 | (unsigned)(1.0/cordic_gain(nstages)
208 | *(4.0 * (1ul<<30))));
209 | fprintf(fp, "\t// and right shifting by 32 bits.\n");
210 | fprintf(fp, "\t// }}}\n");
211 | fprintf(fp, "\t// }}}\n");
212 | }
213 |
214 | int calc_stages(const int working_width, const int phase_bits) {
215 | unsigned nstages = 0;
216 |
217 | for(nstages=0; nstages<64; nstages++) {
218 | double x;
219 | unsigned long phase_value;
220 |
221 | x = atan2(1., pow(2,nstages+1));
222 | x *= (4.0 * (1ul<<(phase_bits-2))) / (M_PI * 2.0);
223 | phase_value = (unsigned)x;
224 | if (phase_value == 0l)
225 | break;
226 | if (working_width <= (int)nstages)
227 | break;
228 | } return nstages;
229 | }
230 |
231 | int calc_stages(const int phase_bits) {
232 | unsigned nstages = 0;
233 |
234 | for(nstages=0; nstages<64; nstages++) {
235 | double x;
236 | unsigned long phase_value;
237 |
238 | x = atan2(1., pow(2,nstages+1));
239 | x *= (4.0 * (1ul<<(phase_bits-2))) / (M_PI * 2.0);
240 | phase_value = (unsigned)x;
241 | if (phase_value == 0l)
242 | break;
243 | } return nstages;
244 | }
245 |
246 | int calc_phase_bits(const int output_width) {
247 | // The number of phase bits required needs to be such that
248 | // the sine of the minimum phase must produce less than a sample
249 | // of value. Further bits won't mean much in reality.
250 | //
251 | // sin(2*pi/(2^phase_bits))*(2^(output_width-1)-1) < 1/2
252 | unsigned phase_bits;
253 |
254 | for(phase_bits=3; phase_bits < 64; phase_bits++) {
255 | double ds, a;
256 |
257 | a = (2.0*M_PI/(double)(1ul< for a copy.
31 | // }}}
32 | // License: GPL, v3, as defined and found on www.gnu.org,
33 | // {{{
34 | // http://www.gnu.org/licenses/gpl.html
35 | //
36 | //
37 | ////////////////////////////////////////////////////////////////////////////////
38 | //
39 | // }}}
40 | #ifndef CORDICLIB_H
41 | #define CORDICLIB_H
42 |
43 | #include
44 |
45 | extern int nextlg(unsigned);
46 | extern double cordic_gain(int nstages);
47 | extern double phase_variance(int nstages, int phase_bits);
48 | extern double transform_quantization_variance(int nstages, int xtrabits, int dropped_bits);
49 | extern void cordic_angles(FILE *fp, int nstages, int phase_bits, bool mem = false);
50 | extern int calc_stages(const int working_width, const int phase_bits);
51 | extern int calc_stages(const int phase_bits);
52 | extern int calc_phase_bits(const int output_width);
53 |
54 | #endif
55 |
--------------------------------------------------------------------------------
/sw/hexfile.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: sw/hexfile.cpp
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose:
8 | //
9 | // Creator: Dan Gisselquist, Ph.D.
10 | // Gisselquist Technology, LLC
11 | //
12 | ////////////////////////////////////////////////////////////////////////////////
13 | // }}}
14 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
15 | // {{{
16 | // This program is free software (firmware): you can redistribute it and/or
17 | // modify it under the terms of the GNU General Public License as published
18 | // by the Free Software Foundation, either version 3 of the License, or (at
19 | // your option) any later version.
20 | //
21 | // This program is distributed in the hope that it will be useful, but WITHOUT
22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 | // for more details.
25 | //
26 | // You should have received a copy of the GNU General Public License along
27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
28 | // target there if the PDF file isn't present.) If not, see
29 | // for a copy.
30 | // }}}
31 | // License: GPL, v3, as defined and found on www.gnu.org,
32 | // {{{
33 | // http://www.gnu.org/licenses/gpl.html
34 | //
35 | //
36 | ////////////////////////////////////////////////////////////////////////////////
37 | //
38 | // }}}
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 |
45 | const char *DEFAULT_EXTENSION = ".hex";
46 |
47 | void hextable(const char *fname, const int lgtable, const int ow,
48 | const long *data, const char *extension) {
49 | FILE *hexfp;
50 | char *hexfname;
51 |
52 | if (ow >= 31) {
53 | printf("Internal err: output width too large for internal data type");
54 | assert(ow < 31);
55 | }
56 |
57 | if (lgtable < 2) {
58 | printf("Internal err: Hex-table size should be larger than 4 entries\n");
59 | assert(lgtable >= 2);
60 | }
61 |
62 | // Append .hex to the filename
63 | int slen = strlen(fname);
64 | hexfname = new char [strlen(fname)+strlen(extension)+3];
65 | strcpy(hexfname, fname);
66 | if ((slen>4)&&(hexfname[slen-2]=='.'))
67 | strcpy(&hexfname[slen-2], extension);
68 | else
69 | strcat(hexfname, extension);
70 |
71 | // Open our file
72 | hexfp = fopen(hexfname, "w");
73 | if (NULL == hexfp) {
74 | fprintf(stderr, "ERR: Cannot open %s for writing\n",
75 | hexfname);
76 | } else {
77 | // Write the entriess to it.
78 | int tbl_entries = (1< 0)
83 | assert(data[k] <= msk);
84 | else
85 | assert(data[k] >= -msk-1);
86 | if (0 == (k%8))
87 | fprintf(hexfp, "%s@%08x ", (k!=0)?"\n":"", k);
88 | fprintf(hexfp, "%0*lx ", nc, data[k] & msk);
89 | } fprintf(hexfp, "\n");
90 | }
91 |
92 | fclose(hexfp);
93 | delete[] hexfname;
94 | }
95 |
--------------------------------------------------------------------------------
/sw/hexfile.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: sw/hexfile.h
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose:
8 | //
9 | // Creator: Dan Gisselquist, Ph.D.
10 | // Gisselquist Technology, LLC
11 | //
12 | ////////////////////////////////////////////////////////////////////////////////
13 | // }}}
14 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
15 | // {{{
16 | // This program is free software (firmware): you can redistribute it and/or
17 | // modify it under the terms of the GNU General Public License as published
18 | // by the Free Software Foundation, either version 3 of the License, or (at
19 | // your option) any later version.
20 | //
21 | // This program is distributed in the hope that it will be useful, but WITHOUT
22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 | // for more details.
25 | //
26 | // You should have received a copy of the GNU General Public License along
27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
28 | // target there if the PDF file isn't present.) If not, see
29 | // for a copy.
30 | // }}}
31 | // License: GPL, v3, as defined and found on www.gnu.org,
32 | // {{{
33 | // http://www.gnu.org/licenses/gpl.html
34 | //
35 | //
36 | ////////////////////////////////////////////////////////////////////////////////
37 | //
38 | // }}}
39 | #ifndef HEXTABLE_H
40 | #define HEXTABLE_H
41 |
42 | extern const char *DEFAULT_EXTENSION; // =".hex";
43 | void hextable(const char *fname, const int lgtable, const int ow,
44 | const long *data, const char *extension = DEFAULT_EXTENSION);
45 |
46 | #endif // HEXTABLE_H
47 |
--------------------------------------------------------------------------------
/sw/legal.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: sw/legal.cpp
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: To insert a legal copywrite statement at the top of every file
8 | // called.
9 | //
10 | // Creator: Dan Gisselquist, Ph.D.
11 | // Gisselquist Technology, LLC
12 | //
13 | ////////////////////////////////////////////////////////////////////////////////
14 | // }}}
15 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
16 | // {{{
17 | // This program is free software (firmware): you can redistribute it and/or
18 | // modify it under the terms of the GNU General Public License as published
19 | // by the Free Software Foundation, either version 3 of the License, or (at
20 | // your option) any later version.
21 | //
22 | // This program is distributed in the hope that it will be useful, but WITHOUT
23 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
24 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 | // for more details.
26 | //
27 | // You should have received a copy of the GNU General Public License along
28 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
29 | // target there if the PDF file isn't present.) If not, see
30 | // for a copy.
31 | // }}}
32 | // License: GPL, v3, as defined and found on www.gnu.org,
33 | // {{{
34 | // http://www.gnu.org/licenses/gpl.html
35 | //
36 | //
37 | ////////////////////////////////////////////////////////////////////////////////
38 | //
39 | // }}}
40 | #include
41 | #include
42 | #include
43 | #include
44 |
45 | #include "legal.h"
46 |
47 | const char PROJECT[] = "A series of CORDIC related projects";
48 |
49 | void legal(FILE *fp, const char *fname, const char *project,
50 | const char *purpose, const char *cmdline) {
51 | fprintf(fp,
52 | "////////////////////////////////////////////////////////////////////////////////\n"
53 | "//\n"
54 | "// Filename: %s\n"
55 | "// {{{\n"
56 | "// Project: %s\n"
57 | "//\n"
58 | "// Purpose: %s\n"
59 | "//\n"
60 | "// This core was generated via a core generator using the following command\n"
61 | "// line:\n"
62 | "//\n"
63 | "// %% %s\n"
64 | "//\n"
65 | "// Creator: Dan Gisselquist, Ph.D.\n"
66 | "// Gisselquist Technology, LLC\n"
67 | "//\n"
68 | "////////////////////////////////////////////////////////////////////////////////\n"
69 | "// }}}\n"
70 | "// Copyright (C) 2017-2024, Gisselquist Technology, LLC\n"
71 | "// {{{\n"
72 | "// This file is part of the CORDIC related project set.\n"
73 | "//\n"
74 | "// The CORDIC related project set is free software (firmware): you can\n"
75 | "// redistribute it and/or modify it under the terms of the GNU Lesser General\n"
76 | "// Public License as published by the Free Software Foundation, either version\n"
77 | "// 3 of the License, or (at your option) any later version.\n"
78 | "//\n"
79 | "// The CORDIC related project set is distributed in the hope that it will be\n"
80 | "// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
81 | "// MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser\n"
82 | "// General Public License for more details.\n"
83 | "//\n"
84 | "// You should have received a copy of the GNU Lesser General Public License\n"
85 | "// along with this program. (It's in the $(ROOT)/doc directory. Run make\n"
86 | "// with no target there if the PDF file isn't present.) If not, see\n"
87 | // for a copy.\n"
88 | ""//\n"
89 | "// License: LGPL, v3, as defined and found on www.gnu.org,\n"
90 | "// http://www.gnu.org/licenses/lgpl.html\n"
91 | "//\n"
92 | "////////////////////////////////////////////////////////////////////////////////\n"
93 | "//\n"
94 | "// }}}\n", fname, project, purpose, (cmdline) ? cmdline : "(Not given)");
95 | }
96 |
97 | char *modulename(const char *fname) {
98 | const char *cptr;
99 | char *ptr;
100 | int slen;
101 |
102 | cptr = strrchr(fname, '/');
103 | if (NULL == cptr)
104 | ptr = strdup(fname);
105 | else
106 | ptr = strdup(cptr+1);
107 |
108 | slen = strlen(ptr);
109 | if ((slen > 2)&&(0 == strcmp(&ptr[slen-2], ".v")))
110 | ptr[slen-2] = '\0';
111 | return ptr;
112 | }
113 |
114 |
--------------------------------------------------------------------------------
/sw/legal.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: sw/legal.h
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: To insert a legal copywrite statement at the top of every file
8 | // called.
9 | //
10 | // Creator: Dan Gisselquist, Ph.D.
11 | // Gisselquist Technology, LLC
12 | //
13 | ////////////////////////////////////////////////////////////////////////////////
14 | // }}}
15 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
16 | // {{{
17 | // This program is free software (firmware): you can redistribute it and/or
18 | // modify it under the terms of the GNU General Public License as published
19 | // by the Free Software Foundation, either version 3 of the License, or (at
20 | // your option) any later version.
21 | //
22 | // This program is distributed in the hope that it will be useful, but WITHOUT
23 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
24 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 | // for more details.
26 | //
27 | // You should have received a copy of the GNU General Public License along
28 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
29 | // target there if the PDF file isn't present.) If not, see
30 | // for a copy.
31 | // }}}
32 | // License: GPL, v3, as defined and found on www.gnu.org,
33 | // {{{
34 | // http://www.gnu.org/licenses/gpl.html
35 | //
36 | //
37 | ////////////////////////////////////////////////////////////////////////////////
38 | //
39 | // }}}
40 | #ifndef LEGAL_H
41 | #define LEGAL_H
42 |
43 | #include
44 | #include
45 |
46 | extern const char PROJECT[];
47 |
48 | extern void legal(FILE *fp, const char *fname, const char *project,
49 | const char *purpose, const char *cmdline = NULL);
50 | extern char *modulename(const char *fname);
51 |
52 | #endif
53 |
--------------------------------------------------------------------------------
/sw/quadtbl.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: sw/quadtbl.h
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose:
8 | //
9 | // Creator: Dan Gisselquist, Ph.D.
10 | // Gisselquist Technology, LLC
11 | //
12 | ////////////////////////////////////////////////////////////////////////////////
13 | // }}}
14 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
15 | // {{{
16 | // This program is free software (firmware): you can redistribute it and/or
17 | // modify it under the terms of the GNU General Public License as published
18 | // by the Free Software Foundation, either version 3 of the License, or (at
19 | // your option) any later version.
20 | //
21 | // This program is distributed in the hope that it will be useful, but WITHOUT
22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 | // for more details.
25 | //
26 | // You should have received a copy of the GNU General Public License along
27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
28 | // target there if the PDF file isn't present.) If not, see
29 | // for a copy.
30 | // }}}
31 | // License: GPL, v3, as defined and found on www.gnu.org,
32 | // {{{
33 | // http://www.gnu.org/licenses/gpl.html
34 | //
35 | //
36 | ////////////////////////////////////////////////////////////////////////////////
37 | //
38 | // }}}
39 | #ifndef QUADTBL_H
40 | #define QUADTBL_H
41 |
42 | extern double sinc(double v);
43 | extern void build_quadtbls(const char *fname,
44 | const int lgsz, const int wid,
45 | int &cbits, int &lbits, int &qbits, double &tblerr);
46 | extern void quadtbl(FILE *fp, FILE *fhp, const char *cmdline,
47 | const char *fname, int phase_bits, int ow, int nxtra,
48 | bool with_reset, bool with_aux, bool async_reset);
49 |
50 | #endif
51 |
--------------------------------------------------------------------------------
/sw/seqcordic.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: sw/seqcordic.h
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose:
8 | //
9 | // Creator: Dan Gisselquist, Ph.D.
10 | // Gisselquist Technology, LLC
11 | //
12 | ////////////////////////////////////////////////////////////////////////////////
13 | // }}}
14 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
15 | // {{{
16 | // This program is free software (firmware): you can redistribute it and/or
17 | // modify it under the terms of the GNU General Public License as published
18 | // by the Free Software Foundation, either version 3 of the License, or (at
19 | // your option) any later version.
20 | //
21 | // This program is distributed in the hope that it will be useful, but WITHOUT
22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 | // for more details.
25 | //
26 | // You should have received a copy of the GNU General Public License along
27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
28 | // target there if the PDF file isn't present.) If not, see
29 | // for a copy.
30 | // }}}
31 | // License: GPL, v3, as defined and found on www.gnu.org,
32 | // {{{
33 | // http://www.gnu.org/licenses/gpl.html
34 | //
35 | //
36 | ////////////////////////////////////////////////////////////////////////////////
37 | //
38 | // }}}
39 | #ifndef SEQCORDIC_H
40 | #define SEQCORDIC_H
41 |
42 | #include
43 |
44 | #include "basiccordic.h"
45 |
46 | void seqcordic(FILE *fp, FILE *fhp, const char *cmdline, const char *fname,
47 | int nstages, int iw, int ow, int nxtra,
48 | int phase_bits=32,
49 | bool with_reset=true, bool with_aux = true,
50 | bool async_reset=false);
51 |
52 | #endif // SEQCORDIC_H
53 |
--------------------------------------------------------------------------------
/sw/seqpolar.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: sw/seqpolar.cpp
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose:
8 | //
9 | // Creator: Dan Gisselquist, Ph.D.
10 | // Gisselquist Technology, LLC
11 | //
12 | ////////////////////////////////////////////////////////////////////////////////
13 | // }}}
14 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
15 | // {{{
16 | // This program is free software (firmware): you can redistribute it and/or
17 | // modify it under the terms of the GNU General Public License as published
18 | // by the Free Software Foundation, either version 3 of the License, or (at
19 | // your option) any later version.
20 | //
21 | // This program is distributed in the hope that it will be useful, but WITHOUT
22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 | // for more details.
25 | //
26 | // You should have received a copy of the GNU General Public License along
27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
28 | // target there if the PDF file isn't present.) If not, see
29 | // for a copy.
30 | // }}}
31 | // License: GPL, v3, as defined and found on www.gnu.org,
32 | // {{{
33 | // http://www.gnu.org/licenses/gpl.html
34 | //
35 | //
36 | ////////////////////////////////////////////////////////////////////////////////
37 | //
38 | // }}}
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 |
46 | #include "legal.h"
47 | #include "cordiclib.h"
48 | #include "topolar.h"
49 |
50 | void seqpolar(FILE *fp, FILE *fhp, const char *cmdline, const char *fname,
51 | int nstages,
52 | int iw, int ow, int nxtra, int phase_bits,
53 | bool with_reset, bool with_aux, bool async_reset) {
54 | // {{{
55 | int working_width = iw;
56 | const char *name;
57 | const char PURPOSE[] =
58 | "This is a rectangular to polar conversion routine based upon an\n"
59 | "//\t\tinternal CORDIC implementation. Basically, the input is\n"
60 | "//\tprovided in i_xval and i_yval. The internal CORDIC rotator will rotate\n"
61 | "//\t(i_xval, i_yval) until i_yval is approximately zero. The resulting\n"
62 | "//\txvalue and phase will be placed into o_xval and o_phase respectively.\n"
63 | "//\n"
64 | "//\tThis particular version of the polar to rectangular CORDIC converter\n"
65 | "//\tconverter processes a somple one at a time. It is completely\n"
66 | "//\tsequential, not parallel at all.\n//",
67 | HPURPOSE[] =
68 | "This .h file notes the default parameter values from\n"
69 | "//\t\twithin the generated file. It is used to communicate\n"
70 | "//\tinformation about the design to the bench testing code.";
71 |
72 | legal(fp, fname, PROJECT, PURPOSE, cmdline);
73 | if (nxtra < 2)
74 | nxtra = 2;
75 | assert(phase_bits >= 3);
76 |
77 | if (working_width < ow)
78 | working_width = ow;
79 | working_width += nxtra;
80 |
81 | working_width += nxtra;
82 | name = modulename(fname);
83 |
84 | std::string resetw = (!with_reset) ? ""
85 | : (async_reset) ? "i_areset_n, ":"i_reset, ";
86 | std::string always_reset = "\talways @(posedge i_clk)\n\t";
87 | if ((with_reset)&&(async_reset))
88 | always_reset = "\talways @(posedge i_clk, negedge i_areset_n)\n"
89 | "\tif (!i_areset_n)\n";
90 | else if (with_reset)
91 | always_reset = "\talways @(posedge i_clk)\n"
92 | "\tif (i_reset)\n";
93 |
94 | fprintf(fp, "`default_nettype\tnone\n//\n");
95 | fprintf(fp,
96 | "module %s #(\n"
97 | "\t\t// {{{\n"
98 | "\t\tlocalparam\tIW=%2d,\t// The number of bits in our inputs\n"
99 | "\t\t\t\tOW=%2d,// The number of output bits to produce\n"
100 | "\t\t\t\t// NSTAGES=%2d,\n"
101 | "\t\t\t\t// XTRA=%2d,// Extra bits for internal precision\n"
102 | "\t\t\t\tWW=%2d,\t// Our working bit-width\n"
103 | "\t\t\t\tPW=%2d\t// Bits in our phase variables\n"
104 | "\t\t// }}}\n"
105 | "\t) (\n"
106 | "\t\t// {{{\n",
107 | name, iw, ow, nstages, nxtra, working_width, phase_bits);
108 | fprintf(fp,
109 | "\t\tinput\twire\t\t\t\ti_clk, %si_stb,\n"
110 | "\t\tinput\twire\tsigned\t[(IW-1):0]\ti_xval, i_yval,%s\n"
111 | "\t\toutput\twire\t\t\t\to_busy,\n"
112 | "\t\toutput\treg\t\t\t\to_done,\n"
113 | "\t\toutput\treg\tsigned\t[(OW-1):0]\to_mag,\n"
114 | "\t\toutput\treg\t\t[(PW-1):0]\to_phase%s\n"
115 | "\t\t// }}}\n"
116 | "\t);\n",
117 | resetw.c_str(),
118 | (with_aux) ? "\n\t\tinput\twire\t\t\t\ti_aux," : "",
119 | (with_aux)?",\n\t\toutput\treg\t\t\t\to_aux":"");
120 |
121 |
122 | fprintf(fp,
123 | "\n"
124 | "\t// First step: expand our input to our working width.\n"
125 | "\t// {{{\n"
126 | "\t// This is going to involve extending our input by one\n"
127 | "\t// (or more) bits in addition to adding any xtra bits on\n"
128 | "\t// bits on the right. The one bit extra on the left is to\n"
129 | "\t// allow for any accumulation due to the cordic gain\n"
130 | "\t// within the algorithm.\n"
131 | "\t// \n"
132 | "\twire\tsigned [(WW-1):0]\te_xval, e_yval;\n");
133 |
134 | if (working_width-iw > 2) {
135 | fprintf(fp,
136 | "\tassign\te_xval = { {(2){i_xval[(IW-1)]}}, i_xval, {(WW-IW-2){1'b0}} };\n"
137 | "\tassign\te_yval = { {(2){i_yval[(IW-1)]}}, i_yval, {(WW-IW-2){1'b0}} };\n\n");
138 | } else if (working_width-iw > 1) {
139 | fprintf(fp,
140 | "\tassign\te_xval = { {(2){i_xval[(IW-1)]}}, i_xval };\n"
141 | "\tassign\te_yval = { {(2){i_yval[(IW-1)]}}, i_yval };\n\n");
142 | } else {
143 | fprintf(fp,
144 | "\tassign\te_xval = { {(2){i_xval[(IW-1)]}, i_xval[(IW-1):1] };\n"
145 | "\tassign\te_yval = { {(2){i_yval[(IW-1)]}, i_yval[(IW-1):1] };\n\n");
146 | } fprintf(fp, "\t// }}}\n");
147 |
148 | fprintf(fp,
149 | "\t// Declare variables for all of the separate stages\n"
150 | "\t// {{{\n");
151 |
152 | fprintf(fp,
153 | "\treg\tsigned\t[(WW-1):0]\txv, yv, prex, prey;\n"
154 | "\treg\t\t[(PW-1):0]\tph, preph;\n\n");
155 | if (with_aux)
156 | fprintf(fp, "\treg\t\taux;\n");
157 | fprintf(fp, "\treg\t\tidle, pre_valid;\n");
158 | fprintf(fp, "\treg\t[%d:0]\tstate;\n\n",
159 | nextlg((unsigned)nstages+1)-1);
160 | fprintf(fp, "\twire\t\tlast_state;\n"
161 | "\t// }}}\n\n");
162 |
163 | if (with_aux) {
164 | fprintf(fp,
165 | "\t//\n"
166 | "\t// Handle the auxilliary logic.\n"
167 | "\t// {{{\n"
168 | "\t// The auxilliary bit is designed so that you can place a valid bit into\n"
169 | "\t// the CORDIC function, and see when it comes out. While the bit is\n"
170 | "\t// allowed to be anything, the requirement of this bit is that it *must*\n"
171 | "\t// be aligned with the output when done. That is, if i_xval and i_yval\n"
172 | "\t// are input together with i_aux, then when o_xval and o_yval are set\n"
173 | "\t// to this value, o_aux *must* contain the value that was in i_aux.\n"
174 | "\t//\n"
175 | "\tinitial\taux = 0;\n");
176 |
177 | fprintf(fp, "%s", always_reset.c_str());
178 |
179 | if (with_reset)
180 | fprintf(fp,
181 | "\t\taux <= 0;\n"
182 | "\telse ");
183 |
184 | fprintf(fp, "if ((i_stb)&&(!o_busy))\n"
185 | "\t\taux <= i_aux;\n"
186 | "\t// }}}\n\n");
187 | }
188 |
189 | fprintf(fp,
190 | "\t// First stage, map to within +/- 45 degrees\n"
191 | "\t// {{{\n"
192 | "\talways @(posedge i_clk)\n"
193 | "\tcase({i_xval[IW-1], i_yval[IW-1]})\n");
194 |
195 | fprintf(fp,
196 | "\t2\'b01: begin // Rotate by -315 degrees\n"
197 | "\t\t// {{{\n"
198 | "\t\tprex <= e_xval - e_yval;\n"
199 | "\t\tprey <= e_xval + e_yval;\n"
200 | "\t\tpreph <= %d\'h%lx;\n"
201 | "\t\tend\n"
202 | "\t\t// }}}\n",
203 | phase_bits, (7ul << (phase_bits-3)));
204 | fprintf(fp,
205 | "\t2\'b10: begin // Rotate by -135 degrees\n"
206 | "\t\t// {{{\n"
207 | "\t\tprex <= -e_xval + e_yval;\n"
208 | "\t\tprey <= -e_xval - e_yval;\n"
209 | "\t\tpreph <= %d\'h%lx;\n"
210 | "\t\tend\n"
211 | "\t\t// }}}\n",
212 | phase_bits, (3ul << (phase_bits-3)));
213 |
214 | fprintf(fp,
215 | "\t2\'b11: begin // Rotate by -225 degrees\n"
216 | "\t\t// {{{\n"
217 | "\t\tprex <= -e_xval - e_yval;\n"
218 | "\t\tprey <= e_xval - e_yval;\n"
219 | "\t\tpreph <= %d\'h%lx;\n"
220 | "\t\tend\n"
221 | "\t\t// }}}\n",
222 | phase_bits, (5ul << (phase_bits-3)));
223 |
224 | fprintf(fp,
225 | "\t// 2\'b00:\n"
226 | "\tdefault: begin // Rotate by -45 degrees\n"
227 | "\t\t// {{{\n"
228 | "\t\tprex <= e_xval + e_yval;\n"
229 | "\t\tprey <= -e_xval + e_yval;\n"
230 | "\t\tpreph <= %d\'h%lx;\n"
231 | "\t\tend\n"
232 | "\t\t// }}}\n"
233 | "\tendcase\n"
234 | "\t// }}}\n\n",
235 | phase_bits, (1ul << (phase_bits-3)));
236 |
237 | cordic_angles(fp, nstages, phase_bits, true);
238 |
239 | fprintf(fp, "\n\tassign last_state = (state >= %d);\n", nstages+1);
240 | fprintf(fp,
241 | "\n\t// idle\n\t// {{{\n"
242 | "\tinitial\tidle = 1\'b1;\n%s", always_reset.c_str());
243 | if (with_reset)
244 | fprintf(fp, "\t\tidle <= 1\'b1;\n\telse ");
245 | else
246 | fprintf(fp, "\t");
247 | fprintf(fp, "if (i_stb)\n"
248 | "\t\tidle <= 1\'b0;\n"
249 | "\telse if (last_state)\n"
250 | "\t\tidle <= 1\'b1;\n\t// }}}\n");
251 |
252 | fprintf(fp,
253 | "\t// pre_valid\n"
254 | "\t// {{{\n"
255 | "\tinitial\tpre_valid = 1\'b0;\n%s", always_reset.c_str());
256 | if (with_reset)
257 | fprintf(fp, "\t\tpre_valid <= 1\'b0;\n\telse\n");
258 | fprintf(fp, "\t\tpre_valid <= (i_stb)&&(idle);\n"
259 | "\t// }}}\n\n");
260 |
261 |
262 | fprintf(fp,
263 | "\t// state\n"
264 | "\t// {{{\n"
265 | "\tinitial\tstate = 0;\n%s", always_reset.c_str());
266 | if (with_reset)
267 | fprintf(fp, "\t\tstate <= 0;\n\telse ");
268 | else
269 | fprintf(fp, "\t");
270 | fprintf(fp, "if (idle)\n"
271 | "\t\tstate <= 0;\n"
272 | "\telse if (last_state)\n"
273 | "\t\tstate <= 0;\n"
274 | "\telse\n"
275 | "\t\tstate <= state + 1;\n\t// }}}\n");
276 |
277 | fprintf(fp,
278 | "\t// cangle -- table lookup\n"
279 | "\t// {{{\n"
280 | "\talways @(posedge i_clk)\n"
281 | "\t\tcangle <= cordic_angle[state[%d:0]];\n\t// }}}\n",
282 | nextlg((unsigned)nstages)-1);
283 |
284 | fprintf(fp,
285 | "\t// Actual CORDIC rotation\n"
286 | "\t// {{{\n"
287 | "\t// Here\'s where we are going to put the actual CORDIC\n"
288 | "\t// rectangular to polar loop. Everything up to this\n"
289 | "\t// point has simply been necessary preliminaries.\n");
290 |
291 | fprintf(fp, "\talways @(posedge i_clk)\n"
292 | "\tif (pre_valid)\n"
293 | "\tbegin\n"
294 | "\t\t// {{{\n"
295 | "\t\txv <= prex;\n"
296 | "\t\tyv <= prey;\n"
297 | "\t\tph <= preph;\n"
298 | "\t\t// }}}\n"
299 | "\tend else if (yv[(WW-1)]) // Below the axis\n"
300 | "\tbegin\n"
301 | "\t\t// {{{\n"
302 | "\t\t// If the vector is below the x-axis, rotate by\n"
303 | "\t\t// the CORDIC angle in a positive direction.\n"
304 | "\t\txv <= xv - (yv>>>state);\n"
305 | "\t\tyv <= yv + (xv>>>state);\n"
306 | "\t\tph <= ph - cangle;\n"
307 | "\t\t// }}}\n"
308 | "\tend else begin\n"
309 | "\t\t// {{{\n"
310 | "\t\t// On the other hand, if the vector is above the\n"
311 | "\t\t// x-axis, then rotate in the other direction\n"
312 | "\t\txv <= xv + (yv>>>state);\n"
313 | "\t\tyv <= yv - (xv>>>state);\n"
314 | "\t\tph <= ph + cangle;\n"
315 | "\t\t// }}}\n"
316 | "\tend\n\t// }}}\n");
317 |
318 | fprintf(fp, "\n\t// o_done\n\t// {{{\n"
319 | "%s", always_reset.c_str());
320 | if (with_reset)
321 | fprintf(fp, "\t\to_done <= 1\'b0;\n\telse\n");
322 | fprintf(fp, "\t\to_done <= (last_state);\n\t// }}}\n");
323 |
324 | if (working_width > ow+1) {
325 | fprintf(fp,
326 | "\t// Round our magnitude towards even\n"
327 | "\t// {{{\n"
328 | "\twire\t[(WW-1):0]\tfinal_mag;\n\n"
329 | "\tassign\tfinal_mag = xv + $signed({{(OW){1\'b0}},\n"
330 | "\t\t\t\txv[(WW-OW)],\n"
331 | "\t\t\t\t{(WW-OW-1){!xv[WW-OW]}} });\n"
332 | "\t// }}}\n"
333 | "\n");
334 |
335 | fprintf(fp, "\t// Output assignments: o_mag, o_phase%s\n"
336 | "\t// {{{\n", (with_aux) ? ", and o_aux":"");
337 | if (with_aux)
338 | fprintf(fp, "\tinitial o_aux = 0;\n");
339 | fprintf(fp, "\talways @(posedge i_clk)\n");
340 | fprintf(fp,
341 | "\tif (last_state)\n"
342 | "\tbegin\n"
343 | "\t\to_mag <= final_mag[(WW-1):(WW-OW)];\n");
344 | } else {
345 | if (with_aux)
346 | fprintf(fp, "\tinitial o_aux = 0;\n");
347 | fprintf(fp, "\talways @(posedge i_clk)\n");
348 | fprintf(fp,
349 | "\tif (last_state)\n"
350 | "\tbegin\t// We accumulate a bit during our processing, so shift by one\n"
351 | "\t\to_mag <= xv[(WW-1):(WW-OW)];\n");
352 | }
353 |
354 | fprintf(fp, "\t\to_phase <= ph;\n");
355 | if (with_aux)
356 | fprintf(fp, "\t\to_aux <= aux;\n");
357 | fprintf(fp, "\tend\n\t// }}}\n");
358 |
359 | fprintf(fp, "\tassign\to_busy = !idle;\n\n");
360 |
361 | if (working_width > ow+1) {
362 | // {{{
363 | fprintf(fp, "\t// Make Verilator happy with pre_.val\n"
364 | "\t// {{{\n\t// verilator lint_off UNUSED\n"
365 | "\twire\tunused_val;\n"
366 | "\tassign\tunused_val = &{ 1\'b0, "
367 | " final_mag[WW-1],\n"
368 | "\t\t\tfinal_mag[(WW-OW-1):0] };\n"
369 | "\t// verilator lint_on UNUSED\n"
370 | "\t// }}}\n");
371 | // }}}
372 | }
373 |
374 | fprintf(fp, "endmodule\n");
375 |
376 | if (NULL != fhp) {
377 | // {{{
378 | char *str = new char[strlen(name)+4], *ptr;
379 | sprintf(str, "%s.h", name);
380 | legal(fhp, str, PROJECT, HPURPOSE);
381 | ptr = str;
382 | while(*ptr) {
383 | if ('.' == *ptr)
384 | *ptr = '_';
385 | else *ptr = toupper(*ptr);
386 | ptr++;
387 | }
388 | fprintf(fhp, "#ifndef\t%s\n", str);
389 | fprintf(fhp, "#define\t%s\n", str);
390 | if (async_reset)
391 | fprintf(fhp, "#define\tASYNC_RESET\n");
392 |
393 | fprintf(fhp, "#ifdef\tCLOCKS_PER_OUTPUT\n");
394 | fprintf(fhp, "#undef\tCLOCKS_PER_OUTPUT\n");
395 | fprintf(fhp, "#endif\t// CLOCKS_PER_OUTPUT\n");
396 | fprintf(fhp, "#define\tCLOCKS_PER_OUTPUT\t%d\n", nstages+3);
397 |
398 | fprintf(fhp, "const int IW = %d;\n", iw);
399 | fprintf(fhp, "const int OW = %d;\n", ow);
400 | fprintf(fhp, "const int NEXTRA = %d;\n", nxtra);
401 | fprintf(fhp, "const int WW = %d;\n", working_width);
402 | fprintf(fhp, "const int PW = %d;\n", phase_bits);
403 | fprintf(fhp, "const int NSTAGES = %d;\n", nstages);
404 | fprintf(fhp, "const double\tQUANTIZATION_VARIANCE = %.16f; // (Units^2)\n",
405 | transform_quantization_variance(nstages,
406 | working_width-iw, working_width-ow));
407 | fprintf(fhp, "const double\tPHASE_VARIANCE_RAD = %.16f; // (Radians^2)\n",
408 | phase_variance(nstages, phase_bits));
409 | fprintf(fhp, "const double\tGAIN = %.16f;\n",
410 | cordic_gain(nstages) * sqrt(2.0) / 2.0);
411 | fprintf(fhp, "const bool\tHAS_RESET = %s;\n", with_reset?"true":"false");
412 | fprintf(fhp, "const bool\tHAS_AUX = %s;\n", with_aux?"true":"false");
413 | if (with_reset)
414 | fprintf(fhp, "#define\tHAS_RESET_WIRE\n");
415 | if (with_aux)
416 | fprintf(fhp, "#define\tHAS_AUX_WIRES\n");
417 | fprintf(fhp, "#endif // %s\n", str);
418 |
419 | delete[] str;
420 | // }}}
421 | }
422 | // }}}
423 | }
424 |
--------------------------------------------------------------------------------
/sw/seqpolar.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: sw/seqpolar.h
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose:
8 | //
9 | // Creator: Dan Gisselquist, Ph.D.
10 | // Gisselquist Technology, LLC
11 | //
12 | ////////////////////////////////////////////////////////////////////////////////
13 | // }}}
14 | // Copyright (C) 2018-2024, Gisselquist Technology, LLC
15 | // {{{
16 | // This program is free software (firmware): you can redistribute it and/or
17 | // modify it under the terms of the GNU General Public License as published
18 | // by the Free Software Foundation, either version 3 of the License, or (at
19 | // your option) any later version.
20 | //
21 | // This program is distributed in the hope that it will be useful, but WITHOUT
22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 | // for more details.
25 | //
26 | // You should have received a copy of the GNU General Public License along
27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
28 | // target there if the PDF file isn't present.) If not, see
29 | // for a copy.
30 | // }}}
31 | // License: GPL, v3, as defined and found on www.gnu.org,
32 | // {{{
33 | // http://www.gnu.org/licenses/gpl.html
34 | //
35 | //
36 | ////////////////////////////////////////////////////////////////////////////////
37 | //
38 | // }}}
39 | #ifndef SEQPOLAR_H
40 | #define SEQPOLAR_H
41 |
42 | #include
43 |
44 | extern void seqpolar(FILE *fp, FILE *fhp, const char *cmdline,
45 | const char *fname,
46 | int nstages, int iw, int ow, int nxtra,
47 | int phase_bits=32,
48 | bool with_reset=true, bool with_aux = true,
49 | bool async_reset = false);
50 |
51 | #endif // SEQPOLAR_H
52 |
--------------------------------------------------------------------------------
/sw/sintable.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: sw/sintable.cpp
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose: To define two different table-based sinewave calculators that
8 | // can be used within an FPGA. This routine not only creates a
9 | // table based sinewave calculator, but also creates a hex file defining
10 | // the values in the table that can be used.
11 | //
12 | // Creator: Dan Gisselquist, Ph.D.
13 | // Gisselquist Technology, LLC
14 | //
15 | ////////////////////////////////////////////////////////////////////////////////
16 | // }}}
17 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
18 | // {{{
19 | // This program is free software (firmware): you can redistribute it and/or
20 | // modify it under the terms of the GNU General Public License as published
21 | // by the Free Software Foundation, either version 3 of the License, or (at
22 | // your option) any later version.
23 | //
24 | // This program is distributed in the hope that it will be useful, but WITHOUT
25 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
26 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
27 | // for more details.
28 | //
29 | // You should have received a copy of the GNU General Public License along
30 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
31 | // target there if the PDF file isn't present.) If not, see
32 | // for a copy.
33 | // }}}
34 | // License: GPL, v3, as defined and found on www.gnu.org,
35 | // {{{
36 | // http://www.gnu.org/licenses/gpl.html
37 | //
38 | //
39 | ////////////////////////////////////////////////////////////////////////////////
40 | //
41 | // }}}
42 | #include
43 | #include
44 | #include
45 | #include
46 | #include
47 | #include
48 | #include "hexfile.h"
49 |
50 | #include "legal.h"
51 |
52 | void sintable(FILE *fp, const char *cmdline, const char *fname,
53 | int lgtable, int ow,
54 | bool with_reset, bool with_aux, bool async_reset) {
55 | // {{{
56 | char *name;
57 | const char PURPOSE[] =
58 | "This is a very simple sinewave table lookup approach\n"
59 | "//\t\tapproach to generating a sine wave. It has the lowest latency\n"
60 | "//\tamong all sinewave generation alternatives.";
61 |
62 | if (lgtable >= 24) {
63 | fprintf(stderr, "ERR: Requested table size is greater than 16M\n\n");
64 | fprintf(stderr, "While this is an arbitrary limit, few FPGA's have this kind of\n");
65 | fprintf(stderr, "block RAM. If you know what you are doing, you can change this\n");
66 | fprintf(stderr, "limit up to perhaps 30 without much hassle. Beyond that, be\n");
67 | fprintf(stderr, "aware of integer overflow.\n");
68 | exit(EXIT_FAILURE);
69 | }
70 |
71 | legal(fp, fname, PROJECT, PURPOSE);
72 | fprintf(fp, "`default_nettype\tnone\n//\n");
73 | name = modulename(fname);
74 |
75 | std::string resetw = (!with_reset) ? ""
76 | : (async_reset) ? "i_areset_n, ":"i_reset, ";
77 | std::string always_reset;
78 | if ((with_reset)&&(async_reset))
79 | always_reset = "\talways @(posedge i_clk, negedge i_areset_n)\n"
80 | "\tif (!i_areset_n)\n";
81 | else if (with_reset)
82 | always_reset = "\talways @(posedge i_clk)\n"
83 | "\tif (i_reset)\n";
84 | else
85 | always_reset = "\talways @(posedge i_clk)\n\t";
86 |
87 | fprintf(fp,
88 | "module %s #(\n"
89 | "\t\t// {{{\n"
90 | "\tparameter\tPW =%2d, // Number of bits in the input phase\n"
91 | "\t\t\tOW =%2d // Number of output bits\n"
92 | "\t\t// }}}\n"
93 | "\t) (\n"
94 | "\t\t// {{{\n"
95 | "\tinput\twire\t\t\ti_clk, %si_ce,\n"
96 | "\tinput\twire\t[(PW-1):0]\ti_phase,\n"
97 | "\toutput\treg\t[(OW-1):0]\to_val%s\n",
98 | name,
99 | // resetw.c_str(),
100 | // (with_aux) ? "i_aux, " :"",
101 | // (with_aux) ? ", o_aux" :"",
102 | lgtable, ow,
103 | resetw.c_str(), (with_aux) ? ",":"");
104 | if (with_aux)
105 | fprintf(fp,
106 | "\t//\n"
107 | "\tinput\twire\t\t\ti_aux,\n"
108 | "\toutput\treg\t\t\to_aux\n");
109 | fprintf(fp, "\t\t// }}}\n"
110 | "\t);\n\n");
111 |
112 | fprintf(fp,
113 | "\t// Declare variables\n"
114 | "\t// {{{\n"
115 | "\treg\t[(OW-1):0]\t\ttbl\t[0:((1<2);
190 | if (lgtable >= 26) {
191 | fprintf(stderr, "ERR: Requested table size is greater than 16M\n\n");
192 | fprintf(stderr, "While this is an arbitrary limit, few FPGA's have this kind of\n");
193 | fprintf(stderr, "block RAM. If you know what you are doing, you can change this\n");
194 | fprintf(stderr, "limit up to perhaps 30 without much hassle. Beyond that, be\n");
195 | fprintf(stderr, "aware of integer overflow.\n");
196 | exit(EXIT_FAILURE);
197 | }
198 |
199 | legal(fp, fname, PROJECT, PURPOSE, cmdline);
200 | name = modulename(fname);
201 |
202 | std::string resetw = (!with_reset) ? ""
203 | : (async_reset) ? "i_areset_n":"i_reset";
204 | std::string always_reset;
205 | if ((with_reset)&&(async_reset))
206 | always_reset = "\talways @(posedge i_clk, negedge i_areset_n)\n"
207 | "\tif (!i_areset_n)\n";
208 | else if (with_reset)
209 | always_reset = "\talways @(posedge i_clk)\n"
210 | "\tif (i_reset)\n";
211 | else
212 | always_reset = "\talways @(posedge i_clk)\n\t";
213 | // }}}
214 |
215 | // Module declaration
216 | // {{{
217 | fprintf(fp,
218 | "module %s #(\n"
219 | // "(i_clk, %s%si_ce, i_phase, %so_val%s);\n"
220 | "\t\t// {{{\n"
221 | "\tparameter\tPW =%2d, // Number of bits in the input phase\n"
222 | "\t\t\tOW =%2d // Number of output bits\n"
223 | "\t\t// }}}\n"
224 | "\t) (\n"
225 | "\t\t// {{{\n"
226 | "\t\tinput\twire\t\t\ti_clk, %s%si_ce,\n"
227 | "\t\tinput\twire\t[(PW-1):0]\ti_phase,\n"
228 | "\t\toutput\treg\t[(OW-1):0]\to_val%s\n",
229 | name,
230 | // resetw.c_str(), (with_reset) ? ", ":"",
231 | // (with_aux) ? "i_aux, ":"",
232 | // (with_aux) ? ", o_aux":"",
233 | lgtable, ow,
234 | resetw.c_str(), (with_reset) ? ", ":"", (with_aux) ? ",":"");
235 |
236 | if (with_aux)
237 | fprintf(fp, "\t//\n"
238 | "\tinput\twire\t\t\ti_aux,\n"
239 | "\toutput\treg\t\t\to_aux\n");
240 | fprintf(fp, "\t\t// }}}\n\t);\n\n");
241 | // }}}
242 |
243 | // Declarations
244 | // {{{
245 | fprintf(fp,
246 | "\t// Declare variables and registers used\n"
247 | "\t// {{{\n"
248 | "\treg\t[(OW-1):0]\t\tquartertable\t[0:((1<<(PW-2))-1)];\n"
249 | "\n"
250 | "\tinitial\t$readmemh(\"%s.hex\", quartertable);\n"
251 | "\n"
252 | "\treg\t[1:0]\tnegate;\n"
253 | "\treg\t[(PW-3):0]\tindex;\n"
254 | "\treg\t[(OW-1):0]\ttblvalue;\n", name);
255 | if (with_aux)
256 | fprintf(fp, "\treg [1:0]\taux;\n");
257 | fprintf(fp, "\t// }}}\n\n");
258 | // }}}
259 |
260 | // Processing
261 | // {{{
262 | fprintf(fp,
263 | "\t// negate, index, tblvalue, o_val\n"
264 | "\t// {{{\n"
265 | "\tinitial\tnegate = 2\'b00;\n"
266 | "\tinitial\tindex = 0;\n"
267 | "\tinitial\ttblvalue= 0;\n"
268 | "\tinitial\to_val = 0;\n");
269 | fprintf(fp, "%s", always_reset.c_str());
270 |
271 | if (with_reset)
272 | fprintf(fp,
273 | "\tbegin\n"
274 | "\t\tnegate <= 2\'b00;\n"
275 | "\t\tindex <= 0;\n"
276 | "\t\ttblvalue<= 0;\n"
277 | "\t\to_val <= 0;\n"
278 | "\tend else ");
279 |
280 | fprintf(fp,
281 | "if (i_ce)\n"
282 | "\tbegin\n"
283 | "\t\t// Clock #1\n"
284 | "\t\t// {{{\n"
285 | "\t\tnegate[0] <= i_phase[(PW-1)];\n"
286 | "\t\tif (i_phase[(PW-2)])\n"
287 | "\t\t\tindex <= ~i_phase[(PW-3):0];\n"
288 | "\t\telse\n"
289 | "\t\t\tindex <= i_phase[(PW-3):0];\n"
290 | "\t\t// }}}\n"
291 | ""
292 | "\t\t// Clock #2\n"
293 | "\t\t// {{{\n"
294 | "\t\ttblvalue <= quartertable[index];\n"
295 | "\t\tnegate[1] <= negate[0];\n"
296 | "\t\t// }}}\n"
297 | ""
298 | "\t\t// Output Clock\n"
299 | "\t\t// {{{\n"
300 | "\t\tif (negate[1])\n"
301 | "\t\t\to_val <= -tblvalue;\n"
302 | "\t\telse\n"
303 | "\t\t\to_val <= tblvalue;\n"
304 | "\t\t// }}}\n"
305 | "\tend\n\t// }}}\n");
306 | // }}}
307 |
308 | if (with_aux) {
309 | // {{{
310 | fprintf(fp, "\t// aux, o_aux\n\t// {{{\n"
311 | "\tinitial\t{ o_aux, aux } = 0;\n");
312 | fprintf(fp, "%s", always_reset.c_str());
313 | if(with_reset)
314 | fprintf(fp, "\t\t{ o_aux, aux } <= 0;\n"
315 | "\telse ");
316 | fprintf(fp, "if (i_ce)\n\t\t{ o_aux, aux } <= { aux, i_aux };\n");
317 | fprintf(fp, "\t// }}}\n");
318 | // }}}
319 | }
320 |
321 | fprintf(fp, "endmodule\n");
322 |
323 | // Build the lookup table
324 | // {{{
325 | long *tbldata;
326 | tbldata = new long[(1< for a copy.
34 | // }}}
35 | // License: GPL, v3, as defined and found on www.gnu.org,
36 | // {{{
37 | // http://www.gnu.org/licenses/gpl.html
38 | //
39 | //
40 | ////////////////////////////////////////////////////////////////////////////////
41 | //
42 | // }}}
43 | #ifndef SINTABLE_H
44 | #define SINTABLE_H
45 |
46 | #include
47 |
48 | extern void sintable(FILE *fp, const char *fname, const char *cmdline,
49 | int lgtable, int ow,
50 | bool with_reset, bool with_aux, bool async_reset);
51 |
52 | extern void quarterwav(FILE *fp, const char *fname, const char *cmdline,
53 | int lgtable, int ow,
54 | bool with_reset, bool with_aux, bool async_reset);
55 |
56 | #endif
57 |
--------------------------------------------------------------------------------
/sw/topolar.cpp:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: sw/topolar.cpp
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose:
8 | //
9 | // Creator: Dan Gisselquist, Ph.D.
10 | // Gisselquist Technology, LLC
11 | //
12 | ////////////////////////////////////////////////////////////////////////////////
13 | // }}}
14 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
15 | // {{{
16 | // This program is free software (firmware): you can redistribute it and/or
17 | // modify it under the terms of the GNU General Public License as published
18 | // by the Free Software Foundation, either version 3 of the License, or (at
19 | // your option) any later version.
20 | //
21 | // This program is distributed in the hope that it will be useful, but WITHOUT
22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 | // for more details.
25 | //
26 | // You should have received a copy of the GNU General Public License along
27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
28 | // target there if the PDF file isn't present.) If not, see
29 | // for a copy.
30 | // }}}
31 | // License: GPL, v3, as defined and found on www.gnu.org,
32 | // {{{
33 | // http://www.gnu.org/licenses/gpl.html
34 | //
35 | //
36 | ////////////////////////////////////////////////////////////////////////////////
37 | //
38 | // }}}
39 | #include
40 | #include
41 | #include
42 | #include
43 | #include
44 | #include
45 |
46 | #include "legal.h"
47 | #include "cordiclib.h"
48 | #include "topolar.h"
49 |
50 | void topolar(FILE *fp, FILE *fhp, const char *cmdline, const char *fname, int nstages, int iw, int ow,
51 | int nxtra, int phase_bits, bool with_reset, bool with_aux,
52 | bool async_reset) {
53 | int working_width = iw;
54 | const char *name;
55 | const char PURPOSE[] =
56 | "This is a rectangular to polar conversion routine based upon an\n"
57 | "//\t\tinternal CORDIC implementation. Basically, the input is\n"
58 | "//\tprovided in i_xval and i_yval. The internal CORDIC rotator will rotate\n"
59 | "//\t(i_xval, i_yval) until i_yval is approximately zero. The resulting\n"
60 | "//\txvalue and phase will be placed into o_xval and o_phase respectively.",
61 | HPURPOSE[] =
62 | "This .h file notes the default parameter values from\n"
63 | "//\t\twithin the generated file. It is used to communicate\n"
64 | "//\tinformation about the design to the bench testing code.";
65 |
66 | legal(fp, fname, PROJECT, PURPOSE, cmdline);
67 | if (nxtra < 2)
68 | nxtra = 2;
69 | assert(phase_bits >= 3);
70 |
71 | if (working_width < ow)
72 | working_width = ow;
73 | working_width += nxtra;
74 |
75 | working_width += nxtra;
76 | name = modulename(fname);
77 |
78 | std::string resetw = (!with_reset) ? ""
79 | : (async_reset) ? "i_areset_n, ":"i_reset, ";
80 | std::string always_reset = "\talways @(posedge i_clk)\n\t";
81 | if ((with_reset)&&(async_reset))
82 | always_reset = "\talways @(posedge i_clk, negedge i_areset_n)\n"
83 | "\tif (!i_areset_n)\n";
84 | else if (with_reset)
85 | always_reset = "\talways @(posedge i_clk)\n"
86 | "\tif (i_reset)\n";
87 |
88 | fprintf(fp, "`default_nettype\tnone\n//\n");
89 | fprintf(fp,
90 | "module %s #(\n"
91 | "\t\t// {{{\n"
92 | "\t\tlocalparam\tIW=%2d,\t// The number of bits in our inputs\n"
93 | "\t\t\tOW=%2d,// The number of output bits to produce\n"
94 | "\t\t\tNSTAGES=%2d,\n"
95 | "\t\t\t// XTRA=%2d,// Extra bits for internal precision\n"
96 | "\t\t\tWW=%2d,\t// Our working bit-width\n"
97 | "\t\t\tPW=%2d\t// Bits in our phase variables\n"
98 | "\t\t// }}}\n"
99 | "\t) (\n"
100 | "\t\t// {{{\n"
101 | "\tinput\twire\t\t\t\ti_clk, %si_ce,\n"
102 | "\tinput\twire\tsigned\t[(IW-1):0]\ti_xval, i_yval,\n"
103 | "\toutput\treg\tsigned\t[(OW-1):0]\to_mag,\n"
104 | "\toutput\treg\t\t[(PW-1):0]\to_phase%s\n",
105 | name,
106 | iw, ow, nstages, nxtra, working_width, phase_bits,
107 | resetw.c_str(), (with_aux) ? ",":"");
108 |
109 | if (with_aux) {
110 | fprintf(fp,
111 | "\tinput\twire\t\t\t\ti_aux,\n"
112 | "\toutput\treg\t\t\t\to_aux\n");
113 | }
114 | fprintf(fp, "\t\t// }}}\n\t);\n");
115 |
116 | fprintf(fp,
117 | "\t// Declare variables for all of the separate stages\n"
118 | "\t// {{{\n"
119 | "\twire\tsigned [(WW-1):0]\te_xval, e_yval;\n"
120 | "\treg signed [(WW-1):0]\txv\t[0:NSTAGES];\n"
121 | "\treg signed [(WW-1):0]\tyv\t[0:NSTAGES];\n"
122 | "\treg [(PW-1):0]\tph\t[0:NSTAGES];\n"
123 | "\t// }}}\n");
124 |
125 |
126 | // Sign extend (if necessary)
127 | // {{{
128 | fprintf(fp,
129 | "\t// Sign extension\n"
130 | "\t// {{{\n"
131 | "\t// First step: expand our input to our working width.\n"
132 | "\t// This is going to involve extending our input by one\n"
133 | "\t// (or more) bits in addition to adding any xtra bits on\n"
134 | "\t// bits on the right. The one bit extra on the left is to\n"
135 | "\t// allow for any accumulation due to the cordic gain\n"
136 | "\t// within the algorithm.\n"
137 | "\t// \n");
138 |
139 | if (working_width-iw > 2) {
140 | fprintf(fp,
141 | "\tassign\te_xval = { {(2){i_xval[(IW-1)]}}, i_xval, {(WW-IW-2){1'b0}} };\n"
142 | "\tassign\te_yval = { {(2){i_yval[(IW-1)]}}, i_yval, {(WW-IW-2){1'b0}} };\n\n");
143 | } else if (working_width-iw > 1) {
144 | fprintf(fp,
145 | "\tassign\te_xval = { {(2){i_xval[(IW-1)]}}, i_xval };\n"
146 | "\tassign\te_yval = { {(2){i_yval[(IW-1)]}}, i_yval };\n\n");
147 | } else {
148 | fprintf(fp,
149 | "\tassign\te_xval = { {(2){i_xval[(IW-1)]}, i_xval[(IW-1):1] };\n"
150 | "\tassign\te_yval = { {(2){i_yval[(IW-1)]}, i_yval[(IW-1):1] };\n\n");
151 | } fprintf(fp, "\t// }}}\n");
152 | // }}}
153 |
154 | if (with_aux) {
155 | // {{{
156 | fprintf(fp,
157 | "\t//\n"
158 | "\t// Handle the auxilliary logic.\n"
159 | "\t// {{{\n"
160 | "\t// The auxilliary bit is designed so that you can place a valid bit into\n"
161 | "\t// the CORDIC function, and see when it comes out. While the bit is\n"
162 | "\t// allowed to be anything, the requirement of this bit is that it *must*\n"
163 | "\t// be aligned with the output when done. That is, if i_xval and i_yval\n"
164 | "\t// are input together with i_aux, then when o_xval and o_yval are set\n"
165 | "\t// to this value, o_aux *must* contain the value that was in i_aux.\n"
166 | "\t//\n"
167 | "\treg\t\t[(NSTAGES):0]\tax;\n"
168 | "\n");
169 |
170 | fprintf(fp,
171 | "\tinitial\tax = 0;\n");
172 | fprintf(fp, "%s", always_reset.c_str());
173 |
174 | if (with_reset)
175 | fprintf(fp,
176 | "\t\tax <= 0;\n"
177 | "\telse ");
178 |
179 | fprintf(fp, "if (i_ce)\n"
180 | "\t\tax <= { ax[(NSTAGES-1):0], i_aux };\n"
181 | "\n");
182 | fprintf(fp, "\t// }}}\n");
183 | // }}}
184 | }
185 |
186 | // Pre-CORDIC rotations
187 | // {{{
188 | fprintf(fp,
189 | "\t// Pre-CORDIC rotation\n"
190 | "\t// {{{\n"
191 | "\tinitial begin\n"
192 | "\t\txv[0] = 0;\n"
193 | "\t\tyv[0] = 0;\n"
194 | "\t\tph[0] = 0;\n"
195 | "\tend\n");
196 | fprintf(fp,
197 | "\t// First stage, map to within +/- 45 degrees\n"
198 | "%s", always_reset.c_str());
199 | if (with_reset)
200 | fprintf(fp,
201 | "\tbegin\n"
202 | "\t\txv[0] <= 0;\n"
203 | "\t\tyv[0] <= 0;\n"
204 | "\t\tph[0] <= 0;\n"
205 | "\tend else ");
206 | fprintf(fp, "if (i_ce)\n\t");
207 |
208 | fprintf(fp,
209 | "case({i_xval[IW-1], i_yval[IW-1]})\n");
210 |
211 | fprintf(fp,
212 | "\t2\'b01: begin // Rotate by -315 degrees\n"
213 | "\t\t// {{{\n"
214 | "\t\txv[0] <= e_xval - e_yval;\n"
215 | "\t\tyv[0] <= e_xval + e_yval;\n"
216 | "\t\tph[0] <= %d\'h%lx;\n"
217 | "\t\tend\n"
218 | "\t\t// }}}\n",
219 | phase_bits, (7ul << (phase_bits-3)));
220 | fprintf(fp,
221 | "\t2\'b10: begin // Rotate by -135 degrees\n"
222 | "\t\t// {{{\n"
223 | "\t\txv[0] <= -e_xval + e_yval;\n"
224 | "\t\tyv[0] <= -e_xval - e_yval;\n"
225 | "\t\tph[0] <= %d\'h%lx;\n"
226 | "\t\tend\n"
227 | "\t\t// }}}\n",
228 | phase_bits, (3ul << (phase_bits-3)));
229 |
230 | fprintf(fp,
231 | "\t2\'b11: begin // Rotate by -225 degrees\n"
232 | "\t\t// {{{\n"
233 | "\t\txv[0] <= -e_xval - e_yval;\n"
234 | "\t\tyv[0] <= e_xval - e_yval;\n"
235 | "\t\tph[0] <= %d\'h%lx;\n"
236 | "\t\tend\n"
237 | "\t\t// }}}\n",
238 | phase_bits, (5ul << (phase_bits-3)));
239 |
240 | fprintf(fp,
241 | "\t// 2\'b00:\n"
242 | "\t\t// {{{\n"
243 | "\tdefault: begin // Rotate by -45 degrees\n"
244 | "\t\txv[0] <= e_xval + e_yval;\n"
245 | "\t\tyv[0] <= -e_xval + e_yval;\n"
246 | "\t\tph[0] <= %d\'h%lx;\n"
247 | "\t\tend\n"
248 | "\t\t// }}}\n"
249 | "\tendcase\n"
250 | "\t// }}}\n",
251 | phase_bits, (1ul << (phase_bits-3)));
252 | // }}}
253 |
254 | cordic_angles(fp, nstages, phase_bits);
255 |
256 | // CORDIC rotation stages
257 | // {{{
258 | fprintf(fp,"\n"
259 | "\t// Actual CORDIC rotations\n"
260 | "\t// {{{\n"
261 | "\tgenvar\ti;\n"
262 | "\tgenerate for(i=0; i= WW))\n"
302 | "\t\t\tbegin // Do nothing but move our vector\n"
303 | "\t\t\t// forward one stage, since we have more\n"
304 | "\t\t\t// stages than valid data\n"
305 | "\t\t\t\t// {{{\n"
306 | "\t\t\t\txv[i+1] <= xv[i];\n"
307 | "\t\t\t\tyv[i+1] <= yv[i];\n"
308 | "\t\t\t\tph[i+1] <= ph[i];\n"
309 | "\t\t\t\t// }}}\n"
310 | "\t\t\tend else if (yv[i][(WW-1)]) // Below the axis\n"
311 | "\t\t\tbegin\n"
312 | "\t\t\t\t// {{{\n"
313 | "\t\t\t\t// If the vector is below the x-axis, rotate by\n"
314 | "\t\t\t\t// the CORDIC angle in a positive direction.\n"
315 | "\t\t\t\txv[i+1] <= xv[i] - (yv[i]>>>(i+1));\n"
316 | "\t\t\t\tyv[i+1] <= yv[i] + (xv[i]>>>(i+1));\n"
317 | "\t\t\t\tph[i+1] <= ph[i] - cordic_angle[i];\n"
318 | "\t\t\t\t// }}}\n"
319 | "\t\t\tend else begin\n"
320 | "\t\t\t\t// {{{\n"
321 | "\t\t\t\t// On the other hand, if the vector is above the\n"
322 | "\t\t\t\t// x-axis, then rotate in the other direction\n"
323 | "\t\t\t\txv[i+1] <= xv[i] + (yv[i]>>>(i+1));\n"
324 | "\t\t\t\tyv[i+1] <= yv[i] - (xv[i]>>>(i+1));\n"
325 | "\t\t\t\tph[i+1] <= ph[i] + cordic_angle[i];\n"
326 | "\t\t\t\t// }}}\n"
327 | "\t\t\tend\n"
328 | "\t\t\t// }}}\n"
329 | "\t\tend\n"
330 | "\tend endgenerate\n\t// }}}\n\n");
331 | // }}}
332 |
333 | // Round the results (if necessary)
334 | // {{{
335 | if (working_width > ow+1) {
336 | fprintf(fp,
337 | "\t// Round our magnitude towards even\n"
338 | "\t// {{{\n"
339 | "\twire\t[(WW-1):0]\tpre_mag;\n\n"
340 | "\tassign\tpre_mag = xv[NSTAGES] + $signed({ {(OW){1\'b0}},\n"
341 | "\t\t\t\txv[NSTAGES][(WW-OW)],\n"
342 | "\t\t\t\t{(WW-OW-1){!xv[NSTAGES][WW-OW]}} });\n"
343 | "\n");
344 |
345 | fprintf(fp,
346 | "\tinitial\to_mag = 0;\n"
347 | "\tinitial\to_phase = 0;\n");
348 | if (with_aux)
349 | fprintf(fp, "\tinitial\to_aux = 0;\n");
350 | fprintf(fp, "%s", always_reset.c_str());
351 | if (with_reset) {
352 | fprintf(fp,
353 | "\tbegin\n"
354 | "\t\to_mag <= 0;\n"
355 | "\t\to_phase <= 0;\n");
356 | if (with_aux)
357 | fprintf(fp,
358 | "\t\to_aux <= 0;\n");
359 | fprintf(fp, "\tend else ");
360 | }
361 |
362 | fprintf(fp, "if (i_ce)\n"
363 | "\tbegin\n"
364 | "\t\to_mag <= pre_mag[(WW-1):(WW-OW)];\n"
365 | "\t\to_phase <= ph[NSTAGES];\n");
366 | if (with_aux)
367 | fprintf(fp,
368 | "\t\to_aux <= ax[NSTAGES];\n");
369 | fprintf(fp, "\tend\n\n");
370 |
371 | fprintf(fp, "\t// Make Verilator happy with pre_.val\n"
372 | "\t// verilator lint_off UNUSED\n"
373 | "\twire\tunused_val;\n"
374 | "\tassign\tunused_val = &{ 1\'b0, "
375 | " pre_mag[WW-1], pre_mag[(WW-OW-1):0] };\n"
376 | "\t// verilator lint_on UNUSED\n"
377 | "\t// }}}\n");
378 | } else {
379 | // No rounding required
380 | // {{{
381 | fprintf(fp,
382 | "\t// No rounding required\n"
383 | "\t// {{{\n"
384 | "\tinitial\to_mag = 0;\n"
385 | "\tinitial\to_phase = 0;\n");
386 | if (with_aux)
387 | fprintf(fp, "\tinitial\to_aux = 0;\n");
388 | fprintf(fp, "%s", always_reset.c_str());
389 |
390 | if (with_reset) {
391 | fprintf(fp, "\tbegin\n"
392 | "\t\to_mag <= 0;\n"
393 | "\t\to_phase <= 0;\n");
394 | if (with_aux)
395 | fprintf(fp, "\t\to_aux <= 0;\n");
396 | fprintf(fp, "\tend else ");
397 | }
398 |
399 | fprintf(fp, "if (i_ce)\n"
400 | "\tbegin\t// We accumulate a bit during our processing, so shift by one\n"
401 | "\t\to_mag <= xv[NSTAGES][(WW-1):(WW-OW)];\n"
402 | "\t\to_phase <= ph[NSTAGES];\n");
403 | if (with_aux)
404 | fprintf(fp, "\t\to_aux <= ax[NSTAGES];\n");
405 | fprintf(fp, "\tend\n\t// }}}\n");
406 | // }}}
407 | }
408 | // }}}
409 |
410 | fprintf(fp, "endmodule\n");
411 |
412 | if (NULL != fhp) {
413 | // {{{
414 | char *str = new char[strlen(name)+4], *ptr;
415 | sprintf(str, "%s.h", name);
416 | legal(fhp, str, PROJECT, HPURPOSE);
417 | ptr = str;
418 | while(*ptr) {
419 | if ('.' == *ptr)
420 | *ptr = '_';
421 | else *ptr = toupper(*ptr);
422 | ptr++;
423 | }
424 | fprintf(fhp, "#ifndef %s\n", str);
425 | fprintf(fhp, "#define %s\n", str);
426 | if (async_reset)
427 | fprintf(fhp, "#define\tASYNC_RESET\n");
428 | fprintf(fhp, "const int IW = %d;\n", iw);
429 | fprintf(fhp, "const int OW = %d;\n", ow);
430 | fprintf(fhp, "const int NEXTRA = %d;\n", nxtra);
431 | fprintf(fhp, "const int WW = %d;\n", working_width);
432 | fprintf(fhp, "const int PW = %d;\n", phase_bits);
433 | fprintf(fhp, "const int NSTAGES = %d;\n", nstages);
434 | fprintf(fhp, "const double\tQUANTIZATION_VARIANCE = %.16f; // (Units^2)\n",
435 | transform_quantization_variance(nstages,
436 | working_width-iw, working_width-ow));
437 | fprintf(fhp, "const double\tPHASE_VARIANCE_RAD = %.16f; // (Radians^2)\n",
438 | phase_variance(nstages, phase_bits));
439 | fprintf(fhp, "const double\tGAIN = %.16f;\n",
440 | cordic_gain(nstages) * sqrt(2.0) / 2.);
441 | fprintf(fhp, "const bool\tHAS_RESET = %s;\n", with_reset?"true":"false");
442 | fprintf(fhp, "const bool\tHAS_AUX = %s;\n", with_aux?"true":"false");
443 | if (with_reset)
444 | fprintf(fhp, "#define\tHAS_RESET_WIRE\n");
445 | if (with_aux)
446 | fprintf(fhp, "#define\tHAS_AUX_WIRES\n");
447 | fprintf(fhp, "#endif // %s\n", str);
448 |
449 | delete[] str;
450 | // }}}
451 | }
452 | }
453 |
--------------------------------------------------------------------------------
/sw/topolar.h:
--------------------------------------------------------------------------------
1 | ////////////////////////////////////////////////////////////////////////////////
2 | //
3 | // Filename: sw/topolar.h
4 | // {{{
5 | // Project: A series of CORDIC related projects
6 | //
7 | // Purpose:
8 | //
9 | // Creator: Dan Gisselquist, Ph.D.
10 | // Gisselquist Technology, LLC
11 | //
12 | ////////////////////////////////////////////////////////////////////////////////
13 | // }}}
14 | // Copyright (C) 2017-2024, Gisselquist Technology, LLC
15 | // {{{
16 | // This program is free software (firmware): you can redistribute it and/or
17 | // modify it under the terms of the GNU General Public License as published
18 | // by the Free Software Foundation, either version 3 of the License, or (at
19 | // your option) any later version.
20 | //
21 | // This program is distributed in the hope that it will be useful, but WITHOUT
22 | // ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
23 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 | // for more details.
25 | //
26 | // You should have received a copy of the GNU General Public License along
27 | // with this program. (It's in the $(ROOT)/doc directory. Run make with no
28 | // target there if the PDF file isn't present.) If not, see
29 | // for a copy.
30 | // }}}
31 | // License: GPL, v3, as defined and found on www.gnu.org,
32 | // {{{
33 | // http://www.gnu.org/licenses/gpl.html
34 | //
35 | //
36 | ////////////////////////////////////////////////////////////////////////////////
37 | //
38 | // }}}
39 | #ifndef TOPOLAR_H
40 | #define TOPOLAR_H
41 |
42 | #include
43 |
44 | extern void topolar(FILE *fp, FILE *fhp, const char *cmdline,
45 | const char *fname,
46 | int nstages, int iw, int ow, int nxtra,
47 | int phase_bits=32,
48 | bool with_reset=true, bool with_aux = true,
49 | bool async_reset = false);
50 |
51 | #endif // TOPOLAR_H
52 |
--------------------------------------------------------------------------------