 |
forums.ps2dev.org Homebrew PS2, PSP & PS3 Development Discussions
|
| View previous topic :: View next topic |
| Author |
Message |
onne
Joined: 29 Aug 2006 Posts: 24
|
Posted: Sun Dec 31, 2006 1:00 am Post subject: Conditionals with VFPU? |
|
|
Hi...
I've been doing basic VFPU stuff for my renderer... But now I'd need some additional complexity, ie. conditions...
Here's my visibility check function, but I'm not sure if the condition check for the division by zero (The seperated part where I break the assembly and inset c++ in between...) could be done more efficiently or more nicely :)
...of course other optimization ideas are welcome as well.
| Code: |
...
float length(0.0);
__asm__ volatile (
//Load Triangles
"ulv.q R100, 0x0(%1)\n" //vert1
"ulv.q R101, 0x0(%2)\n" //vert2
"ulv.q R102, 0x0(%3)\n" //vert3
"ulv.q R103, 0x0(%4)\n" //iViewVector
//make vectors from vertices
"vsub.t R100, R100, R101\n"
"vsub.t R101, R101, R102\n"
//cross to get normal
"vcrsp.t R200, R100, R101\n"
//length...:
"vmul.t R100, R200, R200\n"
"vadd.s S100, S100, S110\n"
"vadd.s S100, S100, S120\n"
//---------------------------------------------------
//Conditional start
//---------------------------------------------------
"mfv %0, S100\n"
: "=r" (length) : "r" (aVertex1), "r" (aVertex2), "r" (aVertex3), "r" (&iViewVector)
);
//CONDITION to prevent division by zero
if(0.0 != length)
{
//---------------------------------------------------
//Conditional end
//---------------------------------------------------
__asm__ volatile ([/b]
// 1/sqrt
"vrsq.s S100, S100\n"
//normalize
"vscl.t R200, R200, S100\n"
//Determine the angle between
"vdot.t S200, R200, R103\n"
//Return
"usv.s S200, 0x0(%0)\n"
: : "r" (aReturnValue)
);
}
else
{
*aReturnValue = 0.0;
}
...
|
|
|
| Back to top |
|
 |
siberianstar
Joined: 22 Jun 2006 Posts: 70
|
Posted: Sun Dec 31, 2006 3:23 am Post subject: |
|
|
| That's going to be slower than not using vfpu. It's better you use vfpu there only to calc rsq. |
|
| Back to top |
|
 |
onne
Joined: 29 Aug 2006 Posts: 24
|
Posted: Sun Dec 31, 2006 3:51 am Post subject: |
|
|
Ok... hmm.
So are you saying there are no comparison operators which with I could check if the content of S100 (in this case) is 0, and branch accordingly?
Yep, if that is the case, then it must be better of doing the part before the "Condition start" without VFPU.
thanks. |
|
| Back to top |
|
 |
swetland
Joined: 31 Dec 2006 Posts: 5 Location: Mountain View, CA
|
Posted: Sun Dec 31, 2006 6:46 am Post subject: |
|
|
MIPS has reference manuals for their architectures available online:
http://www.mips.com/products/resource_library/product_materials/MIPS_Architecture.php
You do have to fill out a little form to get a login before you can download them, but it's pretty painless.
These two documents will probably answer most of your MIPS assembly questions:
MIPS32® Architecture for Programmers Volume I: Introduction to the MIPS32® Architecture (.pdf)
MIPS32® Architecture for Programmers Volume II: The MIPS32® Instruction Set (.pdf)
Brian |
|
| Back to top |
|
 |
Tinnus
Joined: 29 Jul 2006 Posts: 67
|
Posted: Sun Dec 31, 2006 7:41 am Post subject: |
|
|
Yeah, since you depend solely on a S*** register you can just mfv it to a GPR and do the branching there with regular MIPS assembly. mfv takes 1 cycle IIRC and shouldn't be a speed problem...
edit: although gcc is probably already doing that for you. Check the generated .s file to see what the compiler produced... _________________ Let's see what the PSP reserves... well, I'd say anything is better than Palm OS. |
|
| Back to top |
|
 |
