 |
forums.ps2dev.org Homebrew PS2, PSP & PS3 Development Discussions
|
| View previous topic :: View next topic |
| Author |
Message |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Mon Jul 07, 2008 12:29 am Post subject: [VFPU] lvl.q/lvr.q bug : they screw up a FPU reg ! |
|
|
I have two PSPs : one is my old fat PSP and the other a slim PSP.
I run a program using PSPLINK to check up a curious bug about lvl.q/lvr.q.
What is the bug ?
executing a LVL.Q or LVR.Q with a vector register scratches a FPU register this way : if VFPU register number is $N, the FPU register $fN is assigned with 0.0 (at least, this is the value I get on my fat PSP). This is a major issue for callee-saved FPU register which must be invariant before entering the callee function and after exiting the callee function, especially when this callee function doesn't use those callee-saved FPU registers.
On my slim PSP, I don't have this hardware issue so I guess Sony correct it.
Here is a piece of my program to test this bug :
| Code: |
...
float vec4[4] __attribute__((aligned(16))) = { 1.0, 2.0, 3.0, 4.0 };
float expected_value = -1.0;
template< int m, int c >
float vfpu_test_lvlq(float *vec)
{
float res = expected_value;
asm volatile
(
".set push " "\n"
".set noreorder " "\n"
"mov.s $f%2, %0 " "\n"
"lvl.q $%2,12(%1) " "\n" // lvl.q Cmc0.q, 12(%1)
"mov.s %0, $f%2 " "\n"
".set pop " "\n"
: "+f"(res) : "r"(vec), "i"(m*4+c) : "memory"
);
return res;
}
template< int m, int c >
float vfpu_test_lvrq(float *vec)
{
float res = expected_value;
asm volatile
(
".set push " "\n"
".set noreorder " "\n"
"mov.s $f%2, %0 " "\n"
"lvr.q $%2, 0(%1) " "\n" // lvr.q Cmc0.q, 0(%1)
"mov.s %0, $f%2 " "\n"
".set pop " "\n"
: "+f"(res) : "r"(vec), "i"(m*4+c) : "memory"
);
return res;
}
int main(int argc, char *argv[])
{
printf("\n$f0 = %f, %f", vfpu_test_lvlq<0, 0>(vec4), vfpu_test_lvrq<0, 0>(vec4));
printf("\n$f1 = %f, %f", vfpu_test_lvlq<0, 1>(vec4), vfpu_test_lvrq<0, 1>(vec4));
printf("\n$f2 = %f, %f", vfpu_test_lvlq<0, 2>(vec4), vfpu_test_lvrq<0, 2>(vec4));
printf("\n$f3 = %f, %f", vfpu_test_lvlq<0, 3>(vec4), vfpu_test_lvrq<0, 3>(vec4));
printf("\n$f4 = %f, %f", vfpu_test_lvlq<1, 0>(vec4), vfpu_test_lvrq<1, 0>(vec4));
printf("\n$f5 = %f, %f", vfpu_test_lvlq<1, 1>(vec4), vfpu_test_lvrq<1, 1>(vec4));
printf("\n$f6 = %f, %f", vfpu_test_lvlq<1, 2>(vec4), vfpu_test_lvrq<1, 2>(vec4));
printf("\n$f7 = %f, %f", vfpu_test_lvlq<1, 3>(vec4), vfpu_test_lvrq<1, 3>(vec4));
printf("\n$f8 = %f, %f", vfpu_test_lvlq<2, 0>(vec4), vfpu_test_lvrq<2, 0>(vec4));
printf("\n$f9 = %f, %f", vfpu_test_lvlq<2, 1>(vec4), vfpu_test_lvrq<2, 1>(vec4));
printf("\n$f10= %f, %f", vfpu_test_lvlq<2, 2>(vec4), vfpu_test_lvrq<2, 2>(vec4));
printf("\n$f11= %f, %f", vfpu_test_lvlq<2, 3>(vec4), vfpu_test_lvrq<2, 3>(vec4));
printf("\n$f12= %f, %f", vfpu_test_lvlq<3, 0>(vec4), vfpu_test_lvrq<3, 0>(vec4));
printf("\n$f13= %f, %f", vfpu_test_lvlq<3, 1>(vec4), vfpu_test_lvrq<3, 1>(vec4));
printf("\n$f14= %f, %f", vfpu_test_lvlq<3, 2>(vec4), vfpu_test_lvrq<3, 2>(vec4));
printf("\n$f15= %f, %f", vfpu_test_lvlq<3, 3>(vec4), vfpu_test_lvrq<3, 3>(vec4));
printf("\n$f16= %f, %f", vfpu_test_lvlq<4, 0>(vec4), vfpu_test_lvrq<4, 0>(vec4));
printf("\n$f17= %f, %f", vfpu_test_lvlq<4, 1>(vec4), vfpu_test_lvrq<4, 1>(vec4));
printf("\n$f18= %f, %f", vfpu_test_lvlq<4, 2>(vec4), vfpu_test_lvrq<4, 2>(vec4));
printf("\n$f19= %f, %f", vfpu_test_lvlq<4, 3>(vec4), vfpu_test_lvrq<4, 3>(vec4));
printf("\n$f20= %f, %f", vfpu_test_lvlq<5, 0>(vec4), vfpu_test_lvrq<5, 0>(vec4));
printf("\n$f21= %f, %f", vfpu_test_lvlq<5, 1>(vec4), vfpu_test_lvrq<5, 1>(vec4));
printf("\n$f22= %f, %f", vfpu_test_lvlq<5, 2>(vec4), vfpu_test_lvrq<5, 2>(vec4));
printf("\n$f23= %f, %f", vfpu_test_lvlq<5, 3>(vec4), vfpu_test_lvrq<5, 3>(vec4));
printf("\n$f24= %f, %f", vfpu_test_lvlq<6, 0>(vec4), vfpu_test_lvrq<6, 0>(vec4));
printf("\n$f25= %f, %f", vfpu_test_lvlq<6, 1>(vec4), vfpu_test_lvrq<6, 1>(vec4));
printf("\n$f26= %f, %f", vfpu_test_lvlq<6, 2>(vec4), vfpu_test_lvrq<6, 2>(vec4));
printf("\n$f27= %f, %f", vfpu_test_lvlq<6, 3>(vec4), vfpu_test_lvrq<6, 3>(vec4));
printf("\n$f28= %f, %f", vfpu_test_lvlq<7, 0>(vec4), vfpu_test_lvrq<7, 0>(vec4));
printf("\n$f29= %f, %f", vfpu_test_lvlq<7, 1>(vec4), vfpu_test_lvrq<7, 1>(vec4));
printf("\n$f30= %f, %f", vfpu_test_lvlq<7, 2>(vec4), vfpu_test_lvrq<7, 2>(vec4));
printf("\n$f31= %f, %f", vfpu_test_lvlq<7, 3>(vec4), vfpu_test_lvrq<7, 3>(vec4));
printf("\n");
sceKernelExitGame();
return 0;
}
...
|
normally, we should have -1.0 for all the FPU registers (as it is the case for slim PSP), but for fat PSP I get 0.0 (no idea where this value comes from). |
|
| Back to top |
|
 |
