forums.ps2dev.org Forum Index forums.ps2dev.org
Homebrew PS2, PSP & PS3 Development Discussions
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

VFPU playground, code generation for gas-unsupported opcodes
Goto page Previous  1, 2, 3
 
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development
View previous topic :: View next topic  
Author Message
mrbrown



Joined: 17 Jan 2004
Posts: 1536

PostPosted: Wed Oct 12, 2005 6:11 am    Post subject: Reply with quote

By VFPU assember I mean gas. If you saw what it took to implement support for register operands you'd have chickened out like I did :).

Oh and games always run in usermode. Just as there's no way for us to get into the kernel once in usermode, official games can't either.
Back to top
View user's profile Send private message
jsgf



Joined: 12 Jul 2005
Posts: 254

PostPosted: Wed Oct 12, 2005 9:59 am    Post subject: Reply with quote

holger wrote:
jsgf wrote:
I would like to see a very simple, thin libvfpu which provites two things:[list=1]
[*] a set of macros to make inline assembler access to the VFPU easy (like gcc/icc's xmmintrin.h for SSE)


yes, this would be nice, but requires some work in the toolchain, so that gcc knows how to schedule the VFPU registers.


It doesn't require it. It would be nice to have a constraint for VFPU registers so that gcc can reorder the asm statements with respect to other code while maintaining dependencies properly, and doubly nice if there were a gcc type for VFPU register variables, but not essential. A plain asm() with memory-use constraints should be enough.

Quote:
jsgf wrote:
[*] a simple lightweight context switching mechanism to allow multiple libraries to share the VFPU without stomping on each other


becomes obsolete with the above...

Perhaps. But that's quite a bit more work.
Back to top
View user's profile Send private message Visit poster's website
holger



Joined: 18 Aug 2005
Posts: 204

PostPosted: Wed Oct 12, 2005 11:15 pm    Post subject: Reply with quote

jsgf wrote:
holger wrote:
jsgf wrote:
I would like to see a very simple, thin libvfpu which provites two things:[list=1]
[*] a set of macros to make inline assembler access to the VFPU easy (like gcc/icc's xmmintrin.h for SSE)


yes, this would be nice, but requires some work in the toolchain, so that gcc knows how to schedule the VFPU registers.


It doesn't require it. It would be nice to have a constraint for VFPU registers so that gcc can reorder the asm statements with respect to other code while maintaining dependencies properly, and doubly nice if there were a gcc type for VFPU register variables, but not essential. A plain asm() with memory-use constraints should be enough.



you can implement this by wrapping all __asm__ volatile (cgen_asm()) macros with inline functions, but it would not be of much use -- the great thing about intrinsics is that you get rid of the load of register scheduling...
Back to top
View user's profile Send private message
jsgf



Joined: 12 Jul 2005
Posts: 254

PostPosted: Thu Oct 13, 2005 1:16 am    Post subject: Reply with quote

holger wrote:
you can implement this by wrapping all __asm__ volatile (cgen_asm()) macros with inline functions, but it would not be of much use -- the great thing about intrinsics is that you get rid of the load of register scheduling...

Yep, I'm with you there. But since that will require a non-trivial amount of gcc hacking, it would be nice to have a workable substitute for now, if nothing else so we can get a feeling for how and where the VFPU is actually useful.
Back to top
View user's profile Send private message Visit poster's website
holger



Joined: 18 Aug 2005
Posts: 204

PostPosted: Thu Oct 13, 2005 2:28 am    Post subject: Reply with quote

I fear writing big section of inline asm (right now macro-based, hope gas-support comes soon), or dynamic macro-based code generation, is the only option now.
Back to top
View user's profile Send private message
groepaz



Joined: 01 Sep 2005
Posts: 305

PostPosted: Tue Oct 18, 2005 2:38 am    Post subject: Reply with quote

i have added the info from this thread to my doc, those who have messaged me before can get it from its previous location... let me know if there are any obvious errors :)
_________________
http://www.hitmen-console.org
http://hitmen.c02.at/files/yapspd/
Back to top
View user's profile Send private message Visit poster's website
MrMr[iCE]



Joined: 03 Oct 2005
Posts: 43

PostPosted: Wed Oct 19, 2005 3:56 pm    Post subject: Reply with quote

I've written up a reference that shows how the registers are mapped in the various single/pair/triple/quad modes. This should help a bit when trying to juggle all those matrices/vectors around the vfpu register space.

http://bradburn.net/mr.mr/vfpu.html
http://bradburn.net/mr.mr/vfpu2.html <-- this one is nice for a cheat sheet

EDIT: I've also added this to the wiki.
Back to top
View user's profile Send private message
holger



Joined: 18 Aug 2005
Posts: 204

PostPosted: Thu Oct 20, 2005 5:41 am    Post subject: Reply with quote

nice explanation! but the wiki seems dead these minutes...
Back to top
View user's profile Send private message
MrMr[iCE]



Joined: 03 Oct 2005
Posts: 43

PostPosted: Thu Oct 20, 2005 10:12 am    Post subject: Reply with quote

Heh the wiki just links to the first page I pasted above. Ill do a proper entry for the wiki later.
Back to top
View user's profile Send private message
sherpya



Joined: 03 Oct 2005
Posts: 61

PostPosted: Thu Oct 20, 2005 11:01 am    Post subject: Reply with quote

why not adding it directly to gas? it's not possible?
Back to top
View user's profile Send private message
MrMr[iCE]



Joined: 03 Oct 2005
Posts: 43

PostPosted: Thu Oct 20, 2005 12:34 pm    Post subject: Reply with quote

no just very difficult to do...im not familiar with adding opcodes to gas, and I have no clue how to get gcc to schedule the register usage. That requires someone who really knows binutils and gcc to do that. For now well stick to the macro stuff, much easier to use =)
Back to top
View user's profile Send private message
nugi