onne
Joined: 29 Aug 2006 Posts: 24
|
Posted: Sun Dec 31, 2006 10:33 am Post subject: |
|
|
Thanks, everyone... yep, I digged up the R4400 uman book... makes it easier. heh.
Although, as you said Tinnus, gcc is already doing a good job on this simple case. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Sun Dec 31, 2006 10:39 am Post subject: |
|
|
| onne wrote: | Ok... hmm.
So are you saying there are no comparison operators which with I could check if the content of S100 (in this case) is 0, and branch accordingly?
Yep, if that is the case, then it must be better of doing the part before the "Condition start" without VFPU.
thanks. |
There ARE VFPU comparison operators. It is just that we (Raphael and I) don't really try them to discover which flags cc are to used for each comparison operator.
comparisons are :
| Code: |
vcmp.q/t/p/s cn, vt, vs // where cn == EQ/NE/LE/LT/GE/GT
{
CC[cc] = BOPcn(vt, vs); // we guess it is something like that
}
vcmp.q/t/p/s cc, vs // where cn == EZ/EN/EI/ES/NZ/NI/NS
{
CC[cc] = UOPcn(vs); // we guess it is something like that
}
vcmp.q/t/p/s cc // where cn == TR/FL
{
CC[cc] = cn == TR; // we guess it is something like that
}
bvf cc, label <=> exec next insn; if (CC[cc] == 0) goto label;
bvt cc, label <=> exec next insn; if (CC[cc] != 0) goto label;
bvfl cc, label <=> if (CC[cc] == 0) { exec next insn; goto label; }
bvtl cc, label <=> if (CC[cc] != 0) { exec next insn; goto label; }
example :
vcmp.s LT, s000, s001 -> CC[0] = s000 < s001
bvt 0, 0f -> if (CC[0] == 0) s000 += s001;
vnop
vadd.s s000, s001, s000
0f:
...
b(ranch)v(ector)f(alse)
b(ranch)v(ector)t(rue)
b(ranch)v(ector)f(alse)l(ikely)
b(ranch)v(ector)t(rue)l(ikely)
|
I must admit that the link between cc and cn (condition name) is unclear for me.
LT, LE seems to use cc = 0
EQ seems to use cc = 5
i let you to test them :
| Code: |
vzero.s s003
vcmp.s EQ, s000, s003
bvt 5, 0f
vnop
... // your computation when s000 != 0
0:
... // your computation when s000 == 0
|
|
|
| Back to top |
|
 |
onne
Joined: 29 Aug 2006 Posts: 24
|
Posted: Tue Jan 02, 2007 8:37 pm Post subject: |
|
|
Hlide, thanks for your information... yep, it is logical to have some comparison operators for vfpu as well.
Oh, and the piece of code you suggested works nicely... thanks again. I guess one can get pretty far with the mentioned EQ, LT and LE anyway. If I have time I can try to examine other cc's... |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Tue Jan 02, 2007 10:27 pm Post subject: |
|
|
ok, i think i found out how to use vfpu cc :
we have a VFPU control register ($131, VFPU_CC) which contains the last comparison flags which seems to work this way :
VFPU_CC:
bit 0 : comparison on component X is true (works with vcmp.q/t/p/s)
bit 1 : comparison on component Y is true (only works with vcmp.q/t/p)
bit 2 : comparison on component Z is true (only works with vcmp.q/t)
bit 3 : comparison on component W is true (only works with vcmp.q)
bit 4 : bit 0 == 1 or bit 1 == 1 or bit 2 == 1 or bit 3 == 1
bit 5 : bit 0 == 1 and bit 1 == 1 and bit 2 == 1 and bit 3 == 1
bit 6-31 : 0
so my guess (i didn't try it but i'm quite sure about it):
if you want to check if all components of r000 and r001 equal, use cc = 5 :
vcmp.q EQ, r000, r001
...
bvf 5, skip
...
if you want to check if at least one component of r000 and r001 equals, use cc = 4 :
vcmp.q EQ, r000, r001
...
bvf 4, skip
...
if you want to check if component X of r000 and r001 equals regardless the other omponents, use cc = 0 :
vcmp.q EQ, r000, r001
...
bvf 0, skip
...
if you want to check if component Y of r000 and r001 equals regardless the other omponents, use cc = 1 :
vcmp.q EQ, r000, r001
...
bvf 1, skip
...
etc. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Tue Jan 02, 2007 11:27 pm Post subject: |
|
|
| onne wrote: | Hlide, thanks for your information... yep, it is logical to have some comparison operators for vfpu as well.
Oh, and the piece of code you suggested works nicely... thanks again. I guess one can get pretty far with the mentioned EQ, LT and LE anyway. If I have time I can try to examine other cc's... |
thx
i think what you need is probably the following one indeed :
| Code: |
__asm__ volatile (
...
"vcmp.s EZ, s100\n" // s100 != 0.0
"bvtl 0, 0f\n"
"sw $0, %5\n" // *aReturnValue = 0.0 if s100 != 0.0!
... // you computation when s100 != 0.0
"usv.s s200, %5\n"
"0:\n"
... "m"(aReturnValue));
|
or
| Code: |
__asm__ volatile (
...
"vcmp.s LT, s100[|x|], s003\n" // |s100| < epsilon
"bvtl 0, 0f\n"
"sw $0, %5\n" // *aReturnValue = 0.0 if |s100| < epsilon !
... // you computation when s100 != 0.0
"usv.s s200, %5\n"
"0:\n"
... "m"(aReturnValue));
|
where s003 must contain a float representing epsilon.
Last edited by hlide on Fri Jan 05, 2007 11:40 pm; edited 2 times in total |
|
| Back to top |
|
 |
