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

Subversion Repositories dblclockfft

[/] [dblclockfft/] [trunk/] [sw/] [rounding.cpp] - Blame information for rev 37

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 36 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    rounding.cpp
4
//
5
// Project:     A General Purpose Pipelined FFT Implementation
6
//
7
// Purpose:     To create one of a series of modules to handle dropping bits
8
//              within the FFT implementation.
9
//
10
// Creator:     Dan Gisselquist, Ph.D.
11
//              Gisselquist Technology, LLC
12
//
13
////////////////////////////////////////////////////////////////////////////////
14
//
15
// Copyright (C) 2015-2018, 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 37 dgisselq
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
29 36 dgisselq
// target there if the PDF file isn't present.)  If not, see
30
// <http://www.gnu.org/licenses/> for a copy.
31
//
32
// License:     GPL, v3, as defined and found on www.gnu.org,
33
//              http://www.gnu.org/licenses/gpl.html
34
//
35
//
36
////////////////////////////////////////////////////////////////////////////////
37
//
38
//
39
#define _CRT_SECURE_NO_WARNINGS // ms vs 2012 doesn't like fopen
40
 
41
#include <stdio.h>
42
#include <stdlib.h>
43
 
44
#include <string.h>
45
#include <string>
46
#include <math.h>
47
#include <ctype.h>
48
#include <assert.h>
49
 
50
#include "legal.h"
51
#include "rounding.h"
52
 
53
#define SLASHLINE "////////////////////////////////////////////////////////////////////////////////\n"
54
 
55
 
56
void    build_truncator(const char *fname) {
57
        printf("TRUNCATING!\n");
58
        FILE    *fp = fopen(fname, "w");
59
        if (NULL == fp) {
60
                fprintf(stderr, "Could not open \'%s\' for writing\n", fname);
61
                perror("O/S Err was:");
62
                return;
63
        }
64
 
65
        fprintf(fp,
66
SLASHLINE
67
"//\n"
68
"// Filename:\ttruncate.v\n"
69
"//\n"
70
"// Project:\t%s\n"
71
"//\n"
72
"// Purpose:    Truncation is one of several options that can be used\n"
73
"//             internal to the various FFT stages to drop bits from one\n"
74
"//     stage to the next.  In general, it is the simplest method of dropping\n"
75
"//     bits, since it requires only a bit selection.\n"
76
"//\n"
77
"//     This form of rounding isn\'t really that great for FFT\'s, since it\n"
78
"//     tends to produce a DC bias in the result.  (Other less pronounced\n"
79
"//     biases may also exist.)\n"
80
"//\n"
81
"//     This particular version also registers the output with the clock, so\n"
82
"//     there will be a delay of one going through this module.  This will\n"
83
"//     keep it in line with the other forms of rounding that can be used.\n"
84
"//\n"
85
"//\n%s"
86
"//\n",
87
                prjname, creator);
88
 
89
        fprintf(fp, "%s", cpyleft);
90
        fprintf(fp, "//\n//\n`default_nettype\tnone\n//\n");
91
        fprintf(fp,
92
"module truncate(i_clk, i_ce, i_val, o_val);\n"
93
        "\tparameter\tIWID=16, OWID=8, SHIFT=0;\n"
94 37 dgisselq
        "\tinput\twire\t\t\t\ti_clk, i_ce;\n"
95
        "\tinput\twire\tsigned\t[(IWID-1):0]\ti_val;\n"
96 36 dgisselq
        "\toutput\treg\tsigned\t[(OWID-1):0]\to_val;\n"
97
"\n"
98
        "\talways @(posedge i_clk)\n"
99
                "\t\tif (i_ce)\n"
100
                "\t\t\to_val <= i_val[(IWID-1-SHIFT):(IWID-SHIFT-OWID)];\n"
101
"\n"
102
"endmodule\n");
103
}
104
 
