mirror of
https://github.com/ioacademy-jikim/debugging
synced 2025-06-11 09:56:29 +00:00
296 lines
7.2 KiB
C
296 lines
7.2 KiB
C
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <inttypes.h>
|
|
#include "test.h"
|
|
|
|
uint32_t data[64];
|
|
|
|
/* The result of a checksum operation */
|
|
typedef struct {
|
|
uint64_t addr;
|
|
uint64_t len;
|
|
uint32_t sum;
|
|
char cc;
|
|
} cksm_t;
|
|
|
|
|
|
/* Compute the checksum via the cksm insn */
|
|
static __attribute__((noinline)) cksm_t
|
|
cksm_by_insn(const uint32_t *buff, uint64_t len, uint32_t sum)
|
|
{
|
|
const uint32_t *init_addr = buff;
|
|
uint64_t init_length = len;
|
|
uint64_t addr;
|
|
char cc;
|
|
cksm_t result;
|
|
register uint64_t reg2 asm("2") = (uint64_t) buff;
|
|
register uint64_t reg3 asm("3") = len;
|
|
|
|
asm volatile( " lhi 4,42\n\t"
|
|
" xr 4,4\n\t" /* set cc to != 0 */
|
|
"0: cksm %0,%1\n\t" /* do checksum on longs */
|
|
" jo 0b\n\t"
|
|
: "+d" (sum), "+d" (reg2), "+d" (reg3) : : "cc", "memory");
|
|
|
|
cc = get_cc();
|
|
len = reg3;
|
|
addr = reg2;
|
|
|
|
/* Check the results */
|
|
if(addr != (uint64_t)init_addr + init_length)
|
|
printf("FAIL: address not updated properly\n");
|
|
|
|
if(len != 0)
|
|
printf("FAIL: length not zero\n");
|
|
|
|
if (cc != 0)
|
|
printf("FAIL: condition code not zero\n");
|
|
|
|
result.addr = addr;
|
|
result.len = len;
|
|
result.cc = cc;
|
|
result.sum = sum;
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/* Compute the checksum via hand-crafted algorithm */
|
|
static __attribute__((noinline)) cksm_t
|
|
cksm_by_hand(const uint32_t *buff, uint64_t len, uint32_t sum)
|
|
{
|
|
cksm_t result;
|
|
unsigned int n;
|
|
uint64_t v64;
|
|
uint32_t final;
|
|
|
|
for (n=0; n < len/4; n++) {
|
|
/* Add 4 bytes to the sum. Do this in 64-bit arithmetic so it's
|
|
easy to see whether there was a carry-out. */
|
|
v64 = sum;
|
|
v64 += buff[n];
|
|
/* If there was a carry-out, add 1 to the sum. */
|
|
if (v64 >> 32)
|
|
sum = sum + buff[n] + 1;
|
|
else
|
|
sum = sum + buff[n];
|
|
}
|
|
|
|
if (len != 0) {
|
|
switch (len % 4) {
|
|
case 0:
|
|
final = 0; // suppress gcc warning
|
|
/* done */
|
|
break;
|
|
|
|
case 1:
|
|
final = buff[n] & 0xFF000000;
|
|
break;
|
|
|
|
case 2:
|
|
final = buff[n] & 0xFFFF0000;
|
|
break;
|
|
|
|
case 3:
|
|
final = buff[n] & 0xFFFFFF00;
|
|
break;
|
|
}
|
|
|
|
if (len % 4) {
|
|
v64 = sum;
|
|
v64 += final;
|
|
/* If there was a carry-out, add 1 to the sum. */
|
|
if (v64 >> 32)
|
|
sum = sum + final + 1;
|
|
else
|
|
sum = sum + final;
|
|
}
|
|
}
|
|
|
|
result.addr = (uint64_t)buff + len;
|
|
result.len = 0;
|
|
result.cc = 0;
|
|
result.sum = sum;
|
|
|
|
return result;
|
|
}
|
|
|
|
/* The results computed by-insn and by-hand must compare equal and
|
|
the sum must be identical to EXPECTED_SUM. */
|
|
int
|
|
compare_results(cksm_t by_hand, cksm_t by_insn, uint32_t expected_sum)
|
|
{
|
|
int rc = 0;
|
|
|
|
if (by_hand.sum != by_insn.sum) {
|
|
++rc;
|
|
printf("FAIL: sum: by-hand %"PRIx32" by-insn %"PRIx32"\n",
|
|
by_hand.sum, by_insn.sum);
|
|
}
|
|
|
|
if (by_hand.addr != by_insn.addr) {
|
|
++rc;
|
|
printf("FAIL: addr: by-hand %"PRIx64" by-insn %"PRIx64"\n",
|
|
by_hand.addr, by_insn.addr);
|
|
}
|
|
|
|
if (by_hand.len != by_insn.len) {
|
|
++rc;
|
|
printf("FAIL: len: by-hand %"PRIx64" by-insn %"PRIx64"\n",
|
|
by_hand.len, by_insn.len);
|
|
}
|
|
|
|
if (by_hand.cc != by_insn.cc) {
|
|
++rc;
|
|
printf("FAIL: cc: by-hand %d by-insn %d\n",
|
|
by_hand.cc, by_insn.cc);
|
|
}
|
|
|
|
if (by_insn.sum != expected_sum) {
|
|
++rc;
|
|
printf("FAIL: sum: by-insn %"PRIx32" expected %"PRIx32"\n",
|
|
by_insn.sum, expected_sum);
|
|
}
|
|
|
|
if (by_hand.sum != expected_sum) {
|
|
++rc;
|
|
printf("FAIL: sum: by-hand %"PRIx32" expected %"PRIx32"\n",
|
|
by_hand.sum, expected_sum);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
/* Run a testcase. Compute the checksum by-hand and by-insn and compare
|
|
the results */
|
|
void
|
|
run_test(const char *name, const uint32_t *buff, uint64_t len, uint32_t sum,
|
|
uint32_t expected_sum)
|
|
{
|
|
cksm_t by_hand, by_insn;
|
|
|
|
by_hand = cksm_by_hand(buff, len, sum);
|
|
by_insn = cksm_by_insn(buff, len, sum);
|
|
if (compare_results(by_hand, by_insn, expected_sum) != 0) {
|
|
printf("%s failed\n", name);
|
|
}
|
|
}
|
|
|
|
int main ()
|
|
{
|
|
uint32_t sum, expected_sum;
|
|
uint64_t len;
|
|
|
|
/* ---------------- test 1 ------------------------------ */
|
|
/* Add one word to an initial sum; no carry */
|
|
sum = 2;
|
|
data[0] = 1;
|
|
len = 4;
|
|
expected_sum = 3;
|
|
run_test("test1", data, len, sum, expected_sum);
|
|
|
|
/* ---------------- test 2 ------------------------------ */
|
|
/* Add one word to an initial sum; with carry */
|
|
sum = 1;
|
|
data[0] = 0xffffffff;
|
|
len = 4;
|
|
expected_sum = 1;
|
|
run_test("test2", data, len, sum, expected_sum);
|
|
|
|
/* ---------------- test 3 ------------------------------ */
|
|
/* Add 15 words to an initial sum; no carry */
|
|
sum = 0x1;
|
|
data[0] = 0x4;
|
|
data[1] = 0x10;
|
|
data[2] = 0x40;
|
|
data[3] = 0x100;
|
|
data[4] = 0x400;
|
|
data[5] = 0x1000;
|
|
data[6] = 0x4000;
|
|
data[7] = 0x10000;
|
|
data[8] = 0x40000;
|
|
data[9] = 0x100000;
|
|
data[10] = 0x400000;
|
|
data[11] = 0x1000000;
|
|
data[12] = 0x4000000;
|
|
data[13] = 0x10000000;
|
|
data[14] = 0x40000000;
|
|
len = 60;
|
|
expected_sum = 0x55555555;
|
|
run_test("test3", data, len, sum, expected_sum);
|
|
|
|
/* ---------------- test 4 ------------------------------ */
|
|
/* Add some words such that every addition generates a carry.
|
|
The data is such that the least significant byte is zero,
|
|
and the carrys from intermediate additions will accumulate
|
|
in the least significant byte. */
|
|
sum = 0xff000000;
|
|
data[0] = 0x80000000; /* 7f0000001 */
|
|
data[1] = 0x85000000; /* 040000002 */
|
|
data[2] = 0xff000000; /* 030000003 */
|
|
data[3] = 0xff000000; /* 020000004 */
|
|
data[4] = 0xff000000; /* 010000005 */
|
|
data[5] = 0xff000000; /* 000000006 */
|
|
len = 24;
|
|
expected_sum = 0x00000006;
|
|
run_test("test4", data, len, sum, expected_sum);
|
|
|
|
/* ---------------- test 5 ------------------------------ */
|
|
/* No words are added. Pass a NULL pointer so an attempt to
|
|
load would raise a SIGSEGV. */
|
|
len = 0;
|
|
sum = 42;
|
|
expected_sum = sum;
|
|
run_test("test5", NULL, len, sum, expected_sum);
|
|
|
|
/* ---------------- test 6 ------------------------------ */
|
|
/* Add 1 byte; no carry */
|
|
sum = 0x02000000;
|
|
len = 1;
|
|
data[0] = 0x7fffffff;
|
|
expected_sum = 0x81000000;
|
|
run_test("test6", data, len, sum, expected_sum);
|
|
|
|
/* ---------------- test 7 ------------------------------ */
|
|
/* Add 1 byte; carry */
|
|
sum = 0x02000000;
|
|
len = 1;
|
|
data[0] = 0xffffffff;
|
|
expected_sum = 0x01000001;
|
|
run_test("test7", data, len, sum, expected_sum);
|
|
|
|
/* ---------------- test 8 ------------------------------ */
|
|
/* Add 2 bytes; no carry */
|
|
sum = 0x00020000;
|
|
len = 2;
|
|
data[0] = 0x7fffffff;
|
|
expected_sum = 0x80010000;
|
|
run_test("test8", data, len, sum, expected_sum);
|
|
|
|
/* ---------------- test 9 ------------------------------ */
|
|
/* Add 2 bytes; carry */
|
|
sum = 0x00020000;
|
|
len = 2;
|
|
data[0] = 0xffffffff;
|
|
expected_sum = 0x00010001;
|
|
run_test("test9", data, len, sum, expected_sum);
|
|
|
|
/* ---------------- test 10 ------------------------------ */
|
|
/* Add 3 bytes; no carry */
|
|
sum = 0x00000200;
|
|
len = 3;
|
|
data[0] = 0x7fffffff;
|
|
expected_sum = 0x80000100;
|
|
run_test("test10", data, len, sum, expected_sum);
|
|
|
|
/* ---------------- test 11 ------------------------------ */
|
|
/* Add 3 bytes; carry */
|
|
sum = 0x00000200;
|
|
len = 3;
|
|
data[0] = 0xffffffff;
|
|
expected_sum = 0x00000101;
|
|
run_test("test11", data, len, sum, expected_sum);
|
|
|
|
return 0;
|
|
}
|