blob: 270ea6dd5a831ba89cda331e390fe499777e52b3 [file] [log] [blame]
#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) {
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;
}