#include <stdio.h> #include <stdlib.h> typedef enum { ABSS=0, ABSD, ADDS, ADDD, DIVS, DIVD, MULS, MULD, NEGS, NEGD, SQRTS, SQRTD, SUBS, SUBD, RECIPS, RECIPD, RSQRTS, RSQRTD } flt_art_op_t; const char *flt_art_op_names[] = { "abs.s", "abs.d", "add.s", "add.d", "div.s", "div.d", "mul.s", "mul.d", "neg.s", "neg.d", "sqrt.s", "sqrt.d", "sub.s", "sub.d", "recip.s", "recip.d", "rsqrt.s", "rsqrt.d" }; 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 double fs_d[] = { 0, 456.25, 3, -1, 1384.5, -7.25, 1000000000, -5786.5, 1752, 0.015625, 0.03125, -248562.75, 456, -45786.5, 34.03125, 45786.75, 1752065, 107, -45667.25, -7, -347856.5, 356047.5, -1.0, 23.0625 }; const double ft_d[] = { -456.25, -45786.5, 34.03125, 45786.75, 1752065, 107, -45667.25, -7.25, -347856.5, 356047.5, -1.0, 23.0625, 0, 456.25, 3, -1, 1384.5, -7, 1000000000, -5786.5, 1752, 0.015625, 0.03125, -248562.75 }; const float fs_f[] = { 0, 456.25, 3, -1, 1384.5, -7.25, 1000000000, -5786.5, 1752, 0.015625, 0.03125, -248562.75, 456, -45786.5, 34.03125, 45786.75, 1752065, 107, -45667.25, -7, -347856.5, 356047.5, -1.0, 23.0625 }; const float ft_f[] = { -456.25, -4578.5, 34.03125, 4578.75, 175, 107, -456.25, -7.25, -3478.5, 356.5, -1.0, 23.0625, 0, 456.25, 3, -1, 1384.5, -7, 100, -5786.5, 1752, 0.015625, 0.03125, -248562.75 }; #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 BINOPf(op) \ fd_f = 0; \ __asm__ volatile( \ op" %0, %1, %2\n\t" \ : "=f"(fd_f) : "f"(fs_f[i]) , "f"(ft_f[i])); #define BINOPd(op) \ fd_d = 0; \ __asm__ volatile( \ op" %0, %1, %2\n\t" \ : "=f"(fd_d) : "f"(fs_d[i]) , "f"(ft_d[i])); 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 arithmeticOperations(flt_art_op_t op) { double fd_d = 0; float fd_f = 0; int i = 0; round_mode_t rm; for (rm = TO_NEAREST; rm <= TO_MINUS_INFINITY; rm ++) { set_rounding_mode(rm); printf("rounding mode: %s\n", round_mode_name[rm]); for (i = 0; i < 24; i++) { switch(op) { case ABSS: UNOPff("abs.s"); printf("%s %f %f\n", flt_art_op_names[op], fd_f, fs_f[i]); break; case ABSD: UNOPdd("abs.d"); printf("%s %lf %lf\n", flt_art_op_names[op], fd_d, fs_d[i]); break; case ADDS: BINOPf("add.s"); printf("%s %f %f %f\n", flt_art_op_names[op], fd_f, fs_f[i], ft_f[i]); break; case ADDD: BINOPd("add.d"); printf("%s %lf %lf %lf\n", flt_art_op_names[op], fd_d, fs_d[i], ft_d[i]); break; case DIVS: BINOPf("div.s"); printf("%s %f %f %f\n", flt_art_op_names[op], fd_f, fs_f[i], ft_f[i]); break; case DIVD: BINOPd("div.d"); printf("%s %lf %lf %lf\n", flt_art_op_names[op], fd_d, fs_d[i], ft_d[i]); break; case MULS: BINOPf("mul.s"); printf("%s %f %f %f\n", flt_art_op_names[op], fd_f, fs_f[i], ft_f[i]); break; case MULD: BINOPd("mul.d"); printf("%s %lf %lf %lf\n", flt_art_op_names[op], fd_d, fs_d[i], ft_d[i]); break; case NEGS: UNOPff("neg.s"); printf("%s %f %f\n", flt_art_op_names[op], fd_f, fs_f[i]); break; case NEGD: UNOPdd("neg.d"); printf("%s %lf %lf\n", flt_art_op_names[op], fd_d, fs_d[i]); break; case SQRTS: UNOPff("sqrt.s"); printf("%s %f %f\n", flt_art_op_names[op], fd_f, fs_f[i]); break; case SQRTD: UNOPdd("sqrt.d"); printf("%s %lf %lf\n", flt_art_op_names[op], fd_d, fs_d[i]); break; case SUBS: BINOPf("sub.s"); printf("%s %f %f %f\n", flt_art_op_names[op], fd_f, fs_f[i], ft_f[i]); break; case SUBD: BINOPd("sub.d"); printf("%s %lf %lf %lf\n", flt_art_op_names[op], fd_d, fs_d[i], ft_d[i]); break; case RECIPS: #if (__mips==32) && (__mips_isa_rev>=2) UNOPff("recip.s"); printf("%s %f %f\n", flt_art_op_names[op], fd_f, fs_f[i]); #endif break; case RECIPD: #if (__mips==32) && (__mips_isa_rev>=2) UNOPdd("recip.d"); printf("%s %lf %lf\n", flt_art_op_names[op], fd_d, fs_d[i]); #endif break; case RSQRTS: #if (__mips==32) && (__mips_isa_rev>=2) UNOPff("rsqrt.s"); printf("%s %f %f\n", flt_art_op_names[op], fd_f, fs_f[i]); #endif break; case RSQRTD: #if (__mips==32) && (__mips_isa_rev>=2) UNOPdd("rsqrt.d"); printf("%s %lf %lf\n", flt_art_op_names[op], fd_d, fs_d[i]); #endif break; default: printf("error\n"); break; } } } return 0; } int main() { flt_art_op_t op; printf("-------------------------- %s --------------------------\n", "test FPU Arithmetic Operations"); for (op = ABSS; op <= RECIPD; op++) { arithmeticOperations(op); } return 0; }