-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathcapi-vadd.c
120 lines (111 loc) · 3.63 KB
/
capi-vadd.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/*
* Copyright 2016 International Business Machines
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "capi-vadd.h"
// Create Work Element Descriptor (WED) for AFU
vadd_wed* create_wed(unsigned problem_size)
{
vadd_wed *wed;
posix_memalign((void**) &wed, CXL_ALIGNMENT, sizeof(*wed));
// The datatype for this AFU is unsigned
unsigned num_elements = CXL_ALIGNMENT/sizeof(unsigned);
// Determine the number of cache lines needed for output data.
// Write_na only supports data transfers of power of 2.
// Reserving the last cache line for each array ensures no data corruption
unsigned cache_lines = (problem_size%num_elements==0) ?
(problem_size/num_elements):(problem_size/num_elements+1);
wed->size = problem_size;
posix_memalign(&wed->input1, CXL_ALIGNMENT, cache_lines*CXL_ALIGNMENT);
posix_memalign(&wed->input2, CXL_ALIGNMENT, cache_lines*CXL_ALIGNMENT);
posix_memalign(&wed->output, CXL_ALIGNMENT, cache_lines*CXL_ALIGNMENT);
// Set initial values for done flag and clock_count
// The AFU will write to these values upon completion
wed->done = 0;
wed->clock_count = 0;
return wed;
}
// Free our WED
void free_wed(vadd_wed *wed)
{
free(wed->input1);
free(wed->input2);
free(wed->output);
free(wed);
return;
}
int main(int argc, char *argv[])
{
// Number of elements in each array. Default size is 128
unsigned problem_size = (argc>1) ? atoi(argv[1]):128;
printf("Problem size: %d\n", problem_size);
struct cxl_afu_h *afu;
// Open the AFU on the FPGA. Currently hard-coded to afu0.0d
afu = cxl_afu_open_dev("/dev/cxl/afu0.0d");
if (!afu)
{
printf("ERROR: Failed to open AFU\n");
return -1;
}
printf("Creating Work Element Descriptor\n");
// Create a WED for the AFU
vadd_wed *wed = create_wed(problem_size);
// Display the values that are sent to the FPGA
// These values will appear in the simulator when using PSLSE
printf("WED: %p\n", wed);
printf("Size: %lX\n", wed->size);
printf("input1: %p\n", wed->input1);
printf("input2: %p\n", wed->input2);
printf("output: %p\n", wed->output);
int i;
// Pointers to set the input arrays
// WED has void pointers. This AFU uses unsigned numbers
unsigned *input1 = (unsigned*) wed->input1;
unsigned *input2 = (unsigned*) wed->input2;
for (i=0; i<problem_size; i++)
{
input1[i] = i << 8;
input2[i] = i << 8;
}
// Attach to the AFU. WED is sent to the FPGA
cxl_afu_attach(afu, (__u64) wed);
// Wait for the AFU to write to done
printf("Waiting for done\n");
unsigned timeout = 0;
while (!wed->done)
{
sleep(1);
if (++timeout == 15) break;
}
printf("AFU finished\n");
printf("Clock count: %lX\n", wed->clock_count);
// Elapsed time for the AFU in us. (250 MHz clock)
printf("Runtime %f us\n", (double) wed->clock_count/250.0);
// Check AFU output
unsigned errors = 0;
unsigned *output = wed->output;
printf("output: %p\n", output);
for (i=0; i<problem_size; i++)
{
if(output[i] != 2*(i<<8))
{
printf("out%i: %X\n", i, output[i]);
errors++;
}
}
printf("Test %s\n", (errors==0)? "PASS":"FAIL");
cxl_afu_free(afu);
free_wed(wed);
return 0;
}