Line 1... |
Line 1... |
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Filename: fftgen.v
|
// Filename: fftgen.cpp
|
//
|
//
|
// Project: A Doubletime Pipelined FFT
|
// Project: A Doubletime Pipelined FFT
|
//
|
//
|
// Purpose: This is the core generator for the project. Every part
|
// Purpose: This is the core generator for the project. Every part
|
// and piece of this project begins and ends in this program.
|
// and piece of this project begins and ends in this program.
|
Line 357... |
Line 357... |
"\n"
|
"\n"
|
"endmodule\n");
|
"endmodule\n");
|
}
|
}
|
|
|
void build_convround(const char *fname) {
|
void build_convround(const char *fname) {
|
printf("CONVERGENT--ROUNDING!\n");
|
|
FILE *fp = fopen(fname, "w");
|
FILE *fp = fopen(fname, "w");
|
if (NULL == fp) {
|
if (NULL == fp) {
|
fprintf(stderr, "Could not open \'%s\' for writing\n", fname);
|
fprintf(stderr, "Could not open \'%s\' for writing\n", fname);
|
perror("O/S Err was:");
|
perror("O/S Err was:");
|
return;
|
return;
|
Line 1324... |
Line 1323... |
"\t\t\t// Second clock, round and latch for final clock\n"
|
"\t\t\t// Second clock, round and latch for final clock\n"
|
"\t\t\tb_right_r <= rnd_right_r;\n"
|
"\t\t\tb_right_r <= rnd_right_r;\n"
|
"\t\t\tb_right_i <= rnd_right_i;\n"
|
"\t\t\tb_right_i <= rnd_right_i;\n"
|
"\t\t\tb_left_r <= rnd_left_r;\n"
|
"\t\t\tb_left_r <= rnd_left_r;\n"
|
"\t\t\tb_left_i <= rnd_left_i;\n"
|
"\t\t\tb_left_i <= rnd_left_i;\n"
|
|
"\t\tend\n"
|
|
"\n");
|
|
fprintf(fp,
|
|
"\talways @(posedge i_clk)\n"
|
|
"\t\tif (i_rst)\n"
|
|
"\t\t\to_aux <= 1\'b0;\n"
|
|
"\t\telse if (i_ce)\n"
|
|
"\t\tbegin\n"
|
|
"\t\t\t// Second clock, latch for final clock\n"
|
"\t\t\to_aux <= aux & ovalid;\n"
|
"\t\t\to_aux <= aux & ovalid;\n"
|
"\t\tend\n"
|
"\t\tend\n"
|
"\n");
|
"\n");
|
|
|
fprintf(fp,
|
fprintf(fp,
|
"\t// As a final step, we pack our outputs into two packed two\'s\n"
|
"\t// As a final step, we pack our outputs into two packed two\'s\n"
|
"\t// complement numbers per output word, so that each output word\n"
|
"\t// complement numbers per output word, so that each output word\n"
|
"\t// has (2*OWIDTH) bits in it, with the top half being the real\n"
|
"\t// has (2*OWIDTH) bits in it, with the top half being the real\n"
|
"\t// portion and the bottom half being the imaginary portion.\n"
|
"\t// portion and the bottom half being the imaginary portion.\n"
|
Line 1482... |
Line 1491... |
"\t// multiply. Here, we recover them. During the multiply,\n"
|
"\t// multiply. Here, we recover them. During the multiply,\n"
|
"\t// values were multiplied by 2^(CWIDTH-2)*exp{-j*2*pi*...},\n"
|
"\t// values were multiplied by 2^(CWIDTH-2)*exp{-j*2*pi*...},\n"
|
"\t// therefore, the left_x values need to be right shifted by\n"
|
"\t// therefore, the left_x values need to be right shifted by\n"
|
"\t// CWIDTH-2 as well. The additional bits come from a sign\n"
|
"\t// CWIDTH-2 as well. The additional bits come from a sign\n"
|
"\t// extension.\n"
|
"\t// extension.\n"
|
"\twire\taux_s, aux_ss;\n"
|
"\twire\taux_s;\n"
|
"\twire\tsigned\t[(IWIDTH+CWIDTH):0] left_si, left_sr;\n"
|
"\twire\tsigned\t[(IWIDTH+CWIDTH):0] left_si, left_sr;\n"
|
"\treg\t\t[(2*IWIDTH+2):0] left_saved;\n"
|
"\treg\t\t[(2*IWIDTH+2):0] left_saved;\n"
|
"\tassign\tleft_sr = { {2{left_saved[2*(IWIDTH+1)-1]}}, left_saved[(2*(IWIDTH+1)-1):(IWIDTH+1)], {(CWIDTH-2){1'b0}} };\n"
|
"\tassign\tleft_sr = { {2{left_saved[2*(IWIDTH+1)-1]}}, left_saved[(2*(IWIDTH+1)-1):(IWIDTH+1)], {(CWIDTH-2){1'b0}} };\n"
|
"\tassign\tleft_si = { {2{left_saved[(IWIDTH+1)-1]}}, left_saved[((IWIDTH+1)-1):0], {(CWIDTH-2){1'b0}} };\n"
|
"\tassign\tleft_si = { {2{left_saved[(IWIDTH+1)-1]}}, left_saved[((IWIDTH+1)-1):0], {(CWIDTH-2){1'b0}} };\n"
|
"\tassign\taux_s = left_saved[2*IWIDTH+2];\n"
|
"\tassign\taux_s = left_saved[2*IWIDTH+2];\n"
|
Line 1609... |
Line 1618... |
"\n"
|
"\n"
|
"\t// %scmem is defined as an array of real and complex values,\n"
|
"\t// %scmem is defined as an array of real and complex values,\n"
|
"\t// where the top CWIDTH bits are the real value and the bottom\n"
|
"\t// where the top CWIDTH bits are the real value and the bottom\n"
|
"\t// CWIDTH bits are the imaginary value.\n"
|
"\t// CWIDTH bits are the imaginary value.\n"
|
"\t//\n"
|
"\t//\n"
|
"\t// cmem[i] = { (2^(CWIDTH-2)) * cos(2*pi*i/(2^LGWIDTH)),\n"
|
"\t// %scmem[i] = { (2^(CWIDTH-2)) * cos(2*pi*i/(2^LGWIDTH)),\n"
|
"\t// (2^(CWIDTH-2)) * sin(2*pi*i/(2^LGWIDTH)) };\n"
|
"\t// (2^(CWIDTH-2)) * sin(2*pi*i/(2^LGWIDTH)) };\n"
|
"\t//\n"
|
"\t//\n"
|
"\treg [(2*CWIDTH-1):0] %scmem [0:((1<<LGSPAN)-1)];\n"
|
"\treg [(2*CWIDTH-1):0] %scmem [0:((1<<LGSPAN)-1)];\n"
|
"\tinitial\t$readmemh(\"%scmem_%c%d.hex\",%scmem);\n\n",
|
"\tinitial\t$readmemh(\"%scmem_%c%d.hex\",%scmem);\n\n",
|
(inv)?"i":"", (inv)?"i":"",
|
(inv)?"i":"", (inv)?"i":"", (inv)?"i":"",
|
(inv)?"i":"", (odd)?'o':'e',stage<<1,
|
(inv)?"i":"", (odd)?'o':'e',stage<<1, (inv)?"i":"");
|
(inv)?"i":"");
|
|
{
|
{
|
FILE *cmem;
|
FILE *cmem;
|
|
|
{
|
{
|
char *memfile, *ptr;
|
char *memfile, *ptr;
|
Line 1695... |
Line 1703... |
fprintf(fstage,
|
fprintf(fstage,
|
"\t//\n"
|
"\t//\n"
|
"\t// Now, we have all the inputs, so let\'s feed the butterfly\n"
|
"\t// Now, we have all the inputs, so let\'s feed the butterfly\n"
|
"\t//\n"
|
"\t//\n"
|
"\talways\t@(posedge i_clk)\n"
|
"\talways\t@(posedge i_clk)\n"
|
|
"\tif (i_rst)\n"
|
|
"\t\tib_sync <= 1\'b0;\n"
|
|
"\telse if ((i_ce)&&(iaddr[LGSPAN]))\n"
|
|
"\t\tbegin\n"
|
|
"\t\t\t// Set the sync to true on the very first\n"
|
|
"\t\t\t// valid input in, and hence on the very\n"
|
|
"\t\t\t// first valid data out per FFT.\n"
|
|
"\t\t\tib_sync <= (iaddr==(1<<(LGSPAN)));\n"
|
|
"\t\tend\n"
|
|
"\talways\t@(posedge i_clk)\n"
|
"\tif ((i_ce)&&(iaddr[LGSPAN]))\n"
|
"\tif ((i_ce)&&(iaddr[LGSPAN]))\n"
|
"\t\tbegin\n"
|
"\t\tbegin\n"
|
"\t\t\t// One input from memory, ...\n"
|
"\t\t\t// One input from memory, ...\n"
|
"\t\t\tib_a <= imem[iaddr[(LGSPAN-1):0]];\n"
|
"\t\t\tib_a <= imem[iaddr[(LGSPAN-1):0]];\n"
|
"\t\t\t// One input clocked in from the top\n"
|
"\t\t\t// One input clocked in from the top\n"
|
"\t\t\tib_b <= i_data;\n"
|
"\t\t\tib_b <= i_data;\n"
|
"\t\t\t// Set the sync to true on the very first\n"
|
|
"\t\t\t// valid input in, and hence on the very\n"
|
|
"\t\t\t// first valid data out per FFT.\n"
|
|
"\t\t\tib_sync <= (iaddr==(1<<(LGSPAN)));\n"
|
|
"\t\t\tib_c <= %scmem[iaddr[(LGSPAN-1):0]];\n"
|
"\t\t\tib_c <= %scmem[iaddr[(LGSPAN-1):0]];\n"
|
"\t\tend\n\n", (inv)?"i":"");
|
"\t\tend\n\n", (inv)?"i":"");
|
|
|
if (hwmpy) {
|
if (hwmpy) {
|
fprintf(fstage,
|
fprintf(fstage,
|
Line 1765... |
Line 1779... |
"\t\tlonger than the corresponding data bits, to help avoid\n"
|
"\t\tlonger than the corresponding data bits, to help avoid\n"
|
"\t\tcoefficient truncation errors.\n"
|
"\t\tcoefficient truncation errors.\n"
|
"\t-d <dir>\tPlaces all of the generated verilog files into <dir>.\n"
|
"\t-d <dir>\tPlaces all of the generated verilog files into <dir>.\n"
|
"\t-f <size>\tSets the size of the FFT as the number of complex\n"
|
"\t-f <size>\tSets the size of the FFT as the number of complex\n"
|
"\t\tsamples input to the transform.\n"
|
"\t\tsamples input to the transform.\n"
|
"\t-n <nbits>\tSets the number of bits in the twos complement input\n"
|
|
"\t\tto the FFT routine.\n"
|
|
"\t-m <mxbits>\tSets the maximum bit width that the FFT should ever\n"
|
"\t-m <mxbits>\tSets the maximum bit width that the FFT should ever\n"
|
"\t\tproduce. Internal values greater than this value will be\n"
|
"\t\tproduce. Internal values greater than this value will be\n"
|
"\t\ttruncated to this value.\n"
|
"\t\ttruncated to this value.\n"
|
"\t-n <nbits>\tSets the bitwidth for values coming into the (i)FFT.\n"
|
"\t-n <nbits>\tSets the bitwidth for values coming into the (i)FFT.\n"
|
"\t-p <nmpy>\tSets the number of stages that will use any hardware \n"
|
"\t-p <nmpy>\tSets the number of stages that will use any hardware \n"
|
Line 1791... |
Line 1803... |
"\t\tgiven by e^{ j 2 pi k/N n }.\n");
|
"\t\tgiven by e^{ j 2 pi k/N n }.\n");
|
}
|
}
|
|
|
// Features still needed:
|
// Features still needed:
|
// Interactivity.
|
// Interactivity.
|
// Some number of maximum bits, beyond which we won't accumulate any more.
|
|
// Obviously, the build_stage above.
|
|
// Copying the files of interest into the fft-core directory, from
|
|
// whatever directory this file is run out of.
|
|
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
int fftsize = -1, lgsize = -1;
|
int fftsize = -1, lgsize = -1;
|
int nbitsin = 16, xtracbits = 4, nummpy=0, nonmpy=2;
|
int nbitsin = 16, xtracbits = 4, nummpy=0, nonmpy=2;
|
int nbitsout, maxbitsout = -1, xtrapbits=0;
|
int nbitsout, maxbitsout = -1, xtrapbits=0;
|
bool bitreverse = true, inverse=false, interactive = false,
|
bool bitreverse = true, inverse=false, interactive = false,
|