siberianstar
Joined: 22 Jun 2006 Posts: 70
|
Posted: Tue Jan 02, 2007 11:29 pm Post subject: |
|
|
| this is very useful |
|
| Back to top |
|
 |
onne
Joined: 29 Aug 2006 Posts: 24
|
Posted: Wed Jan 03, 2007 11:39 am Post subject: |
|
|
Wow, nice findings! Yep, it only seemed to work since I had set the other values to zero as well... :) And, yes I did some calc before the conditional jump as well...
Now, today I realized(after debugging the VFPU register values in different phases) that instead of having values going to _zero_ I seem to get values going to _infinity_... dough!
It could be though that I have a failure in my dataset... have to check that one too.
EDIT:
ok... I had some problems with my data, but now it seems to work better. But I keep wondering what do all the possible condition names mean? I tried to test them my self, but some of them seem weird. Any ideas for the ones with question marks?
FL - false
TR - true
EQ - equals
NE - not equal
LT - less than
LE - less or equal
GE - greater or equal
GT - greater than
EZ - vs == 0
NZ - vs != 0
EN - ??? false ???
NN - ??? true ???
EI - vs == Inf
NI - vs != Inf
ES - same as EI (or...???)
NS - same as NI (or...???)
EDIT: See hlide's better explanation abount the conditions below...
Last edited by onne on Sat Jan 06, 2007 12:22 am; edited 1 time in total |
|
| Back to top |
|
 |