Joined: 11 Sep 2005
Posts: 6

PostPosted: Sun Oct 23, 2005 5:09 am    Post subject: load 1,2 byte integer? Reply with quote

Yeah~ good job.

I'm wondering how to load/save 1 or 2 byte integer to vector register of GPU at once. For example, loading 32bit color value(RGBA) to C000 register. And after some processing write C000 to memory(32bit).

Is it possible? I cant find a way from current codegen.h. hmm~~~
Back to top
View user's profile Send private message
chp



Joined: 23 Jun 2004
Posts: 313

PostPosted: Sun Oct 23, 2005 1:16 pm    Post subject: Reply with quote

I have added very preliminary VFPU support to GUM now, just as a working example. To enable this support, remove the comment from
Code:
//#define GUM_USE_VFPU
in gumInternal.h, rebuild the library and set THREAD_ATTR_VFPU in the desired program. I have tested a few of the samples and they have all run fine.

Only the stack-functions have been fixed so far, I intend to finish the rest of them tomorrow.

Thanks to holger and MrMr[iCE] for their work on this. libpspvgum from MrMr[iCE] was used as initial inspiration for this implementation.
_________________
GE Dominator
Back to top
View user's profile Send private message
MrMr[iCE]



Joined: 03 Oct 2005
Posts: 43

PostPosted: Sun Oct 23, 2005 2:46 pm    Post subject: Reply with quote

I've updated the wiki again, now theres information on loading/storing values into the vfpu.
Back to top
View user's profile Send private message
holger



Joined: 18 Aug 2005
Posts: 204

PostPosted: Mon Oct 24, 2005 6:29 am    Post subject: Reply with quote

maybe a note about lvl.q/lvr.q/svl.q/svr.q makes sense, to ease unaligned load/stores. Semantics are similiar to unaligned word load/stores.
Back to top
View user's profile Send private message
curlyfuzz



Joined: 24 Oct 2005
Posts: 1

PostPosted: Mon Oct 24, 2005 3:41 pm    Post subject: Reply with quote

MrMr[iCE] wrote:
and here comes another run of ops ive tested:
Code:

