1#include <stdio.h>
2#include <stdint.h>
3#include <inttypes.h>
4#include <assert.h>
5
6/* The golden logs were obtained by running this test natively. */
7
8/* The abstracted result of a CLCL insn */
9typedef struct {
10  uint64_t addr1;
11  uint32_t len1;
12  uint64_t addr2;
13  uint32_t len2;
14  uint8_t  pad;
15  uint32_t cc;
16} clcl_t;
17
18/* Register contents after CLCL insn */
19typedef struct {
20  uint64_t r1;
21  uint64_t r1p1;
22  uint64_t r2;
23  uint64_t r2p1;
24  uint64_t cc;
25} clcl_regs;
26
27/* Run a single CLCL insn and return its raw result. */
28static clcl_regs
29do_clcl(uint64_t r1, uint64_t r1p1, uint64_t r2, uint64_t r2p1)
30{
31  clcl_regs regs;
32
33  register uint64_t a1 asm ("2") = r1;
34  register uint64_t l1 asm ("3") = r1p1;
35  register uint64_t a2 asm ("4") = r2;
36  register uint64_t l2 asm ("5") = r2p1;
37  register uint32_t cc asm ("7");
38
39  asm volatile(	"0: clcl 2,4\n\t"
40                "jo 0b\n\t"
41                "ipm %0\n\t"
42                "srl %0,28\n\t"
43                :"=d" (cc), "+d" (a1),"+d" (l1), "+d" (a2), "+d" (l2)
44                : : "memory", "cc");
45
46  regs.r1   = a1;
47  regs.r1p1 = l1;
48  regs.r2   = a2;
49  regs.r2p1 = l2;
50  regs.cc   = cc;
51
52  return regs;
53}
54
55clcl_t
56result_from_regs(clcl_regs regs)
57{
58  clcl_t result;
59
60  result.addr1 = regs.r1;
61  result.len1  = regs.r1p1 & 0xFFFFFF;
62  result.addr2 = regs.r2;
63  result.len2  = regs.r2p1 & 0xFFFFFF;
64  result.pad   = (regs.r2p1 & 0xFF000000u) >> 24;
65  result.cc    = regs.cc;
66
67  return result;
68}
69
70/* Run CLCL twice using different fill bits for unused register bits.
71   Results ought to be the same */
72static clcl_t
73clcl(void *addr1, uint32_t len1,
74     void *addr2, uint32_t len2, uint32_t pad)
75{
76  clcl_t result1, result2;
77  clcl_regs regs;
78  uint64_t r1, r1p1, r2, r2p1;
79
80  /* Check input arguments */
81  assert((pad & 0xFF) == pad);  /* an 8-byte value */
82  assert((len1 & 0xFFFFFF) == len1);
83  assert((len2 & 0xFFFFFF) == len2);
84
85  /* Build up register contents setting unused bits to 0 */
86  r1   = (uint64_t)addr1;
87  r1p1 = len1;
88  r2   = (uint64_t)addr2;
89  r2p1 = len2 | (pad << 24);
90
91  /* Run clcl */
92  regs = do_clcl(r1, r1p1, r2, r2p1);
93  result1 = result_from_regs(regs);
94
95  /* Check unused bits */
96  if ((regs.r1p1 >> 24) != 0)
97    printf("FAIL: r1[0:39] modified (unused bits 0)\n");
98  if ((regs.r2p1 >> 32) != 0)
99    printf("FAIL: r2[0:31] modified (unused bits 0)\n");
100
101  /* Check pad value */
102  if (result1.pad != pad)
103    printf("FAIL: pad byte modified (unused bits 0)\n");
104
105  /* Build up register contents setting unused bits to 1 */
106  r1p1 |= 0xFFFFFFFFFFull << 24;
107  r2p1 |= ((uint64_t)0xFFFFFFFF) << 32;
108
109  /* Run clcl again */
110  regs = do_clcl(r1, r1p1, r2, r2p1);
111  result2 = result_from_regs(regs);
112
113  /* Check unused bits */
114  if ((regs.r1p1 >> 24) != 0xFFFFFFFFFFull)
115    printf("FAIL: r1[0:39] modified (unused bits 1)\n");
116  if ((regs.r2p1 >> 32) != 0xFFFFFFFFu)
117    printf("FAIL: r2[0:31] modified (unused bits 1)\n");
118
119  /* Check pad value */
120  if (result2.pad != pad)
121    printf("FAIL: pad byte modified (unused bits 1)\n");
122
123  /* Compare results */
124  if (result1.addr1 != result2.addr1)
125    printf("FAIL: addr1 result is different\n");
126  if (result1.addr2 != result2.addr2)
127    printf("FAIL: addr2 result is different\n");
128  if (result1.len1 != result2.len1)
129    printf("FAIL: len1 result is different\n");
130  if (result1.len2 != result2.len2)
131    printf("FAIL: len2 result is different\n");
132  if (result1.pad != result2.pad)
133    printf("FAIL: pad result is different\n");
134  if (result1.cc != result2.cc)
135    printf("FAIL: cc result is different\n");
136
137  return result1;
138}
139
140void
141run_test(void *addr1, uint32_t len1, void *addr2, uint32_t len2, uint32_t pad)
142{
143  clcl_t result;
144
145  result = clcl(addr1, len1, addr2, len2, pad);
146
147  printf("cc: %"PRIu32", len1: %"PRIu32", len2: %"PRIu32
148         ", addr1 diff: %"PRId64", addr2 diff: %"PRId64"\n", result.cc,
149         result.len1, result.len2, (int64_t)result.addr1 - (int64_t)addr1,
150         (int64_t)result.addr2 - (int64_t)addr2);
151}
152
153int main()
154{
155  uint8_t byte, byte1, byte2;
156
157  /* Test 1: both lengths are 0; nothing loaded from memory */
158  printf("--- test 1 ---\n");
159  run_test(NULL, 0, NULL, 0, 0x00);
160  run_test(NULL, 0, NULL, 0, 0xff);
161
162  /* Test 2: Compare two single bytes */
163  printf("--- test 2 ---\n");
164  byte1 = 10;
165  byte2 = 20;
166  run_test(&byte1, 1, &byte2, 1, 0x00);  // first operand low
167  run_test(&byte1, 1, &byte1, 1, 0x00);  // equal
168  run_test(&byte2, 1, &byte1, 1, 0x00);  // first operand high
169  run_test(&byte1, 1, &byte2, 1, 0xFF);  // first operand low
170  run_test(&byte1, 1, &byte1, 1, 0xFF);  // equal
171  run_test(&byte2, 1, &byte1, 1, 0xFF);  // first operand high
172
173  /* Test 3: Compare a single byte against the pad byte */
174  printf("--- test 3 ---\n");
175  byte = 10;
176  run_test(NULL, 0, &byte, 1, 10);  // equal
177  run_test(NULL, 0, &byte, 1,  9);  // first operand low
178  run_test(NULL, 0, &byte, 1, 11);  // first operand high
179  /* Swap operands */
180  run_test(&byte, 1, NULL, 0, 10);  // equal
181  run_test(&byte, 1, NULL, 0,  9);  // first operand high
182  run_test(&byte, 1, NULL, 0, 11);  // first operand low
183
184  /* Test 4: Make sure pad byte is interpreted as unsigned value */
185  printf("--- test 4 ---\n");
186  byte = 10;
187  run_test(&byte, 1, NULL, 0, 0xFF);  // first operand low
188  byte = 0xFF;
189  run_test(&byte, 1, NULL, 0, 0xFF);  // equal
190
191  /* Test 5: Compare a buffer against the pad byte */
192  printf("--- test 5 ---\n");
193  uint8_t buf1[4] = "yyyy";
194  run_test(buf1, 4, NULL, 0, 'y');    // equal
195  run_test(buf1, 4, NULL, 0, 'x');    // greater
196  run_test(buf1, 4, NULL, 0, 'z');    // less
197
198  /* Test 6: Compare two buffers of same size (difference in 1st byte) */
199  {
200  printf("--- test 6 ---\n");
201  uint8_t x[5] = "pqrst";
202  uint8_t y[5] = "abcde";
203  uint8_t z[5] = "abcde";
204  run_test(x, 5, y, 5, 'a');   // first operand low
205  run_test(y, 5, x, 5, 'a');   // first operand high
206  run_test(y, 5, z, 5, 'q');   // equal
207  }
208
209  /* Test 7: Compare two buffers of same size (difference in last byte) */
210  {
211  printf("--- test 7 ---\n");
212  uint8_t x[5] = "abcdd";
213  uint8_t y[5] = "abcde";
214  uint8_t z[5] = "abcdf";
215  run_test(x, 5, y, 5, 'a');   // first operand low
216  run_test(z, 5, z, 5, 'a');   // first operand high
217  }
218
219  /* Test 8: Compare two buffers of different size. The difference
220     is past the end of the shorter string. */
221  {
222  printf("--- test 8 ---\n");
223  uint8_t x[5] = "abcde";
224  uint8_t y[7] = "abcdeff";
225  run_test(x, 5, y, 7, 0);   // first operand low
226  run_test(y, 7, x, 5, 0);   // first operand high
227  run_test(x, 5, y, 7, 'f'); // equal
228  run_test(y, 7, x, 5, 'f'); // equal
229  }
230
231  /* Test 9: Compare two buffers of different size. The difference
232     is before the end of the shorter string. */
233  {
234  printf("--- test 9 ---\n");
235  uint8_t x[5] = "abcab";
236  uint8_t y[7] = "abcdeff";
237  run_test(x, 5, y, 7, 0);   // first operand low
238  run_test(y, 7, x, 5, 0);   // first operand high
239  run_test(x, 5, y, 7, 'f'); // first operand low
240  run_test(y, 7, x, 5, 'f'); // first operand high
241  }
242
243  return 0;
244}
245