onne
Joined: 29 Aug 2006 Posts: 24
|
Posted: Thu Jan 04, 2007 2:06 pm Post subject: |
|
|
And here is the working piece of code...
(although I couldn't get the bvtl work as I wanted... ie. I would have liked to replace the "vnop" with "vzero.s S530")
| Code: | __asm__ volatile (
//Load Triangles
"ulv.q R400, 0x0(%1)\n" //vert1
"ulv.q R401, 0x0(%2)\n" //vert2
"ulv.q R402, 0x0(%3)\n" //vert3
"ulv.q R403, 0x0(%4)\n" //iViewVector
//make vectors from vertices
"vsub.t R500, R400, R401\n"
"vsub.t R501, R401, R402\n"
//cross to get normal
"vcrsp.t R500, R500, R501\n"
//calculate 1/length
"vmul.t R400, R500, R500\n"
"vadd.s S400, S400, S410\n"
"vadd.s S400, S400, S420\n"
"vrsq.s S400, S400\n"
//Is valid result? (ie. not NaN or Inf)
"vzero.s S530\n"
"vcmp.s EI, S400\n"
"bvt 0, 0f\n"
"vnop\n"
//normalize with 1/length
"vscl.t R500, R500, S400\n"
//Determine the angle between
"vdot.t S530, R500, R403\n"
//Return
"0:\n"
"usv.s S530, 0x00(%0)\n"
: : "r" (aReturnValue), "r" (aVertex1), "r" (aVertex2), "r" (aVertex3), "r" (&iViewVector)
);
|
Last edited by onne on Thu Jan 04, 2007 9:33 pm; edited 1 time in total |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Thu Jan 04, 2007 4:31 pm Post subject: |
|
|
bvtl doesn't work !?
you can at least replace vnop with vzero.s S530
and use bvt if bvtl doesn't work (computation is not what you expect ?)
| Code: | __asm__ volatile (
//Load Triangles
"ulv.q R400, 0x0(%1)\n" //vert1
"ulv.q R401, 0x0(%2)\n" //vert2
"ulv.q R402, 0x0(%3)\n" //vert3
"ulv.q R403, 0x0(%4)\n" //iViewVector
//make vectors from vertices
"vsub.t R500, R400, R401\n"
"vsub.t R501, R401, R402\n"
//cross to get normal
"vcrsp.t R500, R500, R501\n"
//calculate 1/length
"vmul.t R400, R500, R500\n"
"vadd.s S400, S400, S410\n"
"vadd.s S400, S400, S420\n"
"vrsq.s S400, S400\n"
//Is valid result? (ie. not NaN or Inf)
"vcmp.s EI, S400\n"
"bvt 0, 0f\n"
"vzero.s S530\n"
//normalize with 1/length
"vscl.t R500, R500, S400\n"
//Determine the angle between
"vdot.t S530, R500, R403\n"
//Return
"0:\n"
"usv.s S530, 0x00(%0)\n"
: : "r" (aReturnValue), "r" (aVertex1), "r" (aVertex2), "r" (aVertex3), "r" (&iViewVector)
);
|
|
|
| Back to top |
|
 |
onne
Joined: 29 Aug 2006 Posts: 24
|
Posted: Thu Jan 04, 2007 9:21 pm Post subject: |
|
|
Well, in my case it seems that there is no instruction executed after either branch...
This is how I tested:
1. I give as input three identical vectors -> S400 will get a NaN value
| Code: | v1: [-0.184323, 0.000000, 0.730595]
v2: [-0.184323, 0.000000, 0.730595]
v3: [-0.184323, 0.000000, 0.730595]
|
2. I use this code, where the expected result of output(S530) is 1.0 if the instruction after the branch would get executed... With both 'bvt' and 'bvtl', I still get 0.0 as result. (also if the comparison is not done at all, it will give an VFPU exception, when scaling with NaN value.)
| Code: | //Is valid result? (ie. not NaN or Inf)
"vzero.s S530\n"
"vcmp.s EI, S400\n"
"bvt 0, 0f\n"
"vone.s S530\n"
|
...at least I cannot see anything wrong there, and in fact removing the "vnop" doesen't change my functionality either... It is quite weird though. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Fri Jan 05, 2007 5:14 am Post subject: |
|
|
| Code: |
vfpu_inf:
.long 0x7f800000
vfpu_nan:
.long 0x7fffffff
.global me_test_vfpu
me_test_vfpu:
lui at, %hi(vfpu_inf)
lv.s S000, %lo(vfpu_inf)(at)
lv.s S001, %lo(vfpu_nan)(at)
vcmp.s EI, S000
mfvc v0, $131
vnop
andi v0, v0, 1
sb v0, 0x00(a0)
vcmp.s NI, S000
mfvc v0, $131
vnop
andi v0, v0, 1
sb v0, 0x01(a0)
vcmp.s EI, S001
mfvc v0, $131
vnop
andi v0, v0, 1
sb v0, 0x02(a0)
vcmp.s NI, S001
mfvc v0, $131
vnop
andi v0, v0, 1
sb v0, 0x03(a0)
vcmp.s EN, S000
mfvc v0, $131
vnop
andi v0, v0, 1
sb v0, 0x04(a0)
vcmp.s NN, S000
mfvc v0, $131
vnop
andi v0, v0, 1
sb v0, 0x05(a0)
vcmp.s EN, S001
mfvc v0, $131
vnop
andi v0, v0, 1
sb v0, 0x06(a0)
vcmp.s NN, S001
mfvc v0, $131
vnop
andi v0, v0, 1
sb v0, 0x07(a0)
vcmp.s ES, S000
mfvc v0, $131
vnop
andi v0, v0, 1
sb v0, 0x08(a0)
vcmp.s NS, S000
mfvc v0, $131
vnop
andi v0, v0, 1
sb v0, 0x09(a0)
vcmp.s ES, S001
mfvc v0, $131
vnop
andi v0, v0, 1
sb v0, 0x0a(a0)
vcmp.s NS, S001
mfvc v0, $131
vnop
andi v0, v0, 1
sb v0, 0x0b(a0)
jr ra
nop
|
results :
| Code: |
Inf Inf Nan Nan
EI NI EI NI -> 01 01 00 00
EN NN EN NN -> 00 01 01 01
ES NS ES NS -> 00 01 00 01
|
if someone can understand the meaning of EI, NI, EN, NN, ES and NS...
Note : wakeup Raphael !!!
EDIT:
ES and NS may be for plus/minus sign (bit S) |
|
| Back to top |
|
 |
onne
Joined: 29 Aug 2006 Posts: 24
|
Posted: Fri Jan 05, 2007 7:34 am Post subject: |
|
|
That test result seems weird... I am atleast capable of testing if a value is NaN or not with EI and NI.
ie. the following code returns me 1, and if I comment out the vrsq, I will get 0, and the opposite happens with NI
| Code: |
void CondTest( float* aTestResult )
{
__asm__ volatile (
"vzero.s S400\n"
"vrsq.s S400, S400\n" // 1/sqrt(0) = NaN
"vone.s S500\n"
"vcmp.s EI, S400\n"
"vnop\n"
"bvtl 0, 0f\n"
"vnop\n"
"vzero.s S500\n"
"0:\n"
"usv.s S500, 0x0(%0)\n"
: : "r" (aTestResult)
);
}
|
|
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Fri Jan 05, 2007 11:18 am Post subject: |
|
|
by the way, 1/sqrt(0) shouldn't be +inf and not NaN ?
sqrt(0) = 0, no ? so 1/sqrt(0) -> 1/0 -> +inf |
|
| Back to top |
|
 |
onne
Joined: 29 Aug 2006 Posts: 24
|
Posted: Fri Jan 05, 2007 12:25 pm Post subject: |
|
|
| That's what I thought as well, but at least when I do printf("result: %f", conditional );, I get NaN... And also I do get Inf's as well, when such occurs. :) Seems like some of the basic stuff doesn't hold with vfpu maths. (for example as I said above about the conditions, NaN==NaN... even though it shouldn't ) |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Fri Jan 05, 2007 8:21 pm Post subject: |
|
|
IEEE Standard 754 states :
| Quote: |
Storage Layout
IEEE floating point numbers have three basic components: the sign, the exponent, and the mantissa. The mantissa is composed of the fraction and an implicit leading digit (explained below). The exponent base (2) is implicit and need not be stored.
| Code: |
+--------+-----------+------------+------+
| Sign | Exponent | Fraction | Bias |
+--------+-----------+------------+------+
| 1 [31] | 8 [30-23] | 23 [22-00] | 127 |
+--------+-----------+------------+------+
|
Infinity
The values +infinity and -infinity are denoted with an exponent of all 1s and a fraction of all 0s. The sign bit distinguishes between negative infinity and positive infinity. Being able to denote infinity as a specific value is useful because it allows operations to continue past overflow situations. Operations with infinite values are well defined in IEEE floating point.
Not A Number
The value NaN (Not a Number) is used to represent a value that does not represent a real number. NaN's are represented by a bit pattern with an exponent of all 1s and a non-zero fraction. There are two categories of NaN: QNaN (Quiet NaN) and SNaN (Signalling NaN).
A QNaN is a NaN with the most significant fraction bit set. QNaN's propagate freely through most arithmetic operations. These values pop out of an operation when the result is not mathematically defined.
An SNaN is a NaN with the most significant fraction bit clear. It is used to signal an exception when used in operations. SNaN's can be handy to assign to uninitialized variables to trap premature usage.
Semantically, QNaN's denote indeterminate operations, while SNaN's denote invalid operations.
Special Operations
Operations on special numbers are well-defined by IEEE. In the simplest case, any operation with a NaN yields a NaN result. Other operations are as follows:
| Code: |
+---------------------+---------+
|Operation | Result |
+---------------------+---------+
| n ÷ ±Infinity| 0 |
|±Infinity × ±Infinity|±Infinity|
| ±nonzero ÷ 0 |±Infinity|
| Infinity + Infinity | Infinity|
| ±0 ÷ ±0 | NaN |
| Infinity - Infinity | NaN |
|±Infinity ÷ ±Infinity| NaN |
|±Infinity × 0 | NaN |
+---------------------+---------+
|
Summary
To sum up, the following are the corresponding values for a given representation:
| Code: |
Float Values (b = bias)
+------+-----------------+---------------+----------------------------+
| Sign | Exponent (e) | Fraction (f) | Value |
+------+-----------------+---------------+----------------------------+
| 0 | 00..00 | 00..00 | +0 |
+------+-----------------+---------------+----------------------------+
| 0 | 00..00 | 00..01 | Positive Denormalized Real |
| | | : | |
| | | 11..11 | 0.f × 2(-b+1) |
+------+-----------------+---------------+----------------------------+
| 0 | 00..01 | | Positive Normalized Real |
| | : | XX..XX | |
| | 11..10 | | 1.f × 2(e-b) |
+------+-----------------+---------------+----------------------------+
| 0 | 11..11 | 00..00 | +Infinity |
+------+-----------------+---------------+----------------------------+
| 1 | 00..00 | 00..00 | -0 |
+------+-----------------+---------------+----------------------------+
| 1 | 00..00 | 00..01 | Negative Denormalized Real |
| | | : | |
| | | 11..11 | -0.f × 2(-b+1) |
+------+-----------------+---------------+----------------------------+
| 1 | 00..01 | | Negative Normalized Real |
| | : | XX..XX | |
| | 11..10 | | 1.f × 2(e-b) |
+------+-----------------+---------------+----------------------------+
| 1 | 11..11 | 00..00 | -Infinity |
+------+-----------------+---------------+----------------------------+
| X | 11..11 | 00..01 | |
| | | : | SNaN |
| | | 01..11 | |
+------+-----------------+---------------+----------------------------+
| X | 11..11 | 10..00 | |
| | | : | QNaN |
| | | 11..11 | |
+------+-----------------+---------------+----------------------------+
|
|
by the way,
vzero.s S000; vrcp.s S000, S000 -> S000 = 1/0
vzero.s S001; vrsq.s S001, S001 -> S001 = 1/sqrt(0)
both give me 0x7F800000 which is +Infinity according to ieee754.
EDIT: it seems my previous code seems to be wrong for an unknown reason (?). A new code using "bvtl" instead of "mfvc" seems to work better... to see.
Last edited by hlide on Fri Jan 05, 2007 9:07 pm; edited 1 time in total |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Fri Jan 05, 2007 9:03 pm Post subject: |
|
|
okay this new code gives a more reliable results :
| Code: |
me_vfpu_qnan:
.long 0x7fffffff # QNaN
.global me_test_vfpu
me_test_vfpu:
lui at, %hi(me_vfpu_qnan)
vzero.s S000
lv.s S001, %lo(me_vfpu_qnan)(at)
sv.s S000, 0x00(a0)
vrcp.s S000,S000
vrsq.s S001,S001
sv.s S000, 0x10(a0)
sv.s S001, 0x14(a0)
li v0, 1
vcmp.s EI, S000
bvtl 0, 0f
sb v0, 0x00(a0)
0: vcmp.s NI, S000
bvtl 0, 0f
sb v0, 0x01(a0)
0: vcmp.s EI, S001
bvtl 0, 0f
sb v0, 0x02(a0)
0: vcmp.s NI, S001
bvtl 0, 0f
sb v0, 0x03(a0)
0: vcmp.s EN, S000
bvtl 0, 0f
sb v0, 0x04(a0)
0: vcmp.s NN, S000
bvtl 0, 0f
sb v0, 0x05(a0)
0: vcmp.s EN, S001
bvtl 0, 0f
sb v0, 0x06(a0)
0: vcmp.s NN, S001
bvtl 0, 0f
sb v0, 0x07(a0)
0: vcmp.s ES, S000
bvtl 0, 0f
sb v0, 0x08(a0)
0: vcmp.s NS, S000
bvtl 0, 0f
sb v0, 0x09(a0)
0: vcmp.s ES, S001
bvtl 0, 0f
sb v0, 0x0a(a0)
0: vcmp.s NS, S001
bvtl 0, 0f
sb v0, 0x0b(a0)
0: jr ra
nop
|
the result is following :
| Code: |
00000000 01 00 00 01 -> S000 is an inf, S001 is not an inf
00000004 00 01 01 00 -> S000 is not a nan, S001 is a nan
00000008 01 00 01 00 -> S000 is special, S001 is special
00000010 7F800000 -> S000 is +inf (result of 1/0)
00000014 7F800001 -> S001 was initialy stored with 7FFFFFFF which has been transformed to 7F800001 apparently by vrsq.s. Does vfpu handle both QNaN and SNaN. If not, what is the default behaviour of a VFPU NaN (Quiet or Signalling) ?
|
well I'm tremendously relieved now about the results.
I guess it is clear now about the meaning of Ex/Nx :
EZ : is zero ?
EI : is Inf ?
EN : is NaN ?
ES : is Special (Inf + Nan) ? (well i guess it must be something like this)
NZ : isn't zero ?
NI : isn't Inf ?
NN : isn't NaN ?
NS : isn't Special (Inf + Nan) ? (well i guess it must be something like this) |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Fri Jan 05, 2007 9:29 pm Post subject: |
|
|
VFPU seems to treat SNaN as QNaN, since 0x7f800001 is normally a SNaN (that is a exception occurs if we try to use it in an operation). Tested in :
| Code: |
lui at, %(vfpu_qnan)
lv.s S001, %(vfpu_qnan)(at) # S001 = QNaN
vrsq.s S001, S001 # S001 = 1/sqrt(QNaN) = SNaN
vadd.s S001, S001, S001 # S001 = SNaN + SNaN = SNaN
|
No exception occurs, so SNaN are treated as QNaN. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Fri Jan 05, 2007 11:36 pm Post subject: |
|
|
Another test :
| Code: |
S000 = +Inf;
S001 = NaN;
# +Inf = +Inf ?
vcmp.s EQ, S000, S000 -> true
# +Inf <> +Inf ?
vcmp.s NE, S000, S000 -> false
# NaN = NaN ?
vcmp.s EQ, S001, S001 -> false
# NaN <> NaN ?
vcmp.s NE, S001, S001 -> true
# +Inf = NaN ?
vcmp.s EQ, S000, S001 -> false
# +Inf <> NaN ?
vcmp.s NE, S000, S001 -> true
|
onne : you shouldn't rely on printf for the right value, but on the hexadecimal value of the float. |
|
| Back to top |
|
 |
