sync with devkit psp

This commit is contained in:
Sam Hegarty
2011-10-24 20:51:41 +13:00
parent 6f7c397dfc
commit e3279bfee3
23 changed files with 1821 additions and 270 deletions

View File

@@ -14,5 +14,5 @@ libpspfpuincludedir = @PSPSDK_INCLUDEDIR@
libpspfpuinclude_HEADERS = pspfpu.h
lib_LIBRARIES = libpspfpu.a
libpspfpu_a_SOURCES = pspfpu.c
libpspfpu_a_SOURCES = pspfpu.c double.S
libpspfpu_a_LIBADD =

196
src/fpu/double.S Normal file
View File

@@ -0,0 +1,196 @@
#define zero $0 /* wired zero */
#define at $1 /* assembler temp */
#define v0 $2 /* return value */
#define v1 $3
#define a0 $4 /* argument registers */
#define a1 $5
#define a2 $6
#define a3 $7
#define t0 $8 /* caller saved */
#define t1 $9
#define t2 $10
#define t3 $11
#define t4 $12
#define t5 $13
#define t6 $14
#define t7 $15
#define s0 $16 /* callee saved */
#define s1 $17
#define s2 $18
#define s3 $19
#define s4 $20
#define s5 $21
#define s6 $22
#define s7 $23
#define t8 $24 /* code generator */
#define t9 $25
#define k0 $26 /* kernel temporary */
#define k1 $27
#define gp $28 /* global pointer */
#define sp $29 /* stack pointer */
#define fp $30 /* frame pointer */
#define ra $31 /* return address */
#define fv0 $f0
#define fv1 $f1
#define ft0 $f2
#define ft1 $f3
#define ft2 $f4
#define ft3 $f5
#define ft4 $f6
#define ft5 $f7
#define ft6 $f8
#define ft7 $f9
#define ft8 $f10
#define ft9 $f11
#define fa0 $f12
#define fa1 $f13
#define fa2 $f14
#define fa3 $f15
#define fa4 $f16
#define fa5 $f17
#define fa6 $f18
#define fa7 $f19
#define fs0 $f20
#define fs1 $f21
#define fs2 $f22
#define fs3 $f23
#define fs4 $f24
#define fs5 $f25
#define fs6 $f26
#define fs7 $f27
#define fs8 $f28
#define fs9 $f29
#define fs10 $f30
#define fs11 $f31
.set noreorder
.set noat
.text
.align 4
.global pspFpuFloatToDouble
.global pspFpuDoubleToFloat
/**
* convert float to double
* double pspFpuFloatToDouble(float a);
*
* input: fa0
* output: v0,v1
* clobber: t0,t1
*/
.ent pspFpuFloatToDouble
pspFpuFloatToDouble:
mfc1 t0, fa0 /* t0 = fa0 */
ext t1, t0, 23, 8 /* t1 = (t0 >> 23) & 0xFF */
beq t1, zero, ftod_denormal /* if (t1==0) goto ftod_denormal */
addiu v0, t1, (-0x7F+0x3FF) /* v0 = t1 - 0x7F + 0x3FF */
xori t1, t1, 0xFF /* t1 = t1 ^ 0xFF */
li v1, 0x7FF /* v1 = 0x7FF */
movz v0, v1, t1 /* v0 = (t1==0) ? v1 : v0 */
ext v1, t0, 3, 20 /* v1 = (t0 >> 3 ) & 0x00FFFFF */
ins v1, v0, 20, 11 /* v1 = (v1 & 0x800FFFFF) | ((v0<<20) & 0x7FF00000) */
sll v0, t0, 29 /* v0 = (t0 << 29) */
srl t0, t0, 31 /* t0 = (t0 >> 31) & 1 */
jr ra /* return */
ins v1, t0, 31, 1 /* v1 = (v1 & 0x7FFFFFFF) | ((t0<<31) & 0x80000000) */
ftod_denormal:
sll v0, t0, 9 /* v0 = t0 << 9 */
beql v0, zero, ftod_zero /* if (v0==0) goto ftod_zero */
move v1, zero /* v1 = 0 */
li v1, 0x380 /* v1 = 0x380 */
clz t1, v0 /* t1 = clz(v0) */
subu v0, v1, t1 /* v0 = v1 - v0 = 0x380 - clz(t1) */
sllv t1, t0, t1 /* t1 = t0 << t1 */
ext v1, t1, 2, 20 /* v1 = (t1 >> 2 ) & 0x00FFFFF */
ins v1, v0, 20, 11 /* v1 = (v1 & 0x800FFFFF) | ((v0<<20) & 0x7FF00000) */
sll v0, t1, 30 /* v0 = (t1 << 30) */
ftod_zero:
srl t0, t0, 31 /* t0 = (t0 >> 31) & 1 */
jr ra /* return */
ins v1, t0, 31, 1 /* v1 = (v1 & 0x7FFFFFFF) | ((t0<<31) & 0x80000000) */
.end pspFpuFloatToDouble
/**
* convert double to float
* float pspFpuDoubleToFloat(double a);
* input: a0,a1
* output: fv0
* clobber: t0,t1,t2,v0
*/
.ent pspFpuDoubleToFloat
pspFpuDoubleToFloat:
ext t0, a1, 20, 11 /* t0 = (a1>>20) & 0x000007FF */
beq t0, zero, dtof_zero /* if (t0==0) goto dtof_zero */
xori t1, t0, 0x7FF /* t1 = t0 ^ 0x7FF */
beq t1, zero, dtof_naninf /* if (t1==0) goto dtof_naninf */
addiu t1, t0, (+0x7F-0x3FF) /* t1 = t0 + 0x7F - 0x3FF */
blez t1, dtof_denormal /* if (t1<=0) goto dtof_denormal */
addiu t2, t1, -0xFE /* t2 = t1 - 0xFE */
bgtz t2, dtof_inf /* if (t2 > 0) goto dtof_inf */
move v0, zero /* v0 = 0 */
srl v0, a0, 29 /* v0 = (a0>>29) & 0x00000007 */
ins v0, a1, 3, 20 /* v0 = (v0 & 0xFF800007) | ((a1 & 0FFFFF)<<3) */
beq t2, zero, dtof_inf_normal /* if (t2==0) goto dtof_inf_normal */
dtof_normal:
srl t2, a1, 31 /* t2 = (a1>>31) & 1 */
ins v0, t2, 31, 1 /* v0 = (v0 & 0x7FFFFFFF) | (t2 << 31) */
ins v0, t1, 23, 8 /* v0 = (v0 & 0x8007FFFF) | (t1 << 23) */
jr ra /* return */
mtc1 v0, fv0 /* fv0 = v0 */
dtof_denormal:
sll t0, a1, 12 /* t0 = a1 << 12 */
srl v0, t0, 10 /* v0 = t0 >> 10 */
srl t0, a0, 30 /* t0 = t0 >> 30 */
or v0, v0, t0 /* v0 = v0 | t0 */
li t0, 0x00400000 /* t0 = 0x00400000 */
or v0, v0, t0 /* v0 = v0 | t0 */
subu t0, zero, t1 /* t0 = zero - t1 */
sltiu t1, t0, 22 /* t1 = (t0 < 22) */
beq t1, zero, dtof_min /* if (t1==0) goto dtof_min */
srlv v0, v0, t0 /* v0 = v0 >> t0 */
srl t2, a1, 31 /* t2 = (a1>>31) & 1 */
ins v0, t2, 31, 1 /* v0 = (v0 & 0x7FFFFFFF) | (t2 << 31) */
jr ra /* return */
mtc1 v0, fv0 /* fv0 = v0 */
dtof_zero:
sll t0, a1, 12 /* t0 = a1 << 12 */
or t0, t0, a0 /* t0 = t0 | a0 */
dtof_min:
li v0, 0x00000001 /* v0 = 0x00000001 */
movz v0, zero, t0 /* v0 = (t0==0) ? zero : v0 */
srl t0, a1, 31 /* t0 = (a1 >> 31) & 1 */
ins v0, t0, 31, 1 /* v0 = (v0 & 0x7FFFFFFF) | ((t0<<31) & 0x80000000) */
jr ra /* return */
mtc1 v0, fv0 /* fv0 = v0 */
dtof_inf_normal:
nor t0, zero, a1 /* t0 = ~a1 */
sll t0, t0, 12 /* t0 = t0 << 12 */
bne t0, zero, dtof_normal /* if (t0!=0) goto dtof_normal */
srl t0, a0, 28 /* t0 = a0 >> 28 */
sltiu t0, t0, 0xF /* t0 = (t0 < 0xF) */
bne t0, zero, dtof_normal /* if (t0!=0) goto dtof_normal */
nop /* waste delay slot */
j dtof_inf /* goto dtof_inf */
move v0, zero /* v0 = 0 */
dtof_naninf:
sll t0, a1, 12 /* t0 = a1 << 12 */
or t1, t0, a0 /* t1 = t0 | a0 */
srl v0, t0, 9 /* v0 = t0 >> 9 */
srl t0, a0, 29 /* t0 = t0 >> 29 */
or v0, v0, t0 /* v0 = v0 | t0 */
sltiu t0, v0, 1 /* t0 = (v0 < 1) */
or v0, v0, t0 /* v0 = v0 | t0 */
movz v0, zero, t1 /* v0 = (t1==0) ? zero : v0 */
dtof_inf:
li t0, 0x7F800000 /* t0 = 0x7F800000 */
or v0, v0, t0 /* v0 = v0 | t0 */
srl t0, a1, 31 /* t0 = (a1 >> 31) & 1 */
ins v0, t0, 31, 1 /* v0 = (v0 & 0x7FFFFFFF) | ((t0<<31) & 0x80000000) */
jr ra /* return */
mtc1 v0, fv0 /* fv0 = v0 */
.end pspFpuDoubleToFloat

