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 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 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 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 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