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