View File

@@ -5,13 +5,42 @@
*
* pspfpu.h - PSP FPU library
*
* Copyright (c) 2006 TyRaNiD (James F.)
* Copyright (c) 2009 JetCube
* Copyright (c) 2006 TyRaNiD (James F.)
*
* $Id: pspfpu.c 1781 2006-02-04 12:53:40Z tyranid $
*/
#include "pspfpu.h"
uint32_t pspfpu_get_fcr31(void)
#define PSP_MATH_PI 3.14159265358979323846
#define PSP_MATH_TWOPI (PSP_MATH_PI * 2.0)
#define PSP_MATH_SQRT2 1.41421356237309504880
#define PSP_MATH_LN2 0.69314718055994530942
#define PSP_MATH_LOG2E 1.4426950408889634074
#define COS_SIN_DIV 0.208
static const float logPoly[] = {
4194305.0 / (1024.0 * 1024.0 * 2.0), /* arround 2.0 */
5590817.0 / (1024.0 * 1024.0 * 8.0), /* arround 2.0/3.0 */
13890687.0 / (1024.0 * 1024.0 * 32.0), /* arround 2.0/5.0 */
};
static const float triPoly[] = {
(float)(2.0*PSP_MATH_PI),
(float)(1.0),
(float)(-0xAAAA98/(1024.0*1024*64)),
(float)( 0x88801C/(1024.0*1024*1024)),
(float)(-0xCB9F27/(1024.0*1024*1024*64)),
(float)(-0xFFFFF9/(1024.0*1024*32)),
(float)( 0xAAA6FB/(1024.0*1024*256)),
(float)(-0xB3D431/(1024.0*1024*1024*8)),
(float)(-0xAAAAAA/(1024.0*1024*32)),
(float)( 0xCCCCCD/(1024.0*1024*64)),
(float)(-0x8F5C29/(1024.0*1024*64)),
};
uint32_t pspFpuGetFCR31(void)
{
uint32_t ret;
@@ -23,129 +52,892 @@ uint32_t pspfpu_get_fcr31(void)
return ret;
}
void pspfpu_set_fcr31(uint32_t var)
void pspFpuSetFCR31(uint32_t var)
{
asm (
"ctc1 %0, $31\n"
:
:
: "r"(var)
);
}
void pspfpu_set_roundmode(enum FpuRoundMode mode)
void pspFpuSetRoundmode(enum PspFpuRoundMode mode)
{
uint32_t fcr;
fcr = pspfpu_get_fcr31();
fcr &= ~FPU_RM_MASK;
fcr |= (mode & FPU_RM_MASK);
pspfpu_set_fcr31(fcr);
fcr = pspFpuGetFCR31();
fcr &= ~PSP_FPU_RM_MASK;
fcr |= (mode & PSP_FPU_RM_MASK);
pspFpuSetFCR31(fcr);
}
enum FpuRoundMode pspfpu_get_roundmode(void)
enum PspFpuRoundMode pspFpuGetRoundmode(void)
{
return pspfpu_get_fcr31() & FPU_RM_MASK;
return pspFpuGetFCR31() & PSP_FPU_RM_MASK;
}
uint32_t pspfpu_get_flags(void)
uint32_t pspFpuGetFlags(void)
{
uint32_t fcr;
fcr = pspfpu_get_fcr31();
return (fcr & FPU_FLAGS_MASK) >> FPU_FLAGS_POS;
fcr = pspFpuGetFCR31();
return (fcr & PSP_FPU_FLAGS_MASK) >> PSP_FPU_FLAGS_POS;
}
void pspfpu_clear_flags(uint32_t clear)
void pspFpuClearFlags(uint32_t clear)
{
uint32_t fcr;
clear &= 0x1F;
fcr = pspfpu_get_fcr31();
fcr &= ~(clear << FPU_FLAGS_POS);
pspfpu_set_fcr31(fcr);
fcr = pspFpuGetFCR31();
fcr &= ~(clear << PSP_FPU_FLAGS_POS);
pspFpuSetFCR31(fcr);
}
uint32_t pspfpu_get_enable(void)
uint32_t pspFpuGetEnable(void)
{
uint32_t fcr;
fcr = pspfpu_get_fcr31();
return (fcr & FPU_ENABLE_MASK) >> FPU_ENABLE_POS;
fcr = pspFpuGetFCR31();
return (fcr & PSP_FPU_ENABLE_MASK) >> PSP_FPU_ENABLE_POS;
}
void pspfpu_set_enable(uint32_t enable)
void pspFpuSetEnable(uint32_t enable)
{
uint32_t fcr;
enable &= 0x1F;
fcr = pspfpu_get_fcr31() & ~FPU_ENABLE_MASK;
fcr |= enable << FPU_ENABLE_POS;
pspfpu_set_fcr31(fcr);
fcr = pspFpuGetFCR31() & ~PSP_FPU_ENABLE_MASK;
fcr |= enable << PSP_FPU_ENABLE_POS;
pspFpuSetFCR31(fcr);
}
uint32_t pspfpu_get_cause(void)
uint32_t pspFpuGetCause(void)
{
uint32_t fcr;
fcr = pspfpu_get_fcr31();
return (fcr & FPU_CAUSE_MASK) >> FPU_CAUSE_POS;
fcr = pspFpuGetFCR31();
return (fcr & PSP_FPU_CAUSE_MASK) >> PSP_FPU_CAUSE_POS;
}
void pspfpu_clear_cause(uint32_t clear)
void pspFpuClearCause(uint32_t clear)
{
uint32_t fcr;
clear &= 0x3F;
fcr = pspfpu_get_fcr31();
fcr &= ~(clear << FPU_CAUSE_POS);
pspfpu_set_fcr31(fcr);
fcr = pspFpuGetFCR31();
fcr &= ~(clear << PSP_FPU_CAUSE_POS);
pspFpuSetFCR31(fcr);
}
uint32_t pspfpu_get_fs(void)
uint32_t pspFpuGetFS(void)
{
uint32_t fcr;
fcr = pspfpu_get_fcr31();
return (fcr & FPU_FS_MASK) >> FPU_FS_POS;
fcr = pspFpuGetFCR31();
return (fcr & PSP_FPU_FS_MASK) >> PSP_FPU_FS_POS;
}
void pspfpu_set_fs(uint32_t fs)
void pspFpuSetFS(uint32_t fs)
{
uint32_t fcr;
fcr = pspfpu_get_fcr31();
fcr &= ~FPU_FS_MASK;
fcr = pspFpuGetFCR31();
fcr &= ~PSP_FPU_FS_MASK;
fcr |= ((fs & 1) << FPU_FS_POS);
fcr |= ((fs & 1) << PSP_FPU_FS_POS);
pspfpu_set_fcr31(fcr);
pspFpuSetFCR31(fcr);
}
uint32_t pspfpu_get_condbits(void)
uint32_t pspFpuGetCondbits(void)
{
uint32_t fcr;
uint32_t cond;
fcr = pspfpu_get_fcr31();
cond = (fcr & FPU_CC0_MASK) >> FPU_CC0_POS;
cond |= (fcr & FPU_CC17_MASK) >> (FPU_CC17_POS-1);
fcr = pspFpuGetFCR31();
cond = (fcr & PSP_FPU_CC0_MASK) >> PSP_FPU_CC0_POS;
cond |= (fcr & PSP_FPU_CC17_MASK) >> (PSP_FPU_CC17_POS-1);
return cond;
}
void pspfpu_clear_condbits(uint32_t clear)
void pspFpuClearCondbits(uint32_t clear)
{
uint32_t fcr;
clear &= 0xFF;
fcr = pspfpu_get_fcr31();
fcr &= ~((clear & 1) << FPU_CC0_POS);
fcr &= ~((clear & 0xFE) << (FPU_CC17_POS-1));
fcr = pspFpuGetFCR31();
fcr &= ~((clear & 1) << PSP_FPU_CC0_POS);
fcr &= ~((clear & 0xFE) << (PSP_FPU_CC17_POS-1));
pspfpu_set_fcr31(fcr);
pspFpuSetFCR31(fcr);
}
float pspFpuAbs(float fs)
{
register float fd;
asm (
"abs.s %0, %1\n"
: "=f"(fd)
: "f"(fs)
);
return (fd);
}
int pspFpuCeil(float fs)
{
return (__builtin_allegrex_ceil_w_s(fs));
}
int pspFpuFloor(float fs)
{
return (__builtin_allegrex_floor_w_s(fs));
}
float pspFpuMax(float fs1, float fs2)
{
register float fd;
fd = (fs1 > fs2) ? fs1 : fs2;
return (fd);
}
float pspFpuMin(float fs1, float fs2)
{
register float fd;
fd = (fs1 < fs2) ? fs1 : fs2;
return (fd);
}
float pspFpuNeg(float fs)
{
register float fd;
asm (
"neg.s %0, %1\n"
: "=f"(fd)
: "f"(fs)
);
return (fd);
}
int pspFpuRound(float fs)
{
return (__builtin_allegrex_round_w_s(fs));
}
float pspFpuRsqrt(float fs)
{
return (1.0f / __builtin_allegrex_sqrt_s(fs));
}
float pspFpuSqrt(float fs)
{
return (__builtin_allegrex_sqrt_s(fs));
}
int pspFpuTrunc(float fs)
{
return (__builtin_allegrex_trunc_w_s(fs));
}
float pspFpuFmod(float fs, float fd)
{
float v;
asm (
".set push\n"
".set noreorder\n"
"div.s %0, %1, %2\n" // v = fs / fd
"trunc.w.s %0, %0\n" // v = trunc(v)
"cvt.s.w %0, %0\n" // v = (float)v = (float)trunc(v)
"mul.s %0, %0, %2\n" // v = v * fd
"sub.s %0, %1, %0\n" // v = fs - v*fd = fs - trunc(fs / fd)*fd
".set pop\n"
: "=&f"(v)
: "f"(fs), "f"(fd)
);
return (v);
}
float pspFpuFrac(float fs)
{
float v;
asm (
".set push\n"
".set noreorder\n"
"trunc.w.s %0, %1\n" // v = trunc(fs)
"cvt.s.w %0, %0\n" // v = (float)v = (float)trunc(fs)
"sub.s %0, %1, %0\n" // v = fs - v
".set pop\n"
: "=&f"(v)
: "f"(fs)
);
return (v);
}
float pspFpuReinterpretFloat(uint32_t ui)
{
float v;
asm (
"mtc1 %1, %0\n"
: "=f"(v)
: "r"(ui)
);
return (v);
}
uint32_t pspFpuReinterpretUint(float fs)
{
unsigned int v;
asm (
"mfc1 %0, %1\n"
: "=r"(v)
: "f"(fs)
);
return (v);
}
int pspFpuIsEqual(float fs1, float fs2)
{
int v;
asm (
".set push\n"
".set noreorder\n"
"c.eq.s %2, %1\n" // compare fs1 to fs2
"move %0, $0\n" // v = 0
"bc1tl 0f\n" // if (fs1==fs2) goto 0f
"addiu %0, $0, 1\n" // if (fs1==fs2) v = 1
"0:\n"
".set pop\n"
: "=r"(v)
: "f"(fs1), "f"(fs2)
);
return (v);
}
float pspFpuSignFloat(float fs)
{
float fv;
asm (
".set push\n"
".set noreorder\n"
"mfc1 $8, %1\n" // t0 = fs
"lui $10, 0x3F80\n" // t2 = 0x3F800000(1.0f)
"srl $9, $8, 23\n" // t1 = t0>>23
"srl $8, $8, 31\n" // t0 = t0>>31
"andi $9, $9, 0x00FF\n" // t1 = t1 & 0x00FF
"sll $8, $8, 31\n" // t0 = t0<<31 = (fs>=0) ? 0 : 0x80000000
"movz $10, $0, $9\n" // t2 = (t1==0) ? 0 : t2
"or $10, $10, $8\n" // t2 = t2 | t0
"mtc1 $10, %0\n" // fv = t2
".set pop\n"
: "=f"(fv)
: "f"(fs)
: "$8", "$9", "$10"
);
return (fv);
}
int pspFpuSignInt(float fs)
{
int v;
asm (
".set push\n"
".set noreorder\n"
"mfc1 %0, %1\n" // v = fs
"lui $8, 0x7F80\n" // t0 = 0x7F800000(binary representaion 1.0 * 2^(255-127))
"and $8, $8, %0\n" // t0 = at & v
"sra %0, %0, 30\n" // v = fs>>30 = (fs>=0) ? 0or1 : -1or-2
"or %0, %0, 1\n" // v = v | 1 = (fs>=0) ? 1 : -1
"movz %0, $0, $8\n" // v = (t0==0) ? 0 : v
".set pop\n"
: "=r"(v)
: "f"(fs)
: "$8"
);
return (v);
}
float pspFpuPositiveZero(void)
{
float v;
asm (
"mtc1 $0, %0\n" // v = 0.0f
: "=f"(v)
);
return (v);
}
float pspFpuNegativeZero(void)
{
float v;
asm (
".set push\n"
".set noreorder\n"
"lui $8, 0x8000\n" // t0 = 0x80000000
"mtc1 $8, %0\n" // v = -0.0f
".set pop\n"
: "=f"(v)
:
: "$8"
);
return (v);
}
int pspFpuIsZero(float f)
{
int v;
asm (
".set push\n"
".set noreorder\n"
"mfc1 $8, %1\n" // t0 = f
"sra %0, $8, 30\n" // v = t0>>30
"sll $8, $8, 1\n" // t0 = t0<<1
"ori %0, %0, 0x0001\n" // v = v | 1 = (f>=0) ? +1 : -1
"movn %0, $0, $8\n" // v = (t0!=0) ? 0 : v
".set pop\n"
: "=r"(v)
: "f"(f)
: "$8"
);
return (v);
}
int pspFpuIsPositiveZero(float f)
{
int v;
asm (
".set push\n"
".set noreorder\n"
"mfc1 %0, %1\n" // v = f
"sltiu %0, %0, 1\n" // v = (v < 1)
".set pop\n"
: "=r"(v)
: "f"(f)
);
return (v);
}
int pspFpuIsNegativeZero(float f)
{
int v;
asm (
".set push\n"
".set noreorder\n"
"mfc1 %0, %1\n" // v = f
"lui $8, 0x8000\n" // t0 = 0x80000000
"xor %0, %0, $8\n" // v = v ^ t0
"sltiu %0, %0, 1\n" // v = (v < 1)
".set pop\n"
: "=r"(v)
: "f"(f)
: "$8"
);
return (v);
}
int pspFpuIsDenormal(float f)
{
int v;
asm (
".set push\n"
".set noreorder\n"
"mfc1 $8, %1\n" // t0 = f
"lui $9, 0x7F80\n" // t1 = 0x7F800000
"or %0, $8, $9\n" // v = t0 | t1 = t0 | 0x7F800000
"and $9, $8, $9\n" // t1 = t0 & t1 = t0 & 0x7F800000
"sra %0, %0, 30\n" // v = v>>30 = (t0>=0) ? +1 : -1
"sll $8, $8, 9\n" // t0 = t0<<9
"movn %0, $0, $9\n" // v = (t1!=0) ? 0 : v if (exp!=0) is not denormal number
"movz %0, $0, $8\n" // v = (t0==0) ? 0 : v if (frac==0) is not decnormal number
".set pop\n"
: "=r"(v)
: "f"(f)
: "$8", "$9"
);
return (v);
}
int pspFpuIsZeroOrDenormal(float f)
{
int v;
asm (
".set push\n"
".set noreorder\n"
"mfc1 $8, %1\n" // t0 = f
"lui $9, 0x7F80\n" // t1 = 0x7F800000
"or %0, $8, $9\n" // v = t0 | t1 = t0 | 0x7F800000
"and $9, $8, $9\n" // t1 = t0 & t1 = t0 & 0x7F800000
"sra %0, %0, 30\n" // v = v>>30 = (t0>=0) ? +1 : -1
"movn %0, $0, $9\n" // v = (t1!=0) ? 0 : v if (exp!=0) is not denormal number
".set pop\n"
: "=r"(v)
: "f"(f)
: "$8", "$9"
);
return (v);
}
float pspFpuPositiveInf(void)
{
float v;
asm (
".set push\n"
".set noreorder\n"
"lui $8, 0x7F80\n" // t0 = 0x7F800000
"mtc1 $8, %0\n" // v = t0 = +Infinity
".set pop\n"
: "=f"(v)
:
: "$8"
);
return (v);
}
float pspFpuNegativeInf(void)
{
float v;
asm (
".set push\n"
".set noreorder\n"
"lui $8, 0xFF80\n" // t0 = 0xFF800000
"mtc1 $8, %0\n" // v = t0 = -Infinity
".set pop\n"
: "=f"(v)
);
return (v);
}
int pspFpuIsInf(float f)
{
int v;
asm (
".set push\n"
".set noreorder\n"
"mfc1 $8, %1\n" // t0 = f
"sll $9, $8, 1\n" // t1 = t0<<1
"sra %0, $8, 30\n" // v = t0>>30
"srl $9, $9, 24\n" // t1 = t1>>24
"sll $8, $8, 9\n" // t0 = t0<<9
"ori %0, %0, 0x0001\n" // v = v | 0x00000001 = (f>=0) ? +1 : -1
"sltiu $9, $9, 0x00FF\n" // t1 = (t1<0xFF)
"movn %0, $0, $8\n" // v = (t0!=0) ? 0 : v if (frac!=0) is not Infinity
"movn %0, $0, $9\n" // v = (t1!=0) ? 0 : v if (exp!=0xFF) is not Infinity
".set pop\n"
: "=r"(v)
: "f"(f)
: "$8", "$9"
);
return (v);
}
float pspFpuPositiveNaN(void)
{
float v;
asm (
".set push\n"
".set noreorder\n"
"lui $8, 0x7F80\n"
"ori $8, $8, 0x0001\n" // t0 = 0x7F800001
"mtc1 $8, %0\n" // v = t0 = +SNaN(0x000001)
".set pop\n"
: "=f"(v)
:
: "$8"
);
return (v);
}
float pspFpuNegativeNaN(void)
{
float v;
asm (
".set push\n"
".set noreorder\n"
"lui $8, 0xFF80\n"
"ori $8, $8, 0x0001\n" // t0 = 0xFF800001
"mtc1 $8, %0\n" // v = t0 = -SNaN(0x000001)
".set pop\n"
: "=f"(v)
:
: "$8"
);
return (v);
}
float pspFpuPositiveQNaN(void)
{
float v;
asm (
".set push\n"
".set noreorder\n"
"lui $8, 0x7FC0\n" // t0 = 0x7FC00000
"mtc1 $8, %0\n" // v = t0 = +QNaN
".set pop\n"
: "=f"(v)
:
: "$8"
);
return (v);
}
float pspFpuNegativeQNaN(void)
{
float v;
asm (
".set push\n"
".set noreorder\n"
"lui $8, 0xFFC0\n" // t0 = 0xFFC00000
"mtc1 $8, %0\n" // v = t0 = -QNaN
".set pop\n"
: "=f"(v)
:
: "$8"
);
return (v);
}
float pspFpuPositiveSNaN(unsigned int uiSignal)
{
float v;
asm (
".set push\n"
".set noreorder\n"
"addiu $9, $0, 1\n" // t1 = 0x00000001
"ext $8, %1, 0, 22\n" // t0 = uiSignal & 0x003FFFFF
"movn $9, $8, $8\n" // t1 = (t0!=0) ? t0 : t1
"lui $8, 0x7F80\n" // t0 = 0x7F800000
"or $9, $9, $8\n" // t1 = t1 | t0
"mtc1 $9, %0\n" // v = t1
".set pop\n"
: "=f"(v)
: "r"(uiSignal)
: "$8", "$9"
);
return (v);
}
float pspFpuNegativeSNaN(unsigned int uiSignal)
{
float v;
asm (
".set push\n"
".set noreorder\n"
"addiu $9, $0, 1\n" // t1 = 0x00000001
"ext $8, %1, 0, 22\n" // t0 = uiSignal & 0x003FFFFF
"movn $9, $8, $8\n" // t1 = (t0!=0) ? t0 : t1
"lui $8, 0xFF80\n" // t0 = 0xFF800000
"or $9, $9, $8\n" // t1 = t1 | t0
"mtc1 $9, %0\n" // v = t1
".set pop\n"
: "=f"(v)
: "r"(uiSignal)
: "$8", "$9"
);
return (v);
}
int pspFpuIsNaN(float f)
{
int v;
asm (
".set push\n"
".set noreorder\n"
"lui %0, 0x807F\n" //
"mfc1 $8, %1\n" // t0 = f
"ori %0, %0, 0xFFFF\n" // v = 0x807FFFFF
"sll $9, $8, 1\n" // t1 = t0<<1
"and %0, %0, $8\n" // v = v & t0
"srl $9, $9, 24\n" // t1 = t1>>24
"sll $8, $8, 9\n" // t0 = t0<<9
"sltiu $9, $9, 0x00FF\n" // t1 = (t1<0xFF)
"movz %0, $0, $8\n" // v = (t0==0) ? 0 : v if (frac==0) is not NaN
"movn %0, $0, $9\n" // v = (t1!=0) ? 0 : v if (exp!=0xFF) is not NAN
".set pop\n"
: "=r"(v)
: "f"(f)
: "$8", "$9"
);
return (v);
}
int pspFpuIsInfOrNaN(float f)
{
int v;
asm (
".set push\n"
".set noreorder\n"
"mfc1 %0, %1\n" // v = f
"sll $8, %0, 1\n" // t0 = v<<1
"sra %0, %0, 30\n" // v = v>>30
"srl $8, $8, 24\n" // t0 = t0>>24
"ori %0, %0, 0x0001\n" // v = v | 0x00000001 = (f>=0) ? +1 : -1
"sltiu $8, $8, 0x00FF\n" // t0 = (t0<0xFF)
"movn %0, $0, $8\n" // v = (t0!=0) ? 0 : v if (exp!=0xFF) is neither NAN nor Infinity
".set pop\n"
: "=r"(v)
: "f"(f)
: "$8"
);
return (v);
}
float pspFpuNormalizePhase(float fs)
{
const float f2pi = PSP_MATH_TWOPI;
float fd;
asm (
".set push\n"
".set noreorder\n"
"mfc1 $9, %1\n" // t1 = f0
"div.s $f0, $f0, %2\n" // f0 = f0 / f2pi = fs / 2PI
"round.w.s $f0, $f0\n" // f0 = (int)(f0+0.5)
"cvt.s.w $f0, $f0\n" // f0 = float(f0)
"mul.s $f0, $f0, %2\n" // f0 = f0 * f2pi = fd * 2PI
"sub.s %0, %1, $f0\n" // fd = fs - f0 = fs - (fd * 2PI)
".set pop\n"
: "=f"(fd)
: "f"(fs), "f"(f2pi)
: "$f0", "$8", "$9"
);
return (fd);
}
float pspFpuLog(float x)
{
union {
float f;
int i;
} fi;
int a, b, exponent;
float y, z;
fi.f = x;
if (fi.i <= 0) {
if ((fi.i & 0x7fffffff) == 0) {
fi.i = 0xff800000; /* -INF */
return fi.f;
}
fi.i = 0xff80ffff; /* Quiet NaN */
return fi.f;
}
b = (fi.i & 0x007fffff);
a = b - (1<<23);
exponent = fi.i;
if (b <= 0x3504F3) {
a = b;
b = b - (1 << 23);
exponent -= (1<<23);
}
b = b - (1 << 23) + (1<<25);
x = (float)(a) / (float)(b);
z = (((exponent>>23)-126) * 0xB17218) * (float)(1.0/(1<<24));
y = x * x;
return z + x * (((logPoly[2] * y + logPoly[1]) * y) + logPoly[0]);
}
float pspFpuExp(float x)
{
/*
* exp(x)=e^x=e^(y * log2)=2^Y
* =2^z * 2^y
* =2^z * (2^(y/2))^2
* =2^z * (e^(f/2))^2
* =2^z * (e^(f/4))^4
* where y=x/log 2
* z=nearest(y) , -0.5 <= f=y-z < 0.5
*/
union {
float f;
int i;
} fi;
float z, f;
fi.f = x;
fi.i &= 0x7fffffff;
if (fi.i >= 0x42b00f34) {/* arround 88.03 */
/* overflow */
if (x != x) {
return x; /* NaN */
}
if (fi.i < 0) {
return 0.0; /* underflow */
}
fi.i = 0x7f800000;
return fi.f; /* +INF */
}
f = fi.f * (float)PSP_MATH_LOG2E;
z = __builtin_allegrex_round_w_s(f);
f = f-z;
fi.i = z;
if (x < 0)
fi.i = -fi.i;
fi.i = (fi.i+127) << 23;
/* use Pade aprox. */
f = (6.0f + (float)(4.0*PSP_MATH_LN2 * 0.25)*f
+ (float)(0.9996*PSP_MATH_LN2*0.25*PSP_MATH_LN2*0.25)*f*f)
/ (6.0f - (float)(2.0*PSP_MATH_LN2 * 0.25)*f);
f *= f;
fi.f *= f*f;
return fi.f;
}
static float _pspFpuSinMain(float x)
{
float y = x*x;
return x * (((triPoly[4] * y
+ triPoly[3]) * y
+ triPoly[2]) * y
+ triPoly[1]);
}
static float _pspFpuCosMain(float x)
{
float y = x*x;
return ((triPoly[7] * y
+ triPoly[6]) * y
+ triPoly[5]) * y
+ triPoly[1];
}
static float _pspFpuAtanMain(float x)
{
float y = x*x;
return x * (((triPoly[10] * y
+ triPoly[9]) * y
+ triPoly[8]) * y
+ triPoly[1]);
}
float pspFpuSin(float x)
{
float pi2;
int sign = 1;
/* NaN */
if (x != x) {
return x;
}
pi2 = triPoly[0];
if (x < 0.0f) {
sign = -1;
x = -x;
}
if (x > pi2) {
float y = x / pi2;
x -= (float)((int)y) * pi2;
}
pi2 *= 0.5f;
if (x > pi2) {
x -= pi2;
sign = -sign;
}
if (x > pi2*0.5f) {
x = pi2 - x;
}
if (x > (float)(PSP_MATH_PI * (0.5 - COS_SIN_DIV))) {
return _pspFpuCosMain(pi2*0.5f - x) * sign;
}
return _pspFpuSinMain(x) * sign;
}
float pspFpuCos(float x)
{
float pi2;
int sign = 1;
/* NaN */
if (x != x) {
return x;
}
pi2 = triPoly[0];
if (x < 0.0f) {
x = -x;
}
if (x > pi2) {
float y = x / pi2;
x -= (float)((int)y) * pi2;
}
pi2 *= 0.5f; // pi2 = PI
if (x > pi2) {
x -= pi2;
sign = -1;
}
if (x > pi2*0.5f) {
sign = -sign;
x = pi2 - x;
}
if (x > (float) (PSP_MATH_PI * COS_SIN_DIV)) {
return _pspFpuSinMain(pi2*0.5f - x) * sign;
}
return _pspFpuCosMain(x) * sign;
}
static float _atanf(float x)
{
if (x < 0.19890f) {
return _pspFpuAtanMain(x);
}
if (x < 0.668106f) {
return (float)(PSP_MATH_PI / 8)
+ _pspFpuAtanMain((x - (float)(PSP_MATH_SQRT2 - 1)) / (1.0f + ((float)(PSP_MATH_SQRT2 - 1)*x)));
}
return ((float)PSP_MATH_PI / 4) + _pspFpuAtanMain((x - 1.0f) / (x + 1.0f));
}
float pspFpuAtan(float x)
{
int sign = 1;
/* NaN */
if (x != x) {
return x;
}
if (x < 0.0f) {
x = -x;
sign = -1;
}
if (x >= 1.0f) {
/*J atan(x) = pi/2 - atan(1/x) */
x = 1.0f / x;
x = ((float)(PSP_MATH_PI / 2)) - _atanf(x);
} else {
x = _atanf(x);
}
return x * (float)sign;
}
float pspFpuAsin(float x)
{
x = x*x;
return pspFpuAtan(__builtin_allegrex_sqrt_s(x/(1.0f-x)));
}
float pspFpuAcos(float x)
{
x = x*x;
return pspFpuAtan(__builtin_allegrex_sqrt_s((1.0f-x)/x));
}

