1/*	$OpenBSD: goodfreg.c,v 1.2 2003/07/12 04:23:16 jason Exp $	*/
2
3/*
4 * Copyright (c) 2003 Jason L. Wright (jason@thought.net)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28#include <sys/types.h>
29#include <stdio.h>
30#include <string.h>
31#include <err.h>
32#include "fpregs.h"
33
34struct fpquad {
35        u_int32_t x1;
36        u_int32_t x2;
37        u_int32_t x3;
38        u_int32_t x4;
39};
40
41void asm_ldq_f0(struct fpquad *);
42void asm_ldq_f4(struct fpquad *);
43void asm_ldq_f8(struct fpquad *);
44void asm_ldq_f12(struct fpquad *);
45void asm_ldq_f16(struct fpquad *);
46void asm_ldq_f20(struct fpquad *);
47void asm_ldq_f24(struct fpquad *);
48void asm_ldq_f28(struct fpquad *);
49void asm_ldq_f32(struct fpquad *);
50void asm_ldq_f36(struct fpquad *);
51void asm_ldq_f40(struct fpquad *);
52void asm_ldq_f44(struct fpquad *);
53void asm_ldq_f48(struct fpquad *);
54void asm_ldq_f52(struct fpquad *);
55void asm_ldq_f56(struct fpquad *);
56void asm_ldq_f60(struct fpquad *);
57
58void asm_stq_f0(struct fpquad *);
59void asm_stq_f4(struct fpquad *);
60void asm_stq_f8(struct fpquad *);
61void asm_stq_f12(struct fpquad *);
62void asm_stq_f16(struct fpquad *);
63void asm_stq_f20(struct fpquad *);
64void asm_stq_f24(struct fpquad *);
65void asm_stq_f28(struct fpquad *);
66void asm_stq_f32(struct fpquad *);
67void asm_stq_f36(struct fpquad *);
68void asm_stq_f40(struct fpquad *);
69void asm_stq_f44(struct fpquad *);
70void asm_stq_f48(struct fpquad *);
71void asm_stq_f52(struct fpquad *);
72void asm_stq_f56(struct fpquad *);
73void asm_stq_f60(struct fpquad *);
74
75int compare_regs(union fpregs *, union fpregs *);
76void dump_reg(union fpregs *);
77void dump_regs(union fpregs *, union fpregs *, union fpregs *);
78int compare_quads(struct fpquad *, struct fpquad *);
79void check_saves(union fpregs *, union fpregs *, union fpregs *);
80void c_stq(union fpregs *, int, struct fpquad *);
81void c_ldq(union fpregs *, int, struct fpquad *);
82void asm_ldq(int, struct fpquad *);
83void asm_stq(int, struct fpquad *);
84void check_reg(int, union fpregs *, union fpregs *, union fpregs *);
85void check_regs(union fpregs *, union fpregs *, union fpregs *);
86int main(void);
87
88int
89compare_regs(union fpregs *fr1, union fpregs *fr2)
90{
91	return (memcmp(fr1, fr2, sizeof(*fr2)));
92}
93
94void
95dump_reg(union fpregs *fr)
96{
97	int i;
98
99	for (i = 0; i < 64; i++) {
100		if ((i & 3) == 0)
101			printf("f%-2d:", i);
102		printf(" %08x", fr->f_reg32[i]);
103		if ((i & 3) == 3)
104			printf("\n");
105	}
106}
107
108void
109dump_regs(union fpregs *fr1, union fpregs *fr2, union fpregs *fr3)
110{
111	printf("BEFORE ASM\n");
112	dump_reg(fr1);
113	printf("AFTER ASM\n");
114	dump_reg(fr2);
115	printf("MANUAL\n");
116	dump_reg(fr3);
117}
118
119int
120compare_quads(struct fpquad *q1, struct fpquad *q2)
121{
122	return (memcmp(q1, q2, sizeof(*q2)));
123}
124
125/*
126 * Verify that savefpregs, loadfpregs, and initfpregs actually seem to work.
127 */
128void
129check_saves(union fpregs *fr1, union fpregs *fr2, union fpregs *fr3)
130{
131	memset(fr1, 0x55, sizeof(*fr1));
132	memset(fr2, 0x55, sizeof(*fr2));
133	memset(fr3, 0x55, sizeof(*fr3));
134	loadfpregs(fr1);
135	if (compare_regs(fr1, fr2))
136		errx(1, "check_saves: loadfpregs1 differs");
137
138	savefpregs(fr2);
139	if (compare_regs(fr1, fr2) || compare_regs(fr2, fr3))
140		errx(1, "check_saves: savefpregs1 differs");
141
142	memset(fr1, 0xaa, sizeof(*fr1));
143	memset(fr2, 0xaa, sizeof(*fr2));
144	memset(fr3, 0xaa, sizeof(*fr3));
145	loadfpregs(fr1);
146	if (compare_regs(fr1, fr2))
147		errx(1, "check_saves: loadfpregs2 differs");
148
149	savefpregs(fr2);
150	if (compare_regs(fr1, fr2) || compare_regs(fr2, fr3))
151		errx(1, "check_saves: savefpregs2 differs");
152
153	memset(fr1, 0xff, sizeof(*fr1));
154	initfpregs(fr2);
155	if (compare_regs(fr1, fr2))
156		errx(1, "check_saves: initfpregs differs");
157}
158
159void
160c_stq(union fpregs *frp, int freg, struct fpquad *q)
161{
162	q->x1 = frp->f_reg32[freg];
163	q->x2 = frp->f_reg32[freg + 1];
164	q->x3 = frp->f_reg32[freg + 2];
165	q->x4 = frp->f_reg32[freg + 3];
166}
167
168void
169c_ldq(union fpregs *frp, int freg, struct fpquad *q)
170{
171	frp->f_reg32[freg] = q->x1;
172	frp->f_reg32[freg + 1] = q->x2;
173	frp->f_reg32[freg + 2] = q->x3;
174	frp->f_reg32[freg + 3] = q->x4;
175}
176
177void
178asm_ldq(int freg, struct fpquad *q)
179{
180	switch (freg) {
181	case 0:
182		asm_ldq_f0(q);
183		break;
184	case 4:
185		asm_ldq_f4(q);
186		break;
187	case 8:
188		asm_ldq_f8(q);
189		break;
190	case 12:
191		asm_ldq_f12(q);
192		break;
193	case 16:
194		asm_ldq_f16(q);
195		break;
196	case 20:
197		asm_ldq_f20(q);
198		break;
199	case 24:
200		asm_ldq_f24(q);
201		break;
202	case 28:
203		asm_ldq_f28(q);
204		break;
205	case 32:
206		asm_ldq_f32(q);
207		break;
208	case 36:
209		asm_ldq_f36(q);
210		break;
211	case 40:
212		asm_ldq_f40(q);
213		break;
214	case 44:
215		asm_ldq_f44(q);
216		break;
217	case 48:
218		asm_ldq_f48(q);
219		break;
220	case 52:
221		asm_ldq_f52(q);
222		break;
223	case 56:
224		asm_ldq_f56(q);
225		break;
226	case 60:
227		asm_ldq_f60(q);
228		break;
229	default:
230		errx(1, "asm_ldq: bad freg %d", freg);
231	}
232}
233
234void
235asm_stq(int freg, struct fpquad *q)
236{
237	switch (freg) {
238	case 0:
239		asm_stq_f0(q);
240		break;
241	case 4:
242		asm_stq_f4(q);
243		break;
244	case 8:
245		asm_stq_f8(q);
246		break;
247	case 12:
248		asm_stq_f12(q);
249		break;
250	case 16:
251		asm_stq_f16(q);
252		break;
253	case 20:
254		asm_stq_f20(q);
255		break;
256	case 24:
257		asm_stq_f24(q);
258		break;
259	case 28:
260		asm_stq_f28(q);
261		break;
262	case 32:
263		asm_stq_f32(q);
264		break;
265	case 36:
266		asm_stq_f36(q);
267		break;
268	case 40:
269		asm_stq_f40(q);
270		break;
271	case 44:
272		asm_stq_f44(q);
273		break;
274	case 48:
275		asm_stq_f48(q);
276		break;
277	case 52:
278		asm_stq_f52(q);
279		break;
280	case 56:
281		asm_stq_f56(q);
282		break;
283	case 60:
284		asm_stq_f60(q);
285		break;
286	default:
287		errx(1, "asm_stq: bad freg %d", freg);
288	}
289}
290
291void
292check_reg(int freg, union fpregs *fr1, union fpregs *fr2, union fpregs *fr3)
293 {
294	struct fpquad q1, q2, q3;
295
296	initfpregs(fr1);
297	initfpregs(fr2);
298	initfpregs(fr3);
299
300	loadfpregs(fr1);
301	q1.x1 = 0x01234567;
302	q1.x2 = 0x89abcdef;
303	q1.x3 = 0x55aa55aa;
304	q1.x4 = 0xa5a5a5a5;
305	asm_ldq(freg, &q1);
306	savefpregs(fr2);
307
308	c_ldq(fr3, freg, &q1);
309
310	if (compare_regs(fr2, fr3)) {
311		errx(1, "ldq: c/asm differ");
312		dump_regs(fr1, fr2, fr3);
313	}
314
315	q2.x1 = q2.x2 = q2.x3 = q2.x4 = 0;
316	q3.x1 = q3.x2 = q3.x3 = q3.x4 = 1;
317	asm_stq(freg, &q2);
318	c_stq(fr3, freg, &q3);
319
320	if (compare_quads(&q1, &q3))
321		errx(1, "c_stq %d differs...", freg);
322
323	if (compare_quads(&q1, &q2))
324		errx(1, "asm_stq %d differs...", freg);
325}
326
327void
328check_regs(union fpregs *fr1, union fpregs *fr2, union fpregs *fr3)
329{
330	int i;
331
332	for (i = 0; i < 16; i++)
333		check_reg(i * 4, fr1, fr2, fr3);
334}
335
336int
337main()
338{
339	union fpregs fr1, fr2, fr3;
340
341	check_saves(&fr1, &fr2, &fr3);
342	check_regs(&fr1, &fr2, &fr3);
343	return (0);
344}
345