OpenCores
URL https://opencores.org/ocsvn/dblclockfft/dblclockfft/trunk

Subversion Repositories dblclockfft

[/] [dblclockfft/] [trunk/] [sw/] [fftlib.cpp] - Rev 37

Compare with Previous | Blame | View Log

////////////////////////////////////////////////////////////////////////////////
//
// Filename: 	fftlib.cpp
//
// Project:	A General Purpose Pipelined FFT Implementation
//
// Purpose:	
//
// Creator:	Dan Gisselquist, Ph.D.
//		Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2018, Gisselquist Technology, LLC
//
// This program is free software (firmware): you can redistribute it and/or
// modify it under the terms of  the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
// target there if the PDF file isn't present.)  If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License:	GPL, v3, as defined and found on www.gnu.org,
//		http://www.gnu.org/licenses/gpl.html
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
#define _CRT_SECURE_NO_WARNINGS   //  ms vs 2012 doesn't like fopen
#include <stdio.h>
#include <stdlib.h>
 
#ifdef _MSC_VER //  added for ms vs compatibility
 
#include <io.h>
#include <direct.h>
#define _USE_MATH_DEFINES
 
#if _MSC_VER <= 1700
 
long long llround(double d) {
	if (d<0) return -(long long)(-d+0.5);
	else	return (long long)(d+0.5); }
 
#endif
 
#else
// And for G++/Linux environment
 
#include <unistd.h>	// Defines the R_OK/W_OK/etc. macros
#endif
 
#include <string.h>
#include <string>
#include <math.h>
// #include <ctype.h>
#include <assert.h>
 
#include "fftlib.h"
 
 
int	lgval(int vl) {
	int	lg;
 
	for(lg=1; (1<<lg) < vl; lg++)
		;
	return lg;
}
 
int	nextlg(int vl) {
	int	r;
 
	for(r=1; r<vl; r<<=1)
		;
	return r;
}
 
int	bflydelay(int nbits, int xtra) {
	int	cbits = nbits + xtra;
	int	delay;
 
	if (USE_OLD_MULTIPLY) {
		if (nbits+1<cbits)
			delay = nbits+4;
		else
			delay = cbits+3;
	} else {
		int	na=nbits+2, nb=cbits+1;
		if (nb<na) {
			int tmp = nb;
			nb = na; na = tmp;
		} delay = ((na)/2+(na&1)+2);
	}
	return delay;
}
 
int	lgdelay(int nbits, int xtra) {
	// The butterfly code needs to compare a valid address, of this
	// many bits, with an address two greater.  This guarantees we
	// have enough bits for that comparison.  We'll also end up with
	// more storage space to look for these values, but without a
	// redesign that's just what we'll deal with.
	return lgval(bflydelay(nbits, xtra)+3);
}
 
void	gen_coeffs(FILE *cmem, int stage, int cbits,
			int nwide, int offset, bool inv) {
	//
	// For an FFT stage of 2^n elements, we need 2^(n-1) butterfly
	// coefficients, sometimes called twiddle factors.  Stage captures the
	// width of the FFT at this point.  If thiss is a 2x at a time FFT,
	// nwide will be equal to 2, and offset will be one or two.
	//
	// assert(nwide > 0);
	// assert(offset < nwide);
	// assert(stage / nwide >  1);
	// assert(stage % nwide == 0);
	// printf("GEN-COEFFS(): stage =%4d, bits =%2d, nwide = %d, offset = %d, nverse = %d\n", stage, cbits, nwide, offset, inv);
	int	ncoeffs = stage/nwide/2;
	for(int i=0; i<ncoeffs; i++) {
		int k = nwide*i+offset;
		double	W = ((inv)?1:-1)*2.0*M_PI*k/(double)(stage);
		double	c, s;
		long long ic, is, vl;
 
		c = cos(W); s = sin(W);
		ic = (long long)llround((1ll<<(cbits-2)) * c);
		is = (long long)llround((1ll<<(cbits-2)) * s);
		vl = (ic & (~(-1ll << (cbits))));
		vl <<= (cbits);
		vl |= (is & (~(-1ll << (cbits))));
		fprintf(cmem, "%0*llx\n", ((cbits*2+3)/4), vl);
		//
	} fclose(cmem);
}
 
std::string	gen_coeff_fname(const char *coredir,
			int stage, int nwide, int offset, bool inv) {
	std::string	result;
	char	*memfile;
 
	assert((nwide == 1)||(nwide == 2));
 
	memfile = new char[strlen(coredir)+3+10+strlen(".hex")+64];
	if (nwide == 2) {
		if (coredir[0] == '\0') {
			sprintf(memfile, "%scmem_%c%d.hex",
				(inv)?"i":"", (offset==1)?'o':'e', stage*nwide);
		} else {
			sprintf(memfile, "%s/%scmem_%c%d.hex",
				coredir, (inv)?"i":"",
				(offset==1)?'o':'e', stage*nwide);
		}
	} else if (coredir[0] == '\0') // if (nwide == 1)
		sprintf(memfile, "%scmem_%d.hex",
			(inv)?"i":"", stage);
	else
		sprintf(memfile, "%s/%scmem_%d.hex",
			coredir, (inv)?"i":"", stage);
 
	result = std::string(memfile);
	delete[] memfile;
	return	result;
}
 
FILE	*gen_coeff_open(const char *fname) {
	FILE	*cmem;
 
	cmem = fopen(fname, "w");
	if (NULL == cmem) {
		fprintf(stderr, "Could not open FFT coefficient file "
				"\'%s\' for writing\n", fname);
		perror("Err from O/S:");
		exit(EXIT_FAILURE);
	}
 
	return cmem;
}
 
void	gen_coeff_file(const char *coredir, const char *fname,
			int stage, int cbits, int nwide, int offset, bool inv) {
	std::string	fstr;
	FILE	*cmem;
 
	fstr= gen_coeff_fname(coredir, stage, nwide, offset, inv);
	cmem = gen_coeff_open(fstr.c_str());
	gen_coeffs(cmem, stage,  cbits, nwide, offset, inv);
}
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.