#include <stdio.h>
#include <stdint.h>
#ifndef __powerpc64__
typedef uint32_t HWord_t;
#else
typedef uint64_t HWord_t;
#endif
typedef void (*test_func_t)();
typedef struct test_table {
test_func_t func;
char *name;
} test_table_t;
static uint32_t values[] = {
0x6efbcfdf,
0xd16c2fd4,
0xf9dc1743,
0xa5aa0bd4,
0x6c8f0c14,
0x69a24188,
0x53b57f1b,
};
register HWord_t r27 asm("r27");
register HWord_t r28 asm("r28");
register HWord_t r29 asm("r29");
register HWord_t r30 asm("r30");
register HWord_t r31 asm("r31");
register HWord_t r14 asm("r14");
HWord_t temp[5];
#ifdef __powerpc64__
#define SAVE_REGS(addr) \
asm volatile( \
" std 27, 0(%0) \n" \
" std 28, 8(%0) \n" \
" std 29, 16(%0) \n" \
" std 30, 24(%0) \n" \
" std 31, 32(%0) \n" \
::"b"(addr))
#define RESTORE_REGS(addr) \
asm volatile( \
" ld 27, 0(%0) \n" \
" ld 28, 8(%0) \n" \
" ld 29, 16(%0) \n" \
" ld 30, 24(%0) \n" \
" ld 31, 32(%0) \n" \
::"b"(addr))
#else /* !__powerpc64__ */
#define SAVE_REGS(addr) \
asm volatile( \
" stw 27, 0(%0) \n" \
" stw 28, 4(%0) \n" \
" stw 29, 8(%0) \n" \
" stw 30, 12(%0) \n" \
" stw 31, 16(%0) \n" \
::"b"(addr))
#define RESTORE_REGS(addr) \
asm volatile( \
" lwz 27, 0(%0) \n" \
" lwz 28, 4(%0) \n" \
" lwz 29, 8(%0) \n" \
" lwz 30, 12(%0) \n" \
" lwz 31, 16(%0) \n" \
::"b"(addr))
#endif /* __powerpc64__ */
/*
* gcc is not happy if we modify r31 (the frame pointer) behind its back
* so we omit it
*/
static void __attribute__((optimize("-fomit-frame-pointer"))) test_lmw(void)
{
r14 = (HWord_t)values;
/* save r27 - r31 */
SAVE_REGS(temp);
/* load r27 - r31 */
asm volatile(
" lmw %r27, 0(%r14) \n");
#ifdef __powerpc64__
printf("lmw => %016lx %016lx %016lx %016lx %016lx\n",
#else
printf("lmw => %08x %08x %08x %08x %08x\n",
#endif
r27, r28, r29, r30, r31);
/*
* test load multiple with nonzero immediate offset
* load the last two values into r30 - r31.
* r27 - r29 should remain the same
*/
asm volatile(
" lmw %r30, 20(%r14) \n");
#ifdef __powerpc64__
printf("lmw => %016lx %016lx %016lx %016lx %016lx\n",
#else
printf("lmw => %08x %08x %08x %08x %08x\n",
#endif
r27, r28, r29, r30, r31);
/* restore r27 - r31 */
RESTORE_REGS(temp);
}
/*
* gcc is not happy if we modify r31 (the frame pointer) behind its back
* so we omit it
*/
static void __attribute__((optimize("-fomit-frame-pointer"))) test_stmw(void)
{
uint32_t result[7] = { 0 };
int i;
SAVE_REGS(temp);
#ifdef __powerpc64__
asm volatile(
" lwz 27, 0(%0) \n" \
" lwz 28, 4(%0) \n" \
" lwz 29, 8(%0) \n" \
" lwz 30, 12(%0) \n" \
" lwz 31, 16(%0) \n" \
::"b"(values));
#else
RESTORE_REGS(values);
#endif
r14 = (HWord_t)&result;
/* store r27 - r31 */
asm volatile(
" stmw %r27, 0(%r14) \n");
printf("stmw => ");
for (i = 0; i < sizeof(result) / sizeof(result[0]); i++)
printf("%08x ", result[i]);
printf("\n");
/*
* test store multiple with nonzero immediate offset
* store r30 - r31 into the last two places in the array
* the rest of the array should remain the same
*/
asm volatile(
" stmw %r30, 20(%r14) \n");
printf("stmw => ");
for (i = 0; i < sizeof(result) / sizeof(result[0]); i++)
printf("%08x ", result[i]);
printf("\n");
RESTORE_REGS(temp);
}
static test_table_t all_tests[] = {
{ &test_lmw,
"Test Load Multiple instruction" },
{ &test_stmw,
"Test Store Multiple instruction" },
{ NULL, NULL },
};
/*
* gcc is not happy if we modify r31 (the frame pointer) behind its back
* so we omit it
*/
int __attribute__((optimize("-fomit-frame-pointer"))) main(void)
{
test_func_t func;
int i = 0;
while ((func = all_tests[i].func)) {
(*func)();
i++;
}
return 0;
}