onne
Joined: 29 Aug 2006 Posts: 24
|
Posted: Sat Jan 06, 2007 12:16 am Post subject: |
|
|
| ok... thanks... Then I must have been getting the Inf when I thought of getting NaN... Weird with the printf though. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Sat Jan 06, 2007 1:47 am Post subject: |
|
|
printf : %d is fetching a double float value instead of a single float value so you may expect bad display.
and yes printf is wrong :
0x7ff0000000000000LL -> +Inf (double) -> displays NaN !?
0x7ff0000000000001LL -> NaN (double) -> displays 0.0...0 !?
0x3ff0000000000001LL -> 1.0 (double) -> displays 1.0...0 (correct) |
|
| Back to top |
|
 |
jimparis
Joined: 10 Jun 2005 Posts: 1179 Location: Boston
|
Posted: Sat Jan 06, 2007 3:02 am Post subject: |
|
|
| I don't have a PSP handy, but that could be a newlib bug; you could check what fpclassify(), isnan(), isinf() return. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Sat Jan 06, 2007 3:18 am Post subject: |
|
|
| jimparis wrote: | | I don't have a PSP handy, but that could be a newlib bug; you could check what fpclassify(), isnan(), isinf() return. |
i got it :
| Code: |
hli@HLIWORLD /d/game console/psp/meccode$ make kxploit psp-gcc -I. -I/d/devkitPro/devkitPSP/psp/sdk/include -Os -G0 -Wall -fsingle-precision-constant -funswitch-loops fbranch-target-load-optimize2 -msingle-float -mhard-float -L. -L/d/devkitPro/devkitPSP/psp/sdk/lib main.o mestub.o -lpspdebug -lpspdisplay -lpspge -lpspctrl -lpspsdk -lc -lpspnet -lpspnet_inet -lpspnet_apctl -lpspnet_resolver -lpsputility -lpspuser lpspkernel -o meccode.elf
main.o: In function `main':
main.c:(.text+0x708): undefined reference to `__fpclassifyd'
collect2: ld returned 1 exit status
make: *** [meccode.elf] Error 1
|
and yes i'm using devkitpro
EDIT: i dunno if pspdevkit uses newlib.
well, i guess i should try to install cygwin... some megabytes to add... |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|