1 #include <stdio.h>
2
3 typedef enum {
4 CEILWS=0, CEILWD,
5 FLOORWS, FLOORWD,
6 ROUNDWS, ROUNDWD,
7 TRUNCWS, TRUNCWD
8 } flt_dir_op_t;
9
10 typedef enum {
11 CVTDS, CVTDW,
12 CVTSD, CVTSW,
13 CVTWS, CVTWD
14 } flt_round_op_t;
15
16 typedef enum {
17 TO_NEAREST=0, TO_ZERO, TO_PLUS_INFINITY, TO_MINUS_INFINITY } round_mode_t;
18 char *round_mode_name[] = { "near", "zero", "+inf", "-inf" };
19
20
21 const char *flt_dir_op_names[] = {
22 "ceil.w.s", "ceil.w.d",
23 "floor.w.s", "floor.w.d",
24 "round.w.s", "round.w.d",
25 "trunc.w.s", "trunc.w.d"
26 };
27
28 const char *flt_round_op_names[] = {
29 "cvt.d.s", "cvt.d.w",
30 "cvt.s.d", "cvt.s.w",
31 "cvt.w.s", "cvt.w.d"
32 };
33
34 const double fs_d[] = {
35 0, 456.25, 3, -1,
36 1384.5, -7.25, 1000000000, -5786.25,
37 1752, 0.015625, 0.03125, -248562.75,
38 -45786.5, 456, 34.03125, 45786.75,
39 1752065, 107, -45667.25, -7,
40 -347856.5, 356047, -1.25, 23.0625
41 };
42
43 const float fs_f[] = {
44 0, 456.25, 3, -1,
45 1384.5, -7.25, 1000000000, -5786.25,
46 1752, 0.015625, 0.03125, -248562.75,
47 -45786.5, 456, 34.03125, 45786.75,
48 1752065, 107, -45667.25, -7,
49 -347856.5, 356047, -1.25, 23.0625
50 };
51
52 const int fs_w[] = {
53 0, 456, 3, -1,
54 0xffffffff, 356, 1000000000, -5786,
55 1752, 24575, 10, -248562,
56 -45786, 456, 34, 45786,
57 1752065, 107, -45667, -7,
58 -347856, 0x80000000, 0xFFFFFFF, 23
59 };
60
61 #define BINOP(op) \
62 __asm__ volatile(op" %1, %2, %3" "\n\t" \
63 "cfc1 %0, $31" "\n\t" \
64 : "=r" (fcsr), "=f"(fd) \
65 : "f"(f) , "f"(fB));
66
67 #define UNOPdd(op) \
68 fd_d = 0; \
69 __asm__ volatile(op" %1, %2" "\n\t" \
70 "cfc1 %0, $31" "\n\t" \
71 : "=r" (fcsr), "=f"(fd_d) \
72 : "f"(fs_d[i]));
73
74 #define UNOPff(op) \
75 fd_f = 0; \
76 __asm__ volatile(op" %1, %2" "\n\t" \
77 "cfc1 %0, $31" "\n\t" \
78 : "=r" (fcsr), "=f"(fd_f) \
79 : "f"(fs_f[i]));
80
81 #define UNOPfd(op) \
82 fd_d = 0; \
83 __asm__ volatile(op" %1, %2" "\n\t" \
84 "cfc1 %0, $31" "\n\t" \
85 : "=r" (fcsr), "=f"(fd_d) \
86 : "f"(fs_f[i]));
87
88 #define UNOPdf(op) \
89 fd_f = 0; \
90 __asm__ volatile(op" %1, %2" "\n\t" \
91 "cfc1 %0, $31" "\n\t" \
92 : "=r" (fcsr), "=f"(fd_f) \
93 : "f"(fs_d[i]));
94
95 #define UNOPfw(op) \
96 fd_w = 0; \
97 __asm__ volatile(op" $f0, %2" "\n\t" \
98 "mfc1 %1, $f0" "\n\t" \
99 "cfc1 %0, $31" "\n\t" \
100 : "=r" (fcsr), "=r"(fd_w) \
101 : "f"(fs_f[i]) \
102 : "$f0");
103
104 #define UNOPdw(op) \
105 fd_w = 0; \
106 __asm__ volatile(op" $f0, %2" "\n\t" \
107 "mfc1 %1, $f0" "\n\t" \
108 "cfc1 %0, $31" "\n\t" \
109 : "=r" (fcsr), "=r"(fd_w) \
110 : "f"(fs_d[i]) \
111 : "$f0");
112
113 #define UNOPwd(op) \
114 fd_d = 0; \
115 __asm__ volatile("mtc1 %2, $f0" "\n\t" \
116 op" %1, $f0" "\n\t" \
117 "cfc1 %0, $31" "\n\t" \
118 : "=r" (fcsr), "=f"(fd_d) \
119 : "r"(fs_w[i]) \
120 : "$f0", "$f1");
121
122 #define UNOPwf(op) \
123 fd_f = 0; \
124 __asm__ volatile("mtc1 %2, $f0" "\n\t" \
125 op" %1, $f0" "\n\t" \
126 "cfc1 %0, $31" "\n\t" \
127 : "=r" (fcsr), "=f"(fd_f) \
128 : "r"(fs_w[i]) \
129 : "$f0");
130
set_rounding_mode(round_mode_t mode)131 void set_rounding_mode(round_mode_t mode)
132 {
133 switch(mode) {
134 case TO_NEAREST:
135 __asm__ volatile("ctc1 $zero, $31" "\n\t");
136 break;
137 case TO_ZERO:
138 __asm__ volatile("li $t0, 0x1" "\n\t"
139 "ctc1 $t0, $31" "\n\t");
140 break;
141 case TO_PLUS_INFINITY:
142 __asm__ volatile("li $t0, 0x2" "\n\t"
143 "ctc1 $t0, $31" "\n\t");
144 break;
145 case TO_MINUS_INFINITY:
146 __asm__ volatile("li $t0, 0x3" "\n\t"
147 "ctc1 $t0, $31" "\n\t");
148 break;
149 }
150 }
151
directedRoundingMode(flt_dir_op_t op)152 int directedRoundingMode(flt_dir_op_t op) {
153 int fd_w = 0;
154 int i;
155 int fcsr = 0;
156 round_mode_t rm = TO_NEAREST;
157 for (i = 0; i < 24; i++) {
158 set_rounding_mode(rm);
159 switch(op) {
160 case CEILWS:
161 UNOPfw("ceil.w.s");
162 printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]);
163 printf("fcsr: 0x%x\n", fcsr);
164 break;
165 case CEILWD:
166 UNOPdw("ceil.w.d");
167 printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]);
168 printf("fcsr: 0x%x\n", fcsr);
169 break;
170 case FLOORWS:
171 UNOPfw("floor.w.s");
172 printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]);
173 printf("fcsr: 0x%x\n", fcsr);
174 break;
175 case FLOORWD:
176 UNOPdw("floor.w.d");
177 printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]);
178 printf("fcsr: 0x%x\n", fcsr);
179 break;
180 case ROUNDWS:
181 UNOPfw("round.w.s");
182 printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]);
183 printf("fcsr: 0x%x\n", fcsr);
184 break;
185 case ROUNDWD:
186 UNOPdw("round.w.d");
187 printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]);
188 printf("fcsr: 0x%x\n", fcsr);
189 break;
190 case TRUNCWS:
191 UNOPfw("trunc.w.s");
192 printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]);
193 printf("fcsr: 0x%x\n", fcsr);
194 break;
195 case TRUNCWD:
196 UNOPdw("trunc.w.d");
197 printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]);
198 printf("fcsr: 0x%x\n", fcsr);
199 break;
200 default:
201 printf("error\n");
202 break;
203 }
204 }
205 return 0;
206 }
207
FCSRRoundingMode(flt_round_op_t op1)208 int FCSRRoundingMode(flt_round_op_t op1)
209 {
210 double fd_d = 0;
211 float fd_f = 0;
212 int fd_w = 0;
213 int i;
214 int fcsr = 0;
215 round_mode_t rm;
216 for (rm = TO_NEAREST; rm <= TO_MINUS_INFINITY; rm ++) {
217 set_rounding_mode(rm);
218 printf("roundig mode: %s\n", round_mode_name[rm]);
219 for (i = 0; i < 24; i++) {
220 set_rounding_mode(rm);
221 switch(op1) {
222 case CVTDS:
223 UNOPfd("cvt.d.s");
224 printf("%s %lf %lf\n", flt_round_op_names[op1], fd_d, fs_f[i]);
225 printf("fcsr: 0x%x\n", fcsr);
226 break;
227 case CVTDW:
228 UNOPwd("cvt.d.w");
229 printf("%s %lf %d\n", flt_round_op_names[op1], fd_d, fs_w[i]);
230 printf("fcsr: 0x%x\n", fcsr);
231 break;
232 case CVTSD:
233 UNOPdf("cvt.s.d");
234 printf("%s %f %lf\n", flt_round_op_names[op1], fd_f, fs_d[i]);
235 printf("fcsr: 0x%x\n", fcsr);
236 break;
237 case CVTSW:
238 UNOPwf("cvt.s.w");
239 printf("%s %f %d\n", flt_round_op_names[op1], fd_f, fs_w[i]);
240 printf("fcsr: 0x%x\n", fcsr);
241 break;
242 case CVTWS:
243 UNOPfw("cvt.w.s");
244 printf("%s %d %f\n", flt_round_op_names[op1], fd_w, fs_f[i]);
245 printf("fcsr: 0x%x\n", fcsr);
246 break;
247 case CVTWD:
248 UNOPdw("cvt.w.d");
249 printf("%s %d %lf\n", flt_round_op_names[op1], fd_w, fs_d[i]);
250 printf("fcsr: 0x%x\n", fcsr);
251 break;
252 default:
253 printf("error\n");
254 break;
255 }
256 }
257 }
258 return 0;
259 }
260
main()261 int main()
262 {
263 flt_dir_op_t op;
264 flt_round_op_t op1;
265
266 printf("-------------------------- %s --------------------------\n",
267 "test FPU Conversion Operations Using a Directed Rounding Mode");
268 for (op = CEILWS; op <= TRUNCWD; op++) {
269 directedRoundingMode(op);
270 }
271
272 printf("-------------------------- %s --------------------------\n",
273 "test FPU Conversion Operations Using the FCSR Rounding Mode");
274 for (op1 = CVTDS; op1 <= CVTWD; op1++) {
275 FCSRRoundingMode(op1);
276 }
277 return 0;
278 }
279
280