105
void    build_roundhalfup(const char *fname) {
106
        FILE    *fp = fopen(fname, "w");
107
        if (NULL == fp) {
108
                fprintf(stderr, "Could not open \'%s\' for writing\n", fname);
109
                perror("O/S Err was:");
110
                return;
111
        }
112
 
113
        fprintf(fp,
114
SLASHLINE
115
"//\n"
116
"// Filename:\troundhalfup.v\n"
117
"//\n"
118
"// Project:\t%s\n"
119
"//\n"
120
"// Purpose:\tRounding half up is the way I was always taught to round in\n"
121
"//             school.  A one half value is added to the result, and then\n"
122
"//     the result is truncated.  When used in an FFT, this produces less\n"
123
"//     bias than the truncation method, although a bias still tends to\n"
124
"//     remain.\n"
125
"//\n"
126
"//\n%s"
127
"//\n",
128
                prjname, creator);
129
 
130
        fprintf(fp, "%s", cpyleft);
131
        fprintf(fp, "//\n//\n`default_nettype\tnone\n//\n");
132
        fprintf(fp,
133
"module roundhalfup(i_clk, i_ce, i_val, o_val);\n"
134
        "\tparameter\tIWID=16, OWID=8, SHIFT=0;\n"
135 37 dgisselq
        "\tinput\twire\t\t\t\ti_clk, i_ce;\n"
136
        "\tinput\twire\tsigned\t[(IWID-1):0]\ti_val;\n"
137 36 dgisselq
        "\toutput\treg\tsigned\t[(OWID-1):0]\to_val;\n"
138
"\n"
139
        "\t// Let's deal with two cases to be as general as we can be here\n"
140
        "\t//\n"
141
        "\t//   1. The desired output would lose no bits at all\n"
142
        "\t//   2. One or more bits would be dropped, so the rounding is simply\n"
143
        "\t//\t\ta matter of adding one to the bit about to be dropped,\n"
144
        "\t//\t\tmoving all halfway and above numbers up to the next\n"
145
        "\t//\t\tvalue.\n"
146
        "\tgenerate\n"
147
        "\tif (IWID-SHIFT == OWID)\n"
148
        "\tbegin // No truncation or rounding, output drops no bits\n"
149
"\n"
150
                "\t\talways @(posedge i_clk)\n"
151
                        "\t\t\tif (i_ce)\to_val <= i_val[(IWID-SHIFT-1):0];\n"
152
"\n"
153
        "\tend else // if (IWID-SHIFT-1 >= OWID)\n"
154
        "\tbegin // Output drops one bit, can only add one or ... not.\n"
155
                "\t\twire\t[(OWID-1):0] truncated_value, rounded_up;\n"
156
                "\t\twire\t\t\tlast_valid_bit, first_lost_bit;\n"
157
                "\t\tassign\ttruncated_value=i_val[(IWID-1-SHIFT):(IWID-SHIFT-OWID)];\n"
158
                "\t\tassign\trounded_up=truncated_value + {{(OWID-1){1\'b0}}, 1\'b1 };\n"
159
                "\t\tassign\tfirst_lost_bit = i_val[(IWID-SHIFT-OWID-1)];\n"
160
"\n"
161
                "\t\talways @(posedge i_clk)\n"
162
                "\t\t\tif (i_ce)\n"
163
                "\t\t\tbegin\n"
164
                        "\t\t\t\tif (!first_lost_bit) // Round down / truncate\n"
165
                        "\t\t\t\t\to_val <= truncated_value;\n"
166
                        "\t\t\t\telse\n"
167
                        "\t\t\t\t\to_val <= rounded_up; // even value\n"
168
                "\t\t\tend\n"
169
"\n"
170
        "\tend\n"
171
        "\tendgenerate\n"
172
"\n"
173
"endmodule\n");
174
}
175
 