/*
+-----------------------------------------+--+--------------+-+--------------+
|31                                    16 |15| 14         8 |7| 6         0  |
+-----------------------------------------+--+--------------+-+--------------+
| opcode 0xd0180000 (s)                   | 0| vfpu_rs[6-0] |0| vfpu_rd[6-0] |
| opcode 0xd0180080 (p)                   | 0| vfpu_rs[6-0] |1| vfpu_rd[6-0] |
| opcode 0xd0188000 (t)                   | 1| vfpu_rs[6-0] |0| vfpu_rd[6-0] |
| opcode 0xd0188080 (q)                   | 1| vfpu_rs[6-0] |1| vfpu_rd[6-0] |
+-----------------------------------------+--+--------------+-+--------------+

   NegativeReciprocal.Single/Pair/Triple/Quad

   vnrcp.s  %vfpu_rd, %vfpu_rs   ; calculate negative reciprocal
   vnrcp.p  %vfpu_rd, %vfpu_rs   ; calculate negative reciprocal
   vnrcp.t  %vfpu_rd, %vfpu_rs   ; calculate negative reciprocal
   vnrcp.q  %vfpu_rd, %vfpu_rs   ; calculate negative reciprocal

   %vfpu_rd:   VFPU Vector Target Register ([s|p|t|q]reg 0..127)
   %vfpu_rs:   VFPU Vector Source Register ([s|p|t|q]reg 0..127)

   vfpu_regs[%vfpu_rd] <- -1/vfpu_regs[%vfpu_rs]
*/

#define vnrcp_s(vfpu_rd, vfpu_rs) (0xd0180000 | (vfpu_rs << 8) | (vfpu_rd))
#define vnrcp_p(vfpu_rd, vfpu_rs) (0xd0180080 | (vfpu_rs << 8) | (vfpu_rd))
#define vnrcp_t(vfpu_rd, vfpu_rs) (0xd0188000 | (vfpu_rs << 8) | (vfpu_rd))
#define vnrcp_q(vfpu_rd, vfpu_rs) (0xd0188080 | (vfpu_rs << 8) | (vfpu_rd))


/*
+-----------------------------------------+--+--------------+-+--------------+
|31                                    16 |15| 14         8 |7| 6         0  |
+-----------------------------------------+--+--------------+-+--------------+
| opcode 0xd01a0000 (s)                   | 0| vfpu_rs[6-0] |0| vfpu_rd[6-0] |
| opcode 0xd01a0080 (p)                   | 0| vfpu_rs[6-0] |1| vfpu_rd[6-0] |
| opcode 0xd01a8000 (t)                   | 1| vfpu_rs[6-0] |0| vfpu_rd[6-0] |
| opcode 0xd01a8080 (q)                   | 1| vfpu_rs[6-0] |1| vfpu_rd[6-0] |
+-----------------------------------------+--+--------------+-+--------------+

   NegativeSin.Single/Pair/Triple/Quad

   vnsin.s  %vfpu_rd, %vfpu_rs   ; calculate negative sin
   vnsin.p  %vfpu_rd, %vfpu_rs   ; calculate negative sin
   vnsin.t  %vfpu_rd, %vfpu_rs   ; calculate negative sin
   vnsin.q  %vfpu_rd, %vfpu_rs   ; calculate negative sin

   %vfpu_rd:   VFPU Vector Target Register ([s|p|t|q]reg 0..127)
   %vfpu_rs:   VFPU Vector Source Register ([s|p|t|q]reg 0..127)

   vfpu_regs[%vfpu_rd] <- sqrt(vfpu_regs[%vfpu_rs])
*/

#define vnsin_s(vfpu_rd, vfpu_rs) (0xd01a0000 | (vfpu_rs << 8) | (vfpu_rd))
#define vnsin_p(vfpu_rd, vfpu_rs) (0xd01a0080 | (vfpu_rs << 8) | (vfpu_rd))
#define vnsin_t(vfpu_rd, vfpu_rs) (0xd01a8000 | (vfpu_rs << 8) | (vfpu_rd))
#define vnsin_q(vfpu_rd, vfpu_rs) (0xd01a8080 | (vfpu_rs << 8) | (vfpu_rd))


