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.2489562, 3, -1, 36 1384.6, -7.2945676, 1000000000, -5786.47, 37 1752, 0.0024575, 0.00000001, -248562.76, 38 -45786.476, 456.2489562, 34.00046, 45786.476, 39 1752065, 107, -45667.24, -7.2945676, 40 -347856.475, 356047.56, -1.0, 23.04, 41 }; 42 43 const float fs_f[] = { 44 0, 456.2489562, 3, -1, 45 1384.6, -7.2945676, 1000000000, -5786.47, 46 1752, 0.0024575, 0.00000001, -248562.76, 47 -45786.476, 456.2489562, 34.00046, 45786.476, 48 1752065, 107, -45667.24, -7.2945676, 49 -347856.475, 356047.56, -1.0, 23.04, 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( \ 63 op" %0, %1, %2\n\t" \ 64 : "=f"(fd) : "f"(f) , "f"(fB)); 65 66 #define UNOPdd(op) \ 67 fd_d = 0; \ 68 __asm__ volatile( \ 69 op" %0, %1\n\t" \ 70 : "=f"(fd_d) : "f"(fs_d[i])); 71 72 #define UNOPff(op) \ 73 fd_f = 0; \ 74 __asm__ volatile( \ 75 op" %0, %1\n\t" \ 76 : "=f"(fd_f) : "f"(fs_f[i])); 77 78 #define UNOPfd(op) \ 79 fd_d = 0; \ 80 __asm__ volatile( \ 81 op" %0, %1\n\t" \ 82 : "=f"(fd_d) : "f"(fs_f[i])); 83 84 #define UNOPdf(op) \ 85 fd_f = 0; \ 86 __asm__ volatile( \ 87 op" %0, %1\n\t" \ 88 : "=f"(fd_f) : "f"(fs_d[i])); 89 90 #define UNOPfw(op) \ 91 fd_w = 0; \ 92 __asm__ volatile( \ 93 op" $f0, %1\n\t" \ 94 "mfc1 %0, $f0\n\t" \ 95 : "=r"(fd_w) : "f"(fs_f[i]) \ 96 : "$f0"); 97 98 #define UNOPdw(op) \ 99 fd_w = 0; \ 100 __asm__ volatile( \ 101 op" $f0, %1\n\t" \ 102 "mfc1 %0, $f0\n\t" \ 103 : "=r"(fd_w) : "f"(fs_d[i]) \ 104 : "$f0"); 105 106 #define UNOPwd(op) \ 107 fd_d = 0; \ 108 __asm__ volatile( \ 109 "mtc1 %1, $f0\n\t" \ 110 op" %0, $f0\n\t" \ 111 : "=f"(fd_d) : "r"(fs_w[i]) \ 112 : "$f0", "$f1"); 113 114 #define UNOPwf(op) \ 115 fd_f = 0; \ 116 __asm__ volatile( \ 117 "mtc1 %1, $f0\n\t" \ 118 op" %0, $f0\n\t" \ 119 : "=f"(fd_f) : "r"(fs_w[i]) \ 120 : "$f0"); 121 122 void set_rounding_mode(round_mode_t mode) 123 { 124 switch(mode) { 125 case TO_NEAREST: 126 __asm__ volatile("cfc1 $t0, $31\n\t" 127 "srl $t0, 2\n\t" 128 "sll $t0, 2\n\t" 129 "ctc1 $t0, $31\n\t"); 130 131 break; 132 case TO_ZERO: 133 __asm__ volatile("cfc1 $t0, $31\n\t" 134 "srl $t0, 2\n\t" 135 "sll $t0, 2\n\t" 136 "addiu $t0, 1\n\t" 137 "ctc1 $t0, $31\n\t"); 138 break; 139 case TO_PLUS_INFINITY: 140 __asm__ volatile("cfc1 $t0, $31\n\t" 141 "srl $t0, 2\n\t" 142 "sll $t0, 2\n\t" 143 "addiu $t0, 2\n\t" 144 "ctc1 $t0, $31\n\t"); 145 break; 146 case TO_MINUS_INFINITY: 147 __asm__ volatile("cfc1 $t0, $31\n\t" 148 "srl $t0, 2\n\t" 149 "sll $t0, 2\n\t" 150 "addiu $t0, 3\n\t" 151 "ctc1 $t0, $31\n\t"); 152 break; 153 } 154 } 155 156 int directedRoundingMode(flt_dir_op_t op) { 157 int fd_w = 0; 158 int i; 159 for (i = 0; i < 24; i++) { 160 switch(op) { 161 case CEILWS: 162 UNOPfw("ceil.w.s"); 163 printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]); 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 break; 169 case FLOORWS: 170 UNOPfw("floor.w.s"); 171 printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]); 172 break; 173 case FLOORWD: 174 UNOPdw("floor.w.d"); 175 printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]); 176 break; 177 case ROUNDWS: 178 UNOPfw("round.w.s"); 179 printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]); 180 break; 181 case ROUNDWD: 182 UNOPdw("round.w.d"); 183 printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]); 184 break; 185 case TRUNCWS: 186 UNOPfw("trunc.w.s"); 187 printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]); 188 break; 189 case TRUNCWD: 190 UNOPdw("trunc.w.d"); 191 printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]); 192 break; 193 default: 194 printf("error\n"); 195 break; 196 } 197 } 198 return 0; 199 } 200 201 int FCSRRoundingMode(flt_round_op_t op1) 202 { 203 double fd_d = 0; 204 float fd_f = 0; 205 int fd_w = 0; 206 int i; 207 round_mode_t rm; 208 for (rm = TO_NEAREST; rm <= TO_MINUS_INFINITY; rm ++) 209 { 210 set_rounding_mode(rm); 211 printf("roundig mode: %s\n", round_mode_name[rm]); 212 for (i = 0; i < 24; i++) 213 { 214 set_rounding_mode(rm); 215 switch(op1) { 216 case CVTDS: 217 UNOPfd("cvt.d.s"); 218 printf("%s %lf %lf\n", flt_round_op_names[op1], fd_d, fs_f[i]); 219 break; 220 case CVTDW: 221 UNOPwd("cvt.d.w"); 222 printf("%s %lf %d\n", flt_round_op_names[op1], fd_d, fs_w[i]); 223 break; 224 case CVTSD: 225 UNOPdf("cvt.s.d"); 226 printf("%s %f %lf\n", flt_round_op_names[op1], fd_f, fs_d[i]); 227 break; 228 case CVTSW: 229 UNOPwf("cvt.s.w"); 230 printf("%s %f %d\n", flt_round_op_names[op1], fd_f, fs_w[i]); 231 break; 232 case CVTWS: 233 UNOPfw("cvt.w.s"); 234 printf("%s %d %f\n", flt_round_op_names[op1], fd_w, fs_f[i]); 235 break; 236 case CVTWD: 237 UNOPdw("cvt.w.d"); 238 printf("%s %d %lf\n", flt_round_op_names[op1], fd_w, fs_d[i]); 239 break; 240 default: 241 printf("error\n"); 242 break; 243 } 244 } 245 } 246 return 0; 247 } 248 249 int main() 250 { 251 flt_dir_op_t op; 252 flt_round_op_t op1; 253 254 printf("-------------------------- %s --------------------------\n", 255 "test FPU Conversion Operations Using a Directed Rounding Mode"); 256 for (op = CEILWS; op <= TRUNCWD; op++) { 257 directedRoundingMode(op); 258 } 259 260 printf("-------------------------- %s --------------------------\n", 261 "test FPU Conversion Operations Using the FCSR Rounding Mode"); 262 for (op1 = CVTDS; op1 <= CVTWD; op1++) { 263 FCSRRoundingMode(op1); 264 } 265 return 0; 266 } 267 268