Home | History | Annotate | Download | only in s390x
      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