| #include <stdio.h> |
| |
| typedef enum { |
| CEILWS=0, CEILWD, |
| FLOORWS, FLOORWD, |
| ROUNDWS, ROUNDWD, |
| TRUNCWS, TRUNCWD |
| } flt_dir_op_t; |
| |
| typedef enum { |
| CVTDS, CVTDW, |
| CVTSD, CVTSW, |
| CVTWS, CVTWD |
| } flt_round_op_t; |
| |
| typedef enum { |
| TO_NEAREST=0, TO_ZERO, TO_PLUS_INFINITY, TO_MINUS_INFINITY } round_mode_t; |
| char *round_mode_name[] = { "near", "zero", "+inf", "-inf" }; |
| |
| |
| const char *flt_dir_op_names[] = { |
| "ceil.w.s", "ceil.w.d", |
| "floor.w.s", "floor.w.d", |
| "round.w.s", "round.w.d", |
| "trunc.w.s", "trunc.w.d" |
| }; |
| |
| const char *flt_round_op_names[] = { |
| "cvt.d.s", "cvt.d.w", |
| "cvt.s.d", "cvt.s.w", |
| "cvt.w.s", "cvt.w.d" |
| }; |
| |
| const double fs_d[] = { |
| 0, 456.2489562, 3, -1, |
| 1384.6, -7.2945676, 1000000000, -5786.47, |
| 1752, 0.0024575, 0.00000001, -248562.76, |
| -45786.476, 456.2489562, 34.00046, 45786.476, |
| 1752065, 107, -45667.24, -7.2945676, |
| -347856.475, 356047.56, -1.0, 23.04, |
| }; |
| |
| const float fs_f[] = { |
| 0, 456.2489562, 3, -1, |
| 1384.6, -7.2945676, 1000000000, -5786.47, |
| 1752, 0.0024575, 0.00000001, -248562.76, |
| -45786.476, 456.2489562, 34.00046, 45786.476, |
| 1752065, 107, -45667.24, -7.2945676, |
| -347856.475, 356047.56, -1.0, 23.04, |
| }; |
| |
| const int fs_w[] = { |
| 0, 456, 3, -1, |
| 0xffffffff, 356, 1000000000, -5786, |
| 1752, 24575, 10, -248562, |
| -45786, 456, 34, 45786, |
| 1752065, 107, -45667, -7, |
| -347856, 0x80000000, 0xFFFFFFF, 23, |
| }; |
| |
| #define BINOP(op) \ |
| __asm__ volatile( \ |
| op" %0, %1, %2\n\t" \ |
| : "=f"(fd) : "f"(f) , "f"(fB)); |
| |
| #define UNOPdd(op) \ |
| fd_d = 0; \ |
| __asm__ volatile( \ |
| op" %0, %1\n\t" \ |
| : "=f"(fd_d) : "f"(fs_d[i])); |
| |
| #define UNOPff(op) \ |
| fd_f = 0; \ |
| __asm__ volatile( \ |
| op" %0, %1\n\t" \ |
| : "=f"(fd_f) : "f"(fs_f[i])); |
| |
| #define UNOPfd(op) \ |
| fd_d = 0; \ |
| __asm__ volatile( \ |
| op" %0, %1\n\t" \ |
| : "=f"(fd_d) : "f"(fs_f[i])); |
| |
| #define UNOPdf(op) \ |
| fd_f = 0; \ |
| __asm__ volatile( \ |
| op" %0, %1\n\t" \ |
| : "=f"(fd_f) : "f"(fs_d[i])); |
| |
| #define UNOPfw(op) \ |
| fd_w = 0; \ |
| __asm__ volatile( \ |
| op" $f0, %1\n\t" \ |
| "mfc1 %0, $f0\n\t" \ |
| : "=r"(fd_w) : "f"(fs_f[i]) \ |
| : "$f0"); |
| |
| #define UNOPdw(op) \ |
| fd_w = 0; \ |
| __asm__ volatile( \ |
| op" $f0, %1\n\t" \ |
| "mfc1 %0, $f0\n\t" \ |
| : "=r"(fd_w) : "f"(fs_d[i]) \ |
| : "$f0"); |
| |
| #define UNOPwd(op) \ |
| fd_d = 0; \ |
| __asm__ volatile( \ |
| "mtc1 %1, $f0\n\t" \ |
| op" %0, $f0\n\t" \ |
| : "=f"(fd_d) : "r"(fs_w[i]) \ |
| : "$f0", "$f1"); |
| |
| #define UNOPwf(op) \ |
| fd_f = 0; \ |
| __asm__ volatile( \ |
| "mtc1 %1, $f0\n\t" \ |
| op" %0, $f0\n\t" \ |
| : "=f"(fd_f) : "r"(fs_w[i]) \ |
| : "$f0"); |
| |
| void set_rounding_mode(round_mode_t mode) |
| { |
| switch(mode) { |
| case TO_NEAREST: |
| __asm__ volatile("cfc1 $t0, $31\n\t" |
| "srl $t0, 2\n\t" |
| "sll $t0, 2\n\t" |
| "ctc1 $t0, $31\n\t"); |
| |
| break; |
| case TO_ZERO: |
| __asm__ volatile("cfc1 $t0, $31\n\t" |
| "srl $t0, 2\n\t" |
| "sll $t0, 2\n\t" |
| "addiu $t0, 1\n\t" |
| "ctc1 $t0, $31\n\t"); |
| break; |
| case TO_PLUS_INFINITY: |
| __asm__ volatile("cfc1 $t0, $31\n\t" |
| "srl $t0, 2\n\t" |
| "sll $t0, 2\n\t" |
| "addiu $t0, 2\n\t" |
| "ctc1 $t0, $31\n\t"); |
| break; |
| case TO_MINUS_INFINITY: |
| __asm__ volatile("cfc1 $t0, $31\n\t" |
| "srl $t0, 2\n\t" |
| "sll $t0, 2\n\t" |
| "addiu $t0, 3\n\t" |
| "ctc1 $t0, $31\n\t"); |
| break; |
| } |
| } |
| |
| int directedRoundingMode(flt_dir_op_t op) { |
| double fd_d = 0; |
| float fd_f =0; |
| int fd_w = 0; |
| int i; |
| for (i = 0; i < 24; i++) { |
| switch(op) { |
| case CEILWS: |
| UNOPfw("ceil.w.s"); |
| printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]); |
| break; |
| case CEILWD: |
| UNOPdw("ceil.w.d"); |
| printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]); |
| break; |
| case FLOORWS: |
| UNOPfw("floor.w.s"); |
| printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]); |
| break; |
| case FLOORWD: |
| UNOPdw("floor.w.d"); |
| printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]); |
| break; |
| case ROUNDWS: |
| UNOPfw("round.w.s"); |
| printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]); |
| break; |
| case ROUNDWD: |
| UNOPdw("round.w.d"); |
| printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]); |
| break; |
| case TRUNCWS: |
| UNOPfw("trunc.w.s"); |
| printf("%s %d %f\n", flt_dir_op_names[op], fd_w, fs_f[i]); |
| break; |
| case TRUNCWD: |
| UNOPdw("trunc.w.d"); |
| printf("%s %d %lf\n", flt_dir_op_names[op], fd_w, fs_d[i]); |
| break; |
| default: |
| printf("error\n"); |
| break; |
| } |
| } |
| return 0; |
| } |
| |
| int FCSRRoundingMode(flt_round_op_t op1) |
| { |
| double fd_d = 0; |
| float fd_f = 0; |
| int fd_w = 0; |
| int i; |
| round_mode_t rm; |
| for (rm = TO_NEAREST; rm <= TO_MINUS_INFINITY; rm ++) |
| { |
| set_rounding_mode(rm); |
| printf("roundig mode: %s\n", round_mode_name[rm]); |
| for (i = 0; i < 24; i++) |
| { |
| set_rounding_mode(rm); |
| switch(op1) { |
| case CVTDS: |
| UNOPfd("cvt.d.s"); |
| printf("%s %lf %lf\n", flt_round_op_names[op1], fd_d, fs_f[i]); |
| break; |
| case CVTDW: |
| UNOPwd("cvt.d.w"); |
| printf("%s %lf %d\n", flt_round_op_names[op1], fd_d, fs_w[i]); |
| break; |
| case CVTSD: |
| UNOPdf("cvt.s.d"); |
| printf("%s %f %lf\n", flt_round_op_names[op1], fd_f, fs_d[i]); |
| break; |
| case CVTSW: |
| UNOPwf("cvt.s.w"); |
| printf("%s %f %d\n", flt_round_op_names[op1], fd_f, fs_w[i]); |
| break; |
| case CVTWS: |
| UNOPfw("cvt.w.s"); |
| printf("%s %d %f\n", flt_round_op_names[op1], fd_w, fs_f[i]); |
| break; |
| case CVTWD: |
| UNOPdw("cvt.w.d"); |
| printf("%s %d %lf\n", flt_round_op_names[op1], fd_w, fs_d[i]); |
| break; |
| default: |
| printf("error\n"); |
| break; |
| } |
| } |
| } |
| return 0; |
| } |
| |
| int main() |
| { |
| flt_dir_op_t op; |
| flt_round_op_t op1; |
| |
| printf("-------------------------- %s --------------------------\n", |
| "test FPU Conversion Operations Using a Directed Rounding Mode"); |
| for (op = CEILWS; op <= TRUNCWD; op++) { |
| directedRoundingMode(op); |
| } |
| |
| printf("-------------------------- %s --------------------------\n", |
| "test FPU Conversion Operations Using the FCSR Rounding Mode"); |
| for (op1 = CVTDS; op1 <= CVTWD; op1++) { |
| FCSRRoundingMode(op1); |
| } |
| return 0; |
| } |