1#include <stdio.h>
2
3typedef enum {
4   CEILWS=0, CEILWD,
5   FLOORWS, FLOORWD,
6   ROUNDWS, ROUNDWD,
7   TRUNCWS, TRUNCWD
8} flt_dir_op_t;
9
10typedef enum {
11   CVTDS, CVTDW,
12   CVTSD, CVTSW,
13   CVTWS, CVTWD
14} flt_round_op_t;
15
16typedef enum {
17   TO_NEAREST=0, TO_ZERO, TO_PLUS_INFINITY, TO_MINUS_INFINITY } round_mode_t;
18char *round_mode_name[] = { "near", "zero", "+inf", "-inf" };
19
20
21const 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
28const 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
34const 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
43const 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
52const 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
131void 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
152int 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
208int 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
261int 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