adrahil
Joined: 16 Mar 2006 Posts: 277
|
Posted: Mon Jul 07, 2008 1:14 am Post subject: |
|
|
| Strange problem indeed... |
|
| Back to top |
|
 |
crazyc
Joined: 17 Jun 2005 Posts: 410
|
Posted: Mon Jul 07, 2008 2:00 am Post subject: |
|
|
It might have something to do with the way those opcodes are encoded.
| Code: | # float vfpu_test_lvlq<0, 0>(float *)
lwc1 $f0, -0x7FF0($gp)
mov.s $f0, $f0
ldc1 $f0, 0xC($a0)
mov.s $f0, $f0
jr $ra
nop
# End of function vfpu_test_lvlq<0,0>(float *)
# float vfpu_test_lvrq<0, 0>(float *)
lwc1 $f0, -0x7FF0($gp)
mov.s $f0, $f0
ldc1 $f0, 2($a0)
mov.s $f0, $f0
jr $ra
nop
# End of function vfpu_test_lvrq<0,0>(float *)
# float vfpu_test_lvq<0, 0>(float *)
lwc1 $f0, -0x7FF0($gp)
mov.s $f0, $f0
ldc2 $0, 0($a0)
mov.s $f0, $f0
jr $ra
nop
# End of function vfpu_test_lvq<0,0>(float *) |
ldc1 may be executed along with lvl.q. |
|
| Back to top |
|
 |
hlide
Joined: 10 Sep 2006 Posts: 750
|
Posted: Mon Jul 07, 2008 2:33 am Post subject: |
|
|
| crazyc wrote: | | ldc1 may be executed along with lvl.q. |
Not only lvl.q but lvr.q as they share the same opcode (bit 1 in offset tells us if it is lvl or lvr and bit 0 in offset tells us if it is a column or row register). So, yes. That's a perfect explanation ! SONY simply forget to "disable" the FPU register write back circuitry for ldc1. A very stupid error indeed. |
|
| 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
|