1 #include <stdio.h>
2 #include <stdint.h>
3 #include <inttypes.h>
4 #include "test.h"
5
6 uint32_t data[64];
7
8 /* The result of a checksum operation */
9 typedef struct {
10 uint64_t addr;
11 uint64_t len;
12 uint32_t sum;
13 char cc;
14 } cksm_t;
15
16
17 /* Compute the checksum via the cksm insn */
18 static __attribute__((noinline)) cksm_t
cksm_by_insn(const uint32_t * buff,uint64_t len,uint32_t sum)19 cksm_by_insn(const uint32_t *buff, uint64_t len, uint32_t sum)
20 {
21 const uint32_t *init_addr = buff;
22 uint64_t init_length = len;
23 uint64_t addr;
24 char cc;
25 cksm_t result;
26 register uint64_t reg2 asm("2") = (uint64_t) buff;
27 register uint64_t reg3 asm("3") = len;
28
29 asm volatile( " lhi 4,42\n\t"
30 " xr 4,4\n\t" /* set cc to != 0 */
31 "0: cksm %0,%1\n\t" /* do checksum on longs */
32 " jo 0b\n\t"
33 : "+d" (sum), "+d" (reg2), "+d" (reg3) : : "cc", "memory");
34
35 cc = get_cc();
36 len = reg3;
37 addr = reg2;
38
39 /* Check the results */
40 if(addr != (uint64_t)init_addr + init_length)
41 printf("FAIL: address not updated properly\n");
42
43 if(len != 0)
44 printf("FAIL: length not zero\n");
45
46 if (cc != 0)
47 printf("FAIL: condition code not zero\n");
48
49 result.addr = addr;
50 result.len = len;
51 result.cc = cc;
52 result.sum = sum;
53
54 return result;
55 }
56
57
58 /* Compute the checksum via hand-crafted algorithm */
59 static __attribute__((noinline)) cksm_t
cksm_by_hand(const uint32_t * buff,uint64_t len,uint32_t sum)60 cksm_by_hand(const uint32_t *buff, uint64_t len, uint32_t sum)
61 {
62 cksm_t result;
63 unsigned int n;
64 uint64_t v64;
65 uint32_t final;
66
67 for (n=0; n < len/4; n++) {
68 /* Add 4 bytes to the sum. Do this in 64-bit arithmetic so it's
69 easy to see whether there was a carry-out. */
70 v64 = sum;
71 v64 += buff[n];
72 /* If there was a carry-out, add 1 to the sum. */
73 if (v64 >> 32)
74 sum = sum + buff[n] + 1;
75 else
76 sum = sum + buff[n];
77 }
78
79 if (len != 0) {
80 switch (len % 4) {
81 case 0:
82 final = 0; // suppress gcc warning
83 /* done */
84 break;
85
86 case 1:
87 final = buff[n] & 0xFF000000;
88 break;
89
90 case 2:
91 final = buff[n] & 0xFFFF0000;
92 break;
93
94 case 3:
95 final = buff[n] & 0xFFFFFF00;
96 break;
97 }
98
99 if (len % 4) {
100 v64 = sum;
101 v64 += final;
102 /* If there was a carry-out, add 1 to the sum. */
103 if (v64 >> 32)
104 sum = sum + final + 1;
105 else
106 sum = sum + final;
107 }
108 }
109
110 result.addr = (uint64_t)buff + len;
111 result.len = 0;
112 result.cc = 0;
113 result.sum = sum;
114
115 return result;
116 }
117
118 /* The results computed by-insn and by-hand must compare equal and
119 the sum must be identical to EXPECTED_SUM. */
120 int
compare_results(cksm_t by_hand,cksm_t by_insn,uint32_t expected_sum)121 compare_results(cksm_t by_hand, cksm_t by_insn, uint32_t expected_sum)
122 {
123 int rc = 0;
124
125 if (by_hand.sum != by_insn.sum) {
126 ++rc;
127 printf("FAIL: sum: by-hand %"PRIx32" by-insn %"PRIx32"\n",
128 by_hand.sum, by_insn.sum);
129 }
130
131 if (by_hand.addr != by_insn.addr) {
132 ++rc;
133 printf("FAIL: addr: by-hand %"PRIx64" by-insn %"PRIx64"\n",
134 by_hand.addr, by_insn.addr);
135 }
136
137 if (by_hand.len != by_insn.len) {
138 ++rc;
139 printf("FAIL: len: by-hand %"PRIx64" by-insn %"PRIx64"\n",
140 by_hand.len, by_insn.len);
141 }
142
143 if (by_hand.cc != by_insn.cc) {
144 ++rc;
145 printf("FAIL: cc: by-hand %d by-insn %d\n",
146 by_hand.cc, by_insn.cc);
147 }
148
149 if (by_insn.sum != expected_sum) {
150 ++rc;
151 printf("FAIL: sum: by-insn %"PRIx32" expected %"PRIx32"\n",
152 by_insn.sum, expected_sum);
153 }
154
155 if (by_hand.sum != expected_sum) {
156 ++rc;
157 printf("FAIL: sum: by-hand %"PRIx32" expected %"PRIx32"\n",
158 by_hand.sum, expected_sum);
159 }
160
161 return rc;
162 }
163
164 /* Run a testcase. Compute the checksum by-hand and by-insn and compare
165 the results */
166 void
run_test(const char * name,const uint32_t * buff,uint64_t len,uint32_t sum,uint32_t expected_sum)167 run_test(const char *name, const uint32_t *buff, uint64_t len, uint32_t sum,
168 uint32_t expected_sum)
169 {
170 cksm_t by_hand, by_insn;
171
172 by_hand = cksm_by_hand(buff, len, sum);
173 by_insn = cksm_by_insn(buff, len, sum);
174 if (compare_results(by_hand, by_insn, expected_sum) != 0) {
175 printf("%s failed\n", name);
176 }
177 }
178
main()179 int main ()
180 {
181 uint32_t sum, expected_sum;
182 uint64_t len;
183
184 /* ---------------- test 1 ------------------------------ */
185 /* Add one word to an initial sum; no carry */
186 sum = 2;
187 data[0] = 1;
188 len = 4;
189 expected_sum = 3;
190 run_test("test1", data, len, sum, expected_sum);
191
192 /* ---------------- test 2 ------------------------------ */
193 /* Add one word to an initial sum; with carry */
194 sum = 1;
195 data[0] = 0xffffffff;
196 len = 4;
197 expected_sum = 1;
198 run_test("test2", data, len, sum, expected_sum);
199
200 /* ---------------- test 3 ------------------------------ */
201 /* Add 15 words to an initial sum; no carry */
202 sum = 0x1;
203 data[0] = 0x4;
204 data[1] = 0x10;
205 data[2] = 0x40;
206 data[3] = 0x100;
207 data[4] = 0x400;
208 data[5] = 0x1000;
209 data[6] = 0x4000;
210 data[7] = 0x10000;
211 data[8] = 0x40000;
212 data[9] = 0x100000;
213 data[10] = 0x400000;
214 data[11] = 0x1000000;
215 data[12] = 0x4000000;
216 data[13] = 0x10000000;
217 data[14] = 0x40000000;
218 len = 60;
219 expected_sum = 0x55555555;
220 run_test("test3", data, len, sum, expected_sum);
221
222 /* ---------------- test 4 ------------------------------ */
223 /* Add some words such that every addition generates a carry.
224 The data is such that the least significant byte is zero,
225 and the carrys from intermediate additions will accumulate
226 in the least significant byte. */
227 sum = 0xff000000;
228 data[0] = 0x80000000; /* 7f0000001 */
229 data[1] = 0x85000000; /* 040000002 */
230 data[2] = 0xff000000; /* 030000003 */
231 data[3] = 0xff000000; /* 020000004 */
232 data[4] = 0xff000000; /* 010000005 */
233 data[5] = 0xff000000; /* 000000006 */
234 len = 24;
235 expected_sum = 0x00000006;
236 run_test("test4", data, len, sum, expected_sum);
237
238 /* ---------------- test 5 ------------------------------ */
239 /* No words are added. Pass a NULL pointer so an attempt to
240 load would raise a SIGSEGV. */
241 len = 0;
242 sum = 42;
243 expected_sum = sum;
244 run_test("test5", NULL, len, sum, expected_sum);
245
246 /* ---------------- test 6 ------------------------------ */
247 /* Add 1 byte; no carry */
248 sum = 0x02000000;
249 len = 1;
250 data[0] = 0x7fffffff;
251 expected_sum = 0x81000000;
252 run_test("test6", data, len, sum, expected_sum);
253
254 /* ---------------- test 7 ------------------------------ */
255 /* Add 1 byte; carry */
256 sum = 0x02000000;
257 len = 1;
258 data[0] = 0xffffffff;
259 expected_sum = 0x01000001;
260 run_test("test7", data, len, sum, expected_sum);
261
262 /* ---------------- test 8 ------------------------------ */
263 /* Add 2 bytes; no carry */
264 sum = 0x00020000;
265 len = 2;
266 data[0] = 0x7fffffff;
267 expected_sum = 0x80010000;
268 run_test("test8", data, len, sum, expected_sum);
269
270 /* ---------------- test 9 ------------------------------ */
271 /* Add 2 bytes; carry */
272 sum = 0x00020000;
273 len = 2;
274 data[0] = 0xffffffff;
275 expected_sum = 0x00010001;
276 run_test("test9", data, len, sum, expected_sum);
277
278 /* ---------------- test 10 ------------------------------ */
279 /* Add 3 bytes; no carry */
280 sum = 0x00000200;
281 len = 3;
282 data[0] = 0x7fffffff;
283 expected_sum = 0x80000100;
284 run_test("test10", data, len, sum, expected_sum);
285
286 /* ---------------- test 11 ------------------------------ */
287 /* Add 3 bytes; carry */
288 sum = 0x00000200;
289 len = 3;
290 data[0] = 0xffffffff;
291 expected_sum = 0x00000101;
292 run_test("test11", data, len, sum, expected_sum);
293
294 return 0;
295 }
296