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