Add LICENSE
[riscv-tests.git] / benchmarks / vec-cmplxmult / vec_cmplxmult_main.c
1 // See LICENSE for license details.
2
3 //**************************************************************************
4 // Vector-Thread Complex Multiply benchmark
5 //--------------------------------------------------------------------------
6 //
7 // This benchmark multiplies two complex numbers together. The input data (and
8 // reference data) should be generated using the cmplxmult_gendata.pl perl
9 // script and dumped to a file named dataset.h. The riscv-gcc toolchain does
10 // not support system calls so printf's can only be used on a host system, not
11 // on the riscv-v processor simulator itself.
12 //
13 // HOWEVER: printstr() and printhex() are provided, for a primitive form of
14 // printing strings and hexadecimal values to stdout.
15
16
17 // Choose which implementation you wish to test... but leave only one on!
18 // (only the first one will be executed).
19 //#define SCALAR_C
20 //#define SCALAR_ASM
21 #define VT_ASM
22
23 //--------------------------------------------------------------------------
24 // Macros
25
26 // Set HOST_DEBUG to 1 if you are going to compile this for a host
27 // machine (ie Athena/Linux) for debug purposes and set HOST_DEBUG
28 // to 0 if you are compiling with the smips-gcc toolchain.
29
30 #ifndef HOST_DEBUG
31 #define HOST_DEBUG 0
32 #endif
33
34 // Set PREALLOCATE to 1 if you want to preallocate the benchmark
35 // function before starting stats. If you have instruction/data
36 // caches and you don't want to count the overhead of misses, then
37 // you will need to use preallocation.
38
39 #ifndef PREALLOCATE
40 #define PREALLOCATE 0
41 #endif
42
43 // Set SET_STATS to 1 if you want to carve out the piece that actually
44 // does the computation.
45
46 #ifndef SET_STATS
47 #define SET_STATS 0
48 #endif
49
50 //--------------------------------------------------------------------------
51 // Host Platform Includes
52
53 #if HOST_DEBUG
54 #include <stdio.h>
55 #include <stdlib.h>
56 #else
57 void printstr(const char*);
58 #endif
59
60 #include "util.h"
61
62
63 //--------------------------------------------------------------------------
64 // Complex Value Structs
65
66 struct Complex
67 {
68 float real;
69 float imag;
70 };
71
72
73 //--------------------------------------------------------------------------
74 // Input/Reference Data
75
76 //#include "dataset_test.h"
77 #include "dataset.h"
78
79
80 //--------------------------------------------------------------------------
81 // Helper functions
82
83 float absolute( float in)
84 {
85 if (in > 0)
86 return in;
87 else
88 return -in;
89 }
90
91
92 // are two floating point numbers "close enough"?
93 // this is pretty loose, because Perl is giving me pretty terrible answers
94 int close_enough(float a, float b)
95 {
96 int close_enough = 1;
97
98 if ( absolute(a) > 1.10*absolute(b)
99 || absolute(a) < 0.90*absolute(b)
100 || absolute(a) > 1.10*absolute(b)
101 || absolute(a) < 0.90*absolute(b))
102 {
103 if (absolute(absolute(a) - absolute(b)) > 0.1)
104 {
105 close_enough = 0;
106 }
107 }
108
109 return close_enough;
110 }
111
112 int verify( int n, struct Complex test[], struct Complex correct[] )
113 {
114 int i;
115 for ( i = 0; i < n; i++ ) {
116 if ( !close_enough(test[i].real, correct[i].real)
117 || !close_enough(test[i].imag, correct[i].imag))
118 {
119 #if HOST_DEBUG
120 printf(" test[%d] : {%3.2f, %3.2f}\n", i, test[i].real, test[i].imag);
121 printf(" corr[%d] : {%3.2f, %3.2f}\n", i, correct[i].real, correct[i].imag);
122 #endif
123 // tell us which index fails + 10
124 // (so that if i==0,i==1 fails, we don't
125 // think it was a 'not-finished yet' or pass)
126 // return i+10;
127 return 2;
128 }
129 }
130 return 1;
131 }
132
133 //#if HOST_DEBUG
134 void printComplexArray( char name[], int n, struct Complex arr[] )
135 {
136 #if HOST_DEBUG
137 int i;
138 printf( " %10s :", name );
139 for ( i = 0; i < n; i++ )
140 printf( " {%03.2f,%03.2f} ", arr[i].real, arr[i].imag );
141 printf( "\n" );
142 #else
143 int i;
144 printstr( name );
145 for ( i = 0; i < n; i++ )
146 {
147 printstr(" {");
148 printhex((int) arr[i].real);
149 printstr(",");
150 printhex((int) arr[i].imag);
151 printstr("}");
152 }
153 printstr( "\n" );
154 #endif
155 }
156 //#endif
157
158
159
160 void finishTest( int correct, long long num_cycles, long long num_retired )
161 {
162 int toHostValue = correct;
163 #if HOST_DEBUG
164 if ( toHostValue == 1 )
165 printf( "*** PASSED ***\n" );
166 else
167 printf( "*** FAILED *** (tohost = %d)\n", toHostValue );
168 exit(0);
169 #else
170 // we no longer run in -testrun mode, which means we can't use
171 // the tohost register to communicate "test is done" and "test results"
172 // so instead we will communicate through print* functions!
173 if ( correct == 1 )
174 {
175 printstr( "*** PASSED *** (num_cycles = 0x" );
176 printhex(num_cycles);
177 printstr( ", num_inst_retired = 0x");
178 printhex(num_retired);
179 printstr( ")\n" );
180 }
181 else
182 {
183 printstr( "*** FAILED *** (num_cycles = 0x");
184 printhex(num_cycles);
185 printstr( ", num_inst_retired = 0x");
186 printhex(num_retired);
187 printstr( ")\n" );
188 }
189 exit();
190 #endif
191 }
192
193
194
195
196 // deprecated - cr10/stats-enable register no longer exists
197 void setStats( int enable )
198 {
199 #if ( !HOST_DEBUG && SET_STATS )
200 asm( "mtpcr %0, cr10" : : "r" (enable) );
201 #endif
202 }
203
204 long long getCycles()
205 {
206 long long cycles = 1337;
207 #if ( !HOST_DEBUG && SET_STATS )
208 __asm__ __volatile__( "rdcycle %0" : "=r" (cycles) );
209 #endif
210 return cycles;
211 }
212
213 long long getInstRetired()
214 {
215 long long inst_retired = 1338;
216 #if ( !HOST_DEBUG && SET_STATS )
217 __asm__ __volatile__( "rdinstret %0" : "=r" (inst_retired) );
218 #endif
219 return inst_retired;
220 }
221
222 //--------------------------------------------------------------------------
223 // complex multiply function
224
225 // scalar C implementation
226 void cmplxmult( int n, struct Complex a[], struct Complex b[], struct Complex c[] )
227 {
228 int i;
229 for ( i = 0; i < n; i++ )
230 {
231 c[i].real = (a[i].real * b[i].real) - (a[i].imag * b[i].imag);
232 c[i].imag = (a[i].imag * b[i].real) + (a[i].real * b[i].imag);
233 }
234 }
235
236 // assembly implementations can be found in *_asm.S
237
238 //--------------------------------------------------------------------------
239 // Main
240
241 int main( int argc, char* argv[] )
242 {
243 struct Complex results_data[DATA_SIZE];
244 long long start_cycles = 0;
245 long long stop_cycles = 0;
246 long long num_cycles;
247 long long start_retired = 0;
248 long long stop_retired = 0;
249 long long num_retired;
250
251 // Output the input array
252
253 #if HOST_DEBUG
254 printComplexArray( "input1", DATA_SIZE, input1_data );
255 printComplexArray( "input2", DATA_SIZE, input2_data );
256 printComplexArray( "verify", DATA_SIZE, verify_data );
257 #endif
258
259 // --------------------------------------------------
260 // If needed we preallocate everything in the caches
261
262 #if PREALLOCATE
263
264 #ifdef SCALAR_C
265 cmplxmult( DATA_SIZE, input1_data, input2_data, results_data );
266 #else
267 #ifdef SCALAR_ASM
268 scalar_cmplxmult_asm( DATA_SIZE, input1_data, input2_data, results_data );
269 #else
270 #ifdef VT_ASM
271 vt_cmplxmult_asm( DATA_SIZE, input1_data, input2_data, results_data );
272 #endif
273 #endif
274 #endif
275
276 #endif
277
278 // --------------------------------------------------
279 // Do the cmplxmult
280
281 start_cycles = getCycles();
282 start_retired = getInstRetired();
283
284 #ifdef SCALAR_C
285 cmplxmult( DATA_SIZE, input1_data, input2_data, results_data );
286 #else
287 #ifdef SCALAR_ASM
288 #if HOST_DEBUG==0
289 scalar_cmplxmult_asm( DATA_SIZE, input1_data, input2_data, results_data );
290 #endif
291 #else
292 #ifdef VT_ASM
293 #if HOST_DEBUG==0
294 vt_cmplxmult_asm( DATA_SIZE, input1_data, input2_data, results_data );
295 #endif
296 #endif
297 #endif
298 #endif
299
300 stop_cycles = getCycles();
301 stop_retired = getInstRetired();
302 num_cycles = stop_cycles - start_cycles;
303 num_retired = stop_retired - start_retired;
304
305 // --------------------------------------------------
306 // Print out the results
307
308 #if HOST_DEBUG
309 printComplexArray( "results", DATA_SIZE, results_data );
310 printComplexArray( "verify ", DATA_SIZE, verify_data );
311 #endif
312
313
314 // --------------------------------------------------
315 // Check the results
316 int correct = verify( DATA_SIZE, results_data, verify_data );
317 finishTest(correct, num_cycles, num_retired);
318
319 }