View File

@@ -5,7 +5,8 @@
*
* pspfpu.h - Prototypes for the FPU library
*
* Copyright (c) 2006 TyRaNiD (James F.)
* Copyright (c) 2009 JetCube
* Copyright (c) 2006 TyRaNiD (James F.)
*
* $Id: pspfpu.h 1782 2006-02-04 12:57:05Z tyranid $
*/
@@ -23,131 +24,131 @@ extern "C" {
#endif
/** Enumeration for FPU rounding modes */
enum FpuRoundMode
enum PspFpuRoundMode
{
/** Round to nearest representable value */
FPU_RN = 0,
PSP_FPU_RN = 0,
/** Round towards zero */
FPU_RZ = 1,
PSP_FPU_RZ = 1,
/** Round towards plus infinity */
FPU_RP = 2,
/** Round towards minus infinity */
FPU_RM = 3,
PSP_FPU_RP = 2,
/** Round towards minus infinity */
PSP_FPU_RM = 3,
};
/** Mask value for rounding mode */
#define FPU_RM_MASK 0x03
#define PSP_FPU_RM_MASK 0x03
/** Enumeration for FPU exceptions */
enum FpuExceptions
enum PspFpuExceptions
{
/** Inexact operation exception */
FPU_EXCEPTION_INEXACT = 0x01,
PSP_FPU_EXCEPTION_INEXACT = 0x01,
/** Underflow exception */
FPU_EXCEPTION_UNDERFLOW = 0x02,
PSP_FPU_EXCEPTION_UNDERFLOW = 0x02,
/** Overflow exception */
FPU_EXCEPTION_OVERFLOW = 0x04,
PSP_FPU_EXCEPTION_OVERFLOW = 0x04,
/** Division by zero exception */
FPU_EXCEPTION_DIVBYZERO = 0x08,
PSP_FPU_EXCEPTION_DIVBYZERO = 0x08,
/** Invalid operation exception */
FPU_EXCEPTION_INVALIDOP = 0x10,
PSP_FPU_EXCEPTION_INVALIDOP = 0x10,
/** Unimplemented operation exception (only supported in the cause bits) */
FPU_EXCEPTION_UNIMPOP = 0x20,
PSP_FPU_EXCEPTION_UNIMPOP = 0x20,
/** All exceptions */
FPU_EXCEPTION_ALL = 0x3F
PSP_FPU_EXCEPTION_ALL = 0x3F
};
/** Bit position of the flag bits */
#define FPU_FLAGS_POS 2
#define PSP_FPU_FLAGS_POS 2
/** Bit position of the enable bits */
#define FPU_ENABLE_POS 7
#define PSP_FPU_ENABLE_POS 7
/** Bit position of the cause bits */
#define FPU_CAUSE_POS 12
#define PSP_FPU_CAUSE_POS 12
/** Bit position of the cc0 bit */
#define FPU_CC0_POS 23
#define PSP_FPU_CC0_POS 23
/** Bit position of the fs bit */
#define FPU_FS_POS 24
#define PSP_FPU_FS_POS 24
/** Bit position of the cc1->7 bits */
#define FPU_CC17_POS 25
#define PSP_FPU_CC17_POS 25
#define FPU_FLAGS_MASK (0x1F << FPU_FLAGS_POS)
#define FPU_ENABLE_MASK (0x1F << FPU_ENABLE_POS)
#define FPU_CAUSE_MASK (0x3F << FPU_CAUSE_POS)
#define FPU_CC0_MASK (1 << FPU_CC0_POS)
#define FPU_FS_MASK (1 << FPU_FS_POS)
#define FPU_CC17_MASK (0x7F << FPU_CC17_POS)
#define PSP_FPU_FLAGS_MASK (0x1F << PSP_FPU_FLAGS_POS)
#define PSP_FPU_ENABLE_MASK (0x1F << PSP_FPU_ENABLE_POS)
#define PSP_FPU_CAUSE_MASK (0x3F << PSP_FPU_CAUSE_POS)
#define PSP_FPU_CC0_MASK (1 << PSP_FPU_CC0_POS)
#define PSP_FPU_FS_MASK (1 << PSP_FPU_FS_POS)
#define PSP_FPU_CC17_MASK (0x7F << PSP_FPU_CC17_POS)
/**
* Get the current value of the control/status register
*
* @return The value of the control/status register
*/
uint32_t pspfpu_get_fcr31(void);
uint32_t pspFpuGetFCR31(void);
/**
* Set the current value of the control/status register
*
* @param var - The value to set.
*/
void pspfpu_set_fcr31(uint32_t var);
void pspFpuSetFCR31(uint32_t var);
/**
* Set the current round mode
*
* @param mode - The rounding mode to set, one of ::FpuRoundMode
* @param mode - The rounding mode to set, one of ::PspFpuRoundMode
*/
void pspfpu_set_roundmode(enum FpuRoundMode mode);
void pspFpuSetRoundmode(enum PspFpuRoundMode mode);
/**
* Get the current round mode
*
* @return The round mode, one of ::FpuRoundMode
* @return The round mode, one of ::PspFpuRoundMode
*/
enum FpuRoundMode pspfpu_get_roundmode(void);
enum PspFpuRoundMode pspFpuGetRoundmode(void);
/**
* Get the exception flags (set when an exception occurs but
* the actual exception bit is not enabled)
*
* @return Bitmask of the flags, zero or more of ::FpuExceptions
* @return Bitmask of the flags, zero or more of ::PspFpuExceptions
*/
uint32_t pspfpu_get_flags(void);
uint32_t pspFpuGetFlags(void);
/**
/**
* Clear the flags bits
*
* @param clear - Bitmask of the bits to clear, one or more of ::FpuExceptions
* @param clear - Bitmask of the bits to clear, one or more of ::PspFpuExceptions
*/
void pspfpu_clear_flags(uint32_t clear);
void pspFpuClearFlags(uint32_t clear);
/**
* Get the exception enable flags
*
* @return Bitmask of the flags, zero or more of ::FpuExceptions
* @return Bitmask of the flags, zero or more of ::PspFpuExceptions
*/
uint32_t pspfpu_get_enable(void);
uint32_t pspFpuGetEnable(void);
/**
/**
* Set the enable flags bits
*
* @param enable - Bitmask of exceptions to enable, zero or more of ::FpuExceptions
* @param enable - Bitmask of exceptions to enable, zero or more of ::PspFpuExceptions
*/
void pspfpu_set_enable(uint32_t enable);
void pspFpuSetEnable(uint32_t enable);
/**
* Get the cause bits (only useful if you installed your own exception handler)
*
* @return Bitmask of flags, zero or more of ::FpuExceptions
* @return Bitmask of flags, zero or more of ::PspFpuExceptions
*/
uint32_t pspfpu_get_cause(void);
uint32_t pspFpuGetCause(void);
/**
* Clear the cause bits
*
* @param clear - Bitmask of the bits to clear, one or more of ::FpuExceptions
* @param clear - Bitmask of the bits to clear, one or more of ::PspFpuExceptions
*
*/
void pspfpu_clear_cause(uint32_t clear);
void pspFpuClearCause(uint32_t clear);
/**
* Get the current value of the FS bit (if FS is 0 then an exception occurs with
@@ -155,28 +156,253 @@ void pspfpu_clear_cause(uint32_t clear);
*
* @return The current state of the FS bit (0 or 1)
*/
uint32_t pspfpu_get_fs(void);
uint32_t pspFpuGetFS(void);
/**
* Set the FS bit
*
* @param fs - 0 or 1 to unset or set fs
*/
void pspfpu_set_fs(uint32_t fs);
void pspFpuSetFS(uint32_t fs);
/**
* Get the condition flags (8 bits)
*
* @return The current condition flags
*/
uint32_t pspfpu_get_condbits(void);
uint32_t pspFpuGetCondbits(void);
/**
* Clear the condition bits
*
* @param clear - Bitmask of the bits to clear
*/
void pspfpu_clear_condbits(uint32_t clear);
void pspFpuClearCondbits(uint32_t clear);
/**
* returns absolute value
*/
float pspFpuAbs(float f);
/**
* Round up
*/
int pspFpuCeil(float f);
/**
* Truncate
*/
int pspFpuFloor(float f);
/**
* select maximum value
*/
float pspFpuMax(float f1, float f2);
/**
* select minimum value
*/
float pspFpuMin(float f1, float f2);
/**
* Sign reversal
*/
float pspFpuNeg(float f);
/**
* Round to nearest
*/
int pspFpuRound(float f);
/*
* Reciprocal of square root
*/
float pspFpuRsqrt(float f);
/**
* Square root
*/
float pspFpuSqrt(float f);
/**
* Round towards zero
*/
int pspFpuTrunc(float f);
/**
*
*/
float pspFpuFmod(float fs, float fd);
/**
*
*/
float pspFpuFrac(float f);
/**
*
*/
float pspFpuReinterpretFloat(uint32_t ui);
/**
*
*/
uint32_t pspFpuReinterpretUint(float f);
/**
*
*/
int pspFpuIsEqual(float f1, float f2);
/**
*
*/
float pspFpuSignFloat(float f);
/**
*
*/
int pspFpuSignInt(float f);
/**
* Positive zero
*/
float pspFpuPositiveZero(void);
/**
* Negative zero
*/
float pspFpuNegativeZero(void);
/**
* Test for zero value
*/
int pspFpuIsZero(float f);
/**
* Test for positive zero
*/
int pspFpuIsPositiveZero(float f);
/**
* Test for negative zero
*/
int pspFpuIsNegativeZero(float f);
/**
* Test for denormalized number
*/
int pspFpuIsDenormal(float f);
/**
* Test for zero or denormalized number
*/
int pspFpuIsZeroOrDenormal(float f);
/**
* Positive infinity
*/
float pspFpuPositiveInf(void);
/**
* Negative infinity
*/
float pspFpuNegativeInf(void);
/**
* Test for infinity
*/
int pspFpuIsInf(float f);
/**
* NaN (positive SNaN)
*/
float pspFpuPositiveNaN(void);
/**
* NaN (negative SNaN)
*/
float pspFpuNegativeNaN(void);
/**
* Quiet NaN (positive QNaN)
*/
float pspFpuPositiveQNaN(void);
/**
* Quiet NaN (positive QNaN)
*/
float pspFpuNegativeQNaN(void);
/**
* Signaling NaN (positive SNaN)
*/
float pspFpuPositiveSNaN(unsigned int uiSignal);
/**
* Signaling NaN (negative SNaN)
*/
float pspFpuNegativeSNaN(unsigned int uiSignal);
/**
* Test for NaN
*/
int pspFpuIsNaN(float f);
/**
* Test for infinity or NaN
*/
int pspFpuIsInfOrNaN(float f);
/**
*
*/
float pspFpuNormalizePhase(float f);
/**
* Sine
*/
float pspFpuSin(float x);
/**
* Cosine
*/
float pspFpuCos(float x);
/**
* Arc tangent
*/
float pspFpuAtan(float x);
/**
* Natural Logarithm
*/
float pspFpuLog(float x);
/**
* Exponential
*/
float pspFpuExp(float x);
/**
* ArcSin
*/
float pspFpuAsin(float x);
/**
* ArcCos
*/
float pspFpuAcos(float x);
/**
* convert float to double
*/
double pspFpuFloatToDouble(float a);
/**
* convert double to float
*/
float pspFpuDoubleToFloat(double a);
#ifdef __cplusplus
}