1 #include <stdio.h>
2 #include <stdint.h>
3 
4 #ifndef __powerpc64__
5 typedef uint32_t HWord_t;
6 #else
7 typedef uint64_t HWord_t;
8 #endif
9 
10 typedef void (*test_func_t)();
11 
12 typedef struct test_table {
13    test_func_t func;
14    char *name;
15 } test_table_t;
16 
17 static uint32_t values[] = {
18    0x6efbcfdf,
19    0xd16c2fd4,
20    0xf9dc1743,
21    0xa5aa0bd4,
22    0x6c8f0c14,
23    0x69a24188,
24    0x53b57f1b,
25 };
26 
27 register HWord_t r27 asm("r27");
28 register HWord_t r28 asm("r28");
29 register HWord_t r29 asm("r29");
30 register HWord_t r30 asm("r30");
31 register HWord_t r31 asm("r31");
32 
33 register HWord_t r14 asm("r14");
34 
35 HWord_t temp[5];
36 
37 #ifdef __powerpc64__
38 
39 #define SAVE_REGS(addr)                       \
40    asm volatile(                              \
41    "	std   27, 0(%0)   \n"                   \
42    "	std   28, 8(%0)   \n"                   \
43    "	std   29, 16(%0)  \n"                   \
44    "	std   30, 24(%0)  \n"                   \
45    "	std   31, 32(%0)  \n"                   \
46    ::"b"(addr))
47 
48 #define RESTORE_REGS(addr)                    \
49    asm volatile(                              \
50    "	ld    27, 0(%0)   \n"                   \
51    "	ld    28, 8(%0)   \n"                   \
52    "	ld    29, 16(%0)  \n"                   \
53    "	ld    30, 24(%0)  \n"                   \
54    "	ld    31, 32(%0)  \n"                   \
55    ::"b"(addr))
56 
57 #else /* !__powerpc64__ */
58 
59 #define SAVE_REGS(addr)                       \
60    asm volatile(                              \
61    "	stw   27, 0(%0)   \n"                   \
62    "	stw   28, 4(%0)   \n"                   \
63    "	stw   29, 8(%0)   \n"                   \
64    "	stw   30, 12(%0)  \n"                   \
65    "	stw   31, 16(%0)  \n"                   \
66    ::"b"(addr))
67 
68 #define RESTORE_REGS(addr)                    \
69    asm volatile(                              \
70    "	lwz   27, 0(%0)   \n"                   \
71    "	lwz   28, 4(%0)   \n"                   \
72    "	lwz   29, 8(%0)   \n"                   \
73    "	lwz   30, 12(%0)  \n"                   \
74    "	lwz   31, 16(%0)  \n"                   \
75    ::"b"(addr))
76 
77 #endif /* __powerpc64__ */
78 
79 /*
80  * gcc is not happy if we modify r31 (the frame pointer) behind its back
81  * so we omit it
82  */
test_lmw(void)83 static void __attribute__((optimize("-fomit-frame-pointer"))) test_lmw(void)
84 {
85    r14 = (HWord_t)values;
86 
87    /* save r27 - r31 */
88    SAVE_REGS(temp);
89 
90    /* load r27 - r31 */
91    asm volatile(
92       "	lmw	%r27, 0(%r14)	\n");
93 
94 #ifdef __powerpc64__
95    printf("lmw => %016lx %016lx %016lx %016lx %016lx\n",
96 #else
97    printf("lmw => %08x %08x %08x %08x %08x\n",
98 #endif
99           r27, r28, r29, r30, r31);
100 
101    /*
102     * test load multiple with nonzero immediate offset
103     * load the last two values into r30 - r31.
104     * r27 - r29 should remain the same
105     */
106    asm volatile(
107       "	lmw	%r30, 20(%r14)	\n");
108 
109 #ifdef __powerpc64__
110    printf("lmw => %016lx %016lx %016lx %016lx %016lx\n",
111 #else
112    printf("lmw => %08x %08x %08x %08x %08x\n",
113 #endif
114           r27, r28, r29, r30, r31);
115 
116    /* restore r27 - r31 */
117    RESTORE_REGS(temp);
118 }
119 
120 /*
121  * gcc is not happy if we modify r31 (the frame pointer) behind its back
122  * so we omit it
123  */
test_stmw(void)124 static void __attribute__((optimize("-fomit-frame-pointer"))) test_stmw(void)
125 {
126    uint32_t result[7] = { 0 };
127    int i;
128 
129    SAVE_REGS(temp);
130 
131 #ifdef __powerpc64__
132    asm volatile(
133    "	lwz   27, 0(%0)   \n"                   \
134    "	lwz   28, 4(%0)   \n"                   \
135    "	lwz   29, 8(%0)   \n"                   \
136    "	lwz   30, 12(%0)  \n"                   \
137    "	lwz   31, 16(%0)  \n"                   \
138    ::"b"(values));
139 #else
140    RESTORE_REGS(values);
141 #endif
142 
143    r14 = (HWord_t)&result;
144 
145    /* store r27 - r31 */
146    asm volatile(
147       "	stmw	%r27, 0(%r14)	\n");
148 
149    printf("stmw => ");
150    for (i = 0; i < sizeof(result) / sizeof(result[0]); i++)
151       printf("%08x ", result[i]);
152 
153    printf("\n");
154 
155    /*
156     * test store multiple with nonzero immediate offset
157     * store r30 - r31 into the last two places in the array
158     * the rest of the array should remain the same
159     */
160    asm volatile(
161       "	stmw	%r30, 20(%r14)	\n");
162 
163    printf("stmw => ");
164    for (i = 0; i < sizeof(result) / sizeof(result[0]); i++)
165       printf("%08x ", result[i]);
166 
167    printf("\n");
168 
169    RESTORE_REGS(temp);
170 }
171 
172 static test_table_t all_tests[] = {
173    { &test_lmw,
174      "Test Load Multiple instruction" },
175    { &test_stmw,
176      "Test Store Multiple instruction" },
177    { NULL, NULL },
178 };
179 
180 /*
181  * gcc is not happy if we modify r31 (the frame pointer) behind its back
182  * so we omit it
183  */
main(void)184 int __attribute__((optimize("-fomit-frame-pointer"))) main(void)
185 {
186    test_func_t func;
187    int i = 0;
188 
189    while ((func = all_tests[i].func)) {
190       (*func)();
191       i++;
192    }
193 
194    return 0;
195 }
196