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 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 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 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 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 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