/*
+-----------------------------------------+--+--------------+-+--------------+
|31                                    16 |15| 14         8 |7| 6         0  |
+-----------------------------------------+--+--------------+-+--------------+
| opcode 0xd01c0000 (s)                   | 0| vfpu_rs[6-0] |0| vfpu_rd[6-0] |
| opcode 0xd01c0080 (p)                   | 0| vfpu_rs[6-0] |1| vfpu_rd[6-0] |
| opcode 0xd01c8000 (t)                   | 1| vfpu_rs[6-0] |0| vfpu_rd[6-0] |
| opcode 0xd01c8080 (q)                   | 1| vfpu_rs[6-0] |1| vfpu_rd[6-0] |
+-----------------------------------------+--+--------------+-+--------------+

   ReciprocalExp2.Single/Pair/Triple/Quad

   vrexp2.s  %vfpu_rd, %vfpu_rs   ; calculate 1/(2^y)
   vrexp2.p  %vfpu_rd, %vfpu_rs   ; calculate 1/(2^y)
   vrexp2.t  %vfpu_rd, %vfpu_rs   ; calculate 1/(2^y)
   vrexp2.q  %vfpu_rd, %vfpu_rs   ; calculate 1/(2^y)

   %vfpu_rd:   VFPU Vector Target Register ([s|p|t|q]reg 0..127)
   %vfpu_rs:   VFPU Vector Source Register ([s|p|t|q]reg 0..127)

   vfpu_regs[%vfpu_rd] <- 1/exp2(vfpu_regs[%vfpu_rs])
*/

#define vrexp2_s(vfpu_rd, vfpu_rs) (0xd01c0000 | (vfpu_rs << 8) | (vfpu_rd))
#define vrexp2_p(vfpu_rd, vfpu_rs) (0xd01c0080 | (vfpu_rs << 8) | (vfpu_rd))
#define vrexp2_t(vfpu_rd, vfpu_rs) (0xd01c8000 | (vfpu_rs << 8) | (vfpu_rd))
#define vrexp2_q(vfpu_rd, vfpu_rs) (0xd01c8080 | (vfpu_rs << 8) | (vfpu_rd))




Seems like these opcodes are the same as for reciprocal/sin/exp2 but with the flag 0x00080000 ored into the opcode. (meaning to negate the input register before the calculation). Maybe this is a more general feature?
Back to top
View user's profile Send private message
MrMr[iCE]



Joined: 03 Oct 2005
Posts: 43

PostPosted: Mon Oct 24, 2005 4:56 pm    Post subject: Reply with quote

Honestly I don't know. I'm using the opcode list in binutils, this is what you would see if these opcodes were found in a binary with psp-objdump.
Back to top
View user's profile Send private message
groepaz



Joined: 01 Sep 2005
Posts: 305

PostPosted: Mon Oct 24, 2005 5:52 pm    Post subject: Reply with quote

bit 24-26 seem to be more like an "extended opcode" field, not directly related to a specific feature...

edit: doh...0x00080000 isnt bit 24-26 :=P there is indeed a small chance that what you say is true :)
_________________
http://www.hitmen-console.org
http://hitmen.c02.at/files/yapspd/
Back to top
View user's profile Send private message Visit poster's website
jonny



Joined: 22 Sep 2005
Posts: 351

PostPosted: Fri Nov 04, 2005 3:23 am    Post subject: Reply with quote

is this the latest codegen?

http://svn.pspdev.org/filedetails.php?repname=psp&path=%2Ftrunk%2Fpspgl%2Fpspgl_codegen.h&rev=1133&sc=1
Back to top
View user's profile Send private message Visit poster's website
nugi



Joined: 11 Sep 2005
Posts: 6

PostPosted: Tue Dec 06, 2005 10:34 pm    Post subject: Thread down? Reply with quote

No more opcodes from this thread?

Here's some more opcodes from my test codes... no documents sorry~
I think there is no sense to use gas to assemble vfpu codes. The way of using vfpu codes was sufficient to me and greatly helped me. Thank you~
I hope this thread not to be closed due to no contribution!

int to short.
#define vi2s_p(vfpu_rd,vfpu_rs) (0xd03f0080 | ((vfpu_rs) << 8) | (vfpu_rd))
#define vi2s_q(vfpu_rd,vfpu_rs) (0xd03f8080 | ((vfpu_rs) << 8) | (vfpu_rd))

int to unsigned char.
#define vi2uc_q(vfpu_rd,vfpu_rs) (0xd03c8080 | ((vfpu_rs) << 8) | (vfpu_rd))