176
void    build_roundfromzero(const char *fname) {
177
        FILE    *fp = fopen(fname, "w");
178
        if (NULL == fp) {
179
                fprintf(stderr, "Could not open \'%s\' for writing\n", fname);
180
                perror("O/S Err was:");
181
                return;
182
        }
183
 
184
        fprintf(fp,
185
SLASHLINE
186
"//\n"
187
"// Filename:\troundfromzero.v\n"
188
"//\n"
189
"// Project:    %s\n"
190
"//\n"
191
"// Purpose:    Truncation is one of several options that can be used\n"
192
"//             internal to the various FFT stages to drop bits from one\n"
193
"//     stage to the next.  In general, it is the simplest method of dropping\n"
194
"//     bits, since it requires only a bit selection.\n"
195
"//\n"
196
"//     This form of rounding isn\'t really that great for FFT\'s, since it\n"
197
"//     tends to produce a DC bias in the result.  (Other less pronounced\n"
198
"//     biases may also exist.)\n"
199
"//\n"
200
"//     This particular version also registers the output with the clock, so\n"
201
"//     clock, so there will be a delay of one going through this module.\n"
202
"//     This will keep it in line with the other forms of rounding that can\n"
203
"//     be used.\n"
204
"//\n"
205
"//\n%s"
206
"//\n",
207
                prjname, creator);
208
 
209
        fprintf(fp, "%s", cpyleft);
210
        fprintf(fp, "//\n//\n`default_nettype\tnone\n//\n");
211
        fprintf(fp,
212
"module roundfromzero(i_clk, i_ce, i_val, o_val);\n"
213
        "\tparameter\tIWID=16, OWID=8, SHIFT=0;\n"
214 37 dgisselq
        "\tinput\twire\t\t\t\ti_clk, i_ce;\n"
215
        "\tinput\twire\tsigned\t[(IWID-1):0]\ti_val;\n"
216 36 dgisselq
        "\toutput\treg\tsigned\t[(OWID-1):0]\to_val;\n"
217
"\n"
218
        "\t// Let's deal with three cases to be as general as we can be here\n"
219
        "\t//\n"
220
        "\t//\t1. The desired output would lose no bits at all\n"
221
        "\t//\t2. One bit would be dropped, so the rounding is simply\n"
222
        "\t//\t\tadjusting the value to be the closer to zero in\n"
223
        "\t//\t\tcases of being halfway between two.  If identically\n"
224
        "\t//\t\tequal to a number, we just leave it as is.\n"
225
        "\t//\t3. Two or more bits would be dropped.  In this case, we round\n"
226
        "\t//\t\tnormally unless we are rounding a value of exactly\n"
227
        "\t//\t\thalfway between the two.  In the halfway case, we\n"
228
        "\t//\t\tround away from zero.\n"
229
        "\tgenerate\n"
230
        "\tif (IWID == OWID) // In this case, the shift is irrelevant and\n"
231
        "\tbegin // cannot be applied.  No truncation or rounding takes\n"
232
        "\t// effect here.\n"
233
"\n"
234
                "\t\talways @(posedge i_clk)\n"
235
                        "\t\t\tif (i_ce)\to_val <= i_val[(IWID-1):0];\n"
236
"\n"
237
        "\tend else if (IWID-SHIFT == OWID)\n"
238
        "\tbegin // No truncation or rounding, output drops no bits\n"
239
"\n"
240
                "\t\talways @(posedge i_clk)\n"
241
                        "\t\t\tif (i_ce)\to_val <= i_val[(IWID-SHIFT-1):0];\n"
242
"\n"
243
        "\tend else if (IWID-SHIFT-1 == OWID)\n"
244
        "\tbegin // Output drops one bit, can only add one or ... not.\n"
245
        "\t\twire\t[(OWID-1):0]\ttruncated_value, rounded_up;\n"
246
        "\t\twire\t\t\tsign_bit, first_lost_bit;\n"
247
        "\t\tassign\ttruncated_value=i_val[(IWID-1-SHIFT):(IWID-SHIFT-OWID)];\n"
248
        "\t\tassign\trounded_up=truncated_value + {{(OWID-1){1\'b0}}, 1\'b1 };\n"
249
        "\t\tassign\tfirst_lost_bit = i_val[0];\n"
250
        "\t\tassign\tsign_bit = i_val[(IWID-1)];\n"
251
"\n"
252
        "\t\talways @(posedge i_clk)\n"
253
                "\t\t\tif (i_ce)\n"
254
                "\t\t\tbegin\n"
255
                        "\t\t\t\tif (!first_lost_bit) // Round down / truncate\n"
256
                                "\t\t\t\t\to_val <= truncated_value;\n"
257
                        "\t\t\t\telse if (sign_bit)\n"
258
                                "\t\t\t\t\to_val <= truncated_value;\n"
259
                        "\t\t\t\telse\n"
260
                                "\t\t\t\t\to_val <= rounded_up;\n"
261
                "\t\t\tend\n"
262
"\n"
263
        "\tend else // If there's more than one bit we are dropping\n"
264
        "\tbegin\n"
265
                "\t\twire\t[(OWID-1):0]\ttruncated_value, rounded_up;\n"
266
                "\t\twire\t\t\tsign_bit, first_lost_bit;\n"
267
                "\t\tassign\ttruncated_value=i_val[(IWID-1-SHIFT):(IWID-SHIFT-OWID)];\n"
268
                "\t\tassign\trounded_up=truncated_value + {{(OWID-1){1\'b0}}, 1\'b1 };\n"
269
                "\t\tassign\tfirst_lost_bit = i_val[(IWID-SHIFT-OWID-1)];\n"
270
                "\t\tassign\tsign_bit = i_val[(IWID-1)];\n"
271
"\n"
272
                "\t\twire\t[(IWID-SHIFT-OWID-2):0]\tother_lost_bits;\n"
273
                "\t\tassign\tother_lost_bits = i_val[(IWID-SHIFT-OWID-2):0];\n"
274
"\n"
275
                "\t\talways @(posedge i_clk)\n"
276
                        "\t\t\tif (i_ce)\n"
277
                        "\t\t\tbegin\n"
278
                        "\t\t\t\tif (!first_lost_bit) // Round down / truncate\n"
279
                                "\t\t\t\t\to_val <= truncated_value;\n"
280
                        "\t\t\t\telse if (|other_lost_bits) // Round up to\n"
281
                                "\t\t\t\t\to_val <= rounded_up; // closest value\n"
282
                        "\t\t\t\telse if (sign_bit)\n"
283
                                "\t\t\t\t\to_val <= truncated_value;\n"
284
                        "\t\t\t\telse\n"
285
                                "\t\t\t\t\to_val <= rounded_up;\n"
286
                        "\t\t\tend\n"
287
        "\tend\n"
288
        "\tendgenerate\n"
289
"\n"
290
"endmodule\n");
291
}
292
 
