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