int to float.
#define vi2f_s(vfpu_rd,vfpu_rs,scale) (0xd2800000 | ((scale) << 16) | ((vfpu_rs) << 8) | (vfpu_rd))
#define vi2f_p(vfpu_rd,vfpu_rs,scale) (0xd2800080 | ((scale) << 16) | ((vfpu_rs) << 8) | (vfpu_rd))
#define vi2f_t(vfpu_rd,vfpu_rs,scale) (0xd2808000 | ((scale) << 16) | ((vfpu_rs) << 8) | (vfpu_rd))
#define vi2f_q(vfpu_rd,vfpu_rs,scale) (0xd2808080 | ((scale) << 16) | ((vfpu_rs) << 8) | (vfpu_rd))

float to int round to near.
#define vf2in_s(vfpu_rd,vfpu_rs,scale) (0xd2000000 | ((scale) << 16) | ((vfpu_rs) << 8) | (vfpu_rd))
#define vf2in_p(vfpu_rd,vfpu_rs,scale) (0xd2000080 | ((scale) << 16) | ((vfpu_rs) << 8) | (vfpu_rd))
#define vf2in_t(vfpu_rd,vfpu_rs,scale) (0xd2008000 | ((scale) << 16) | ((vfpu_rs) << 8) | (vfpu_rd))
#define vf2in_q(vfpu_rd,vfpu_rs,scale) (0xd2008080 | ((scale) << 16) | ((vfpu_rs) << 8) | (vfpu_rd))

also there are vf2id, vf2id instructions with different rounding methods.

Maybe something is wrong in unused instruction to me.
Back to top
View user's profile Send private message
Brunni



Joined: 08 Oct 2005
Posts: 186

PostPosted: Sun Dec 11, 2005 10:26 pm    Post subject: Reply with quote

Hello. I have some problems with lv_q. For example, if I do this:
Code:
float vfpu_add(float f1, float f2)
{
   vfpu_vars[0] = f1;
   vfpu_vars[1] = f2;
   register void *ptr __asm ("a0") = vfpu_vars;
   __asm__ volatile (
      cgen_asm(lv_q(0, 0, R_a0, 0))
      cgen_asm(vadd_s(124, 0, 1))
      cgen_asm(sv_q(31, 0 * 4, R_a0, 0))
   : "=r"(ptr) : "r"(ptr) : "memory");
   return vfpu_vars[0];
}

This won't work as expected (i.e. add f1 and f2 and return the result). It seems that f1 is not loaded, if I load something else in register 1 before, it will keep this value after lv_q.
Instead, something like this will work:
Code:
float vfpu_add(float f1, float f2)
{
   vfpu_vars[0] = f1;
   vfpu_vars[1] = f2;
   register void *ptr __asm ("a0") = vfpu_vars;
   __asm__ volatile (
      cgen_asm(lv_s(0, 0, R_a0, 0))
      cgen_asm(lv_s(1, 1, R_a0, 0))
      cgen_asm(vadd_s(124, 0, 1))
      cgen_asm(sv_q(31, 0 * 4, R_a0, 0))
   : "=r"(ptr) : "r"(ptr) : "memory");
   return vfpu_vars[0];
}

But in the .h file it's indicated:
Code:
    lv.q %vfpu_rt, offset(%base)

   %fpu_rt:   VFPU Vector Target Register (column0-31/row32-63)

But here fpu_rt seems to be just the register number... so maybe it's my fault (I'm a real beginner), or there is really something I didn't understand. If someone could help me please...
Thanks in advance ^^
_________________
Sorry for my bad english
Oldschool library for PSP - PC version released
Back to top
View user's profile Send private message
nugi



Joined: 11 Sep 2005
Posts: 6

PostPosted: Mon Dec 12, 2005 2:17 am    Post subject: Hmm.... Reply with quote

Some information and suggestion.
1. Before start, final address should be aligned to 16 for quad version(q) and 4 for single version(s).
2. Use Q_C000 style register defined in codegen.h rather than using direct register numbers.
3. Example : lv_q(Q_C000, 0, R_a0)
Loads 16 byte data(4xfloat) into Q_C000 register from address pointed by R_a0(==vfpu_vars).
That is, if float vfpu_vars[4]={100, 101, 102, 103} then S_S000=100, S_S001=101... As noted, vfpu_vars should be 16 byte aligned.
4. a simple test program(newvfpu.c?) will greatly help! Find it in this thread and use it.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    forums.ps2dev.org Forum Index -> PSP Development All times are GMT + 10 Hours
Goto page Previous  1, 2, 3
Page 3 of 3

 
Jump to:  
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