293
void    build_convround(const char *fname) {
294
        FILE    *fp = fopen(fname, "w");
295
        if (NULL == fp) {
296
                fprintf(stderr, "Could not open \'%s\' for writing\n", fname);
297
                perror("O/S Err was:");
298
                return;
299
        }
300
 
301
        fprintf(fp,
302
SLASHLINE
303
"//\n"
304
"// Filename:   convround.v\n"
305
"//\n"
306
"// Project:    %s\n"
307
"//\n"
308
"// Purpose:    A convergent rounding routine, also known as banker\'s\n"
309
"//             rounding, Dutch rounding, Gaussian rounding, unbiased\n"
310
"//     rounding, or ... more, at least according to Wikipedia.\n"
311
"//\n"
312
"//     This form of rounding works by rounding, when the direction is in\n"
313
"//     question, towards the nearest even value.\n"
314
"//\n"
315
"//\n%s"
316
"//\n",
317
                prjname, creator);
318
 
319
        fprintf(fp, "%s", cpyleft);
320
        fprintf(fp, "//\n//\n`default_nettype\tnone\n//\n");
321
        fprintf(fp,
322
"module convround(i_clk, i_ce, i_val, o_val);\n"
323
"\tparameter\tIWID=16, OWID=8, SHIFT=0;\n"
324 37 dgisselq
"\tinput\twire\t\t\t\ti_clk, i_ce;\n"
325
"\tinput\twire\tsigned\t[(IWID-1):0]\ti_val;\n"
326 36 dgisselq
"\toutput\treg\tsigned\t[(OWID-1):0]\to_val;\n"
327
"\n"
328
"\t// Let's deal with three cases to be as general as we can be here\n"
329
"\t//\n"
330
"\t//\t1. The desired output would lose no bits at all\n"
331
"\t//\t2. One bit would be dropped, so the rounding is simply\n"
332
"\t//\t\tadjusting the value to be the nearest even number in\n"
333
"\t//\t\tcases of being halfway between two.  If identically\n"
334
"\t//\t\tequal to a number, we just leave it as is.\n"
335
"\t//\t3. Two or more bits would be dropped.  In this case, we round\n"
336
"\t//\t\tnormally unless we are rounding a value of exactly\n"
337
"\t//\t\thalfway between the two.  In the halfway case we round\n"
338
"\t//\t\tto the nearest even number.\n"
339
"\tgenerate\n"
340
// What if IWID < OWID?  We should expand here ... somehow
341
        "\tif (IWID == OWID) // In this case, the shift is irrelevant and\n"
342
        "\tbegin // cannot be applied.  No truncation or rounding takes\n"
343
        "\t// effect here.\n"
344
"\n"
345
                "\t\talways @(posedge i_clk)\n"
346
                        "\t\t\tif (i_ce)\to_val <= i_val[(IWID-1):0];\n"
347
"\n"
348
// What if IWID-SHIFT < OWID?  Shouldn't we also shift here as well?
349
"\tend else if (IWID-SHIFT == OWID)\n"
350
"\tbegin // No truncation or rounding, output drops no bits\n"
351
"\n"
352
"\t\talways @(posedge i_clk)\n"
353
"\t\t\tif (i_ce)\to_val <= i_val[(IWID-SHIFT-1):0];\n"
354
"\n"
355
"\tend else if (IWID-SHIFT-1 == OWID)\n"
356
// Is there any way to limit the number of bits that are examined here, for the
357
// purpose of simplifying/reducing logic?  I mean, if we go from 32 to 16 bits,
358
// must we check all 15 bits for equality to zero?
359
"\tbegin // Output drops one bit, can only add one or ... not.\n"
360
"\t\twire\t[(OWID-1):0] truncated_value, rounded_up;\n"
361
"\t\twire\t\t\tlast_valid_bit, first_lost_bit;\n"
362
"\t\tassign\ttruncated_value=i_val[(IWID-1-SHIFT):(IWID-SHIFT-OWID)];\n"
363
"\t\tassign\trounded_up=truncated_value + {{(OWID-1){1\'b0}}, 1\'b1 };\n"
364
"\t\tassign\tlast_valid_bit = truncated_value[0];\n"
365
"\t\tassign\tfirst_lost_bit = i_val[0];\n"
366
"\n"
367
"\t\talways @(posedge i_clk)\n"
368
"\t\t\tif (i_ce)\n"
369
"\t\t\tbegin\n"
370
"\t\t\t\tif (!first_lost_bit) // Round down / truncate\n"
371
"\t\t\t\t\to_val <= truncated_value;\n"
372
"\t\t\t\telse if (last_valid_bit)// Round up to nearest\n"
373
"\t\t\t\t\to_val <= rounded_up; // even value\n"
374
"\t\t\t\telse // else round down to the nearest\n"
375
"\t\t\t\t\to_val <= truncated_value; // even value\n"
376
"\t\t\tend\n"
377
"\n"
378
"\tend else // If there's more than one bit we are dropping\n"
379
"\tbegin\n"
380
"\t\twire\t[(OWID-1):0] truncated_value, rounded_up;\n"
381
"\t\twire\t\t\tlast_valid_bit, first_lost_bit;\n"
382
"\t\tassign\ttruncated_value=i_val[(IWID-1-SHIFT):(IWID-SHIFT-OWID)];\n"
383
"\t\tassign\trounded_up=truncated_value + {{(OWID-1){1\'b0}}, 1\'b1 };\n"
384
"\t\tassign\tlast_valid_bit = truncated_value[0];\n"
385
"\t\tassign\tfirst_lost_bit = i_val[(IWID-SHIFT-OWID-1)];\n"
386
"\n"
387
"\t\twire\t[(IWID-SHIFT-OWID-2):0]\tother_lost_bits;\n"
388
"\t\tassign\tother_lost_bits = i_val[(IWID-SHIFT-OWID-2):0];\n"
389
"\n"
390
"\t\talways @(posedge i_clk)\n"
391
"\t\t\tif (i_ce)\n"
392
"\t\t\tbegin\n"
393
"\t\t\t\tif (!first_lost_bit) // Round down / truncate\n"
394
"\t\t\t\t\to_val <= truncated_value;\n"
395
"\t\t\t\telse if (|other_lost_bits) // Round up to\n"
396
"\t\t\t\t\to_val <= rounded_up; // closest value\n"
397
"\t\t\t\telse if (last_valid_bit) // Round up to\n"
398
"\t\t\t\t\to_val <= rounded_up; // nearest even\n"
399
"\t\t\t\telse   // else round down to nearest even\n"
400
"\t\t\t\t\to_val <= truncated_value;\n"
401
"\t\t\tend\n"
402
"\tend\n"
403
"\tendgenerate\n"
404
"\n"
405
"endmodule\n");
406
}
407
 

powered by: WebSVN 2.1.0

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