 |
forums.ps2dev.org Homebrew PS2, PSP & PS3 Development Discussions
|
| View previous topic :: View next topic |
| Author |
Message |
Fanjita
Joined: 28 Sep 2005 Posts: 217
|
Posted: Sun Oct 30, 2005 2:12 am Post subject: How to write homebrew for v2.0 firmware |
|
|
Here's a short guide, with hints and tips for making sure your code will work well on v2.0 firmware. I'll update it from time to time as more factors come to light.
Kernel mode
This is the biggie. You can't currently use any kernel-mode features in v2.0 homebrew. Here's what that means in practice:
- You can request kernel-mode (in the PSPSDK, this means that the second argument to MODULE_INFO() is '0x1000'), so long as you don't break any of the rules below. The loader will attempt to automatically patch up your app to remove typical 'unnecessary' kernel access (e.g. stdio handlers, exception handlers) that cannot be supported in user mode. This also usually means that your init() function will not get called. Preferably, you should use user-mode, to avoid any problems, but this level of kernel-mode tolerance means that you can usually get away with using a single source for 1.5 and 2.0, with better debugging support etc. on the 1.5 platform.
- You can use wi-fi, so long as the users use the special wifi hack for the loader. If you are going to use wifi, you should use the new PSPSDK support for loading the network modules, because the loader can automatically patch this when starting the app. PSPPet's wifi sample code will also usually work, depending on how heavily you modified it. Other methods for starting the network modules may not be supported.
- You can use stdio stream handlers, but they won't have any effect.
- You can install exception handlers, but they won't have any effect.
- You can't access kernel-space memory.
Stability tips
The environment when running under v2.0 is pretty close to that under v1.5 - once loaded, your app will make system calls in exactly the same way, will be loaded in memory in exactly the same place, etc. There are some small differences you might want to be aware of, because these can help improve your stability on 2.0.
- Memory allocation: The environment that the loader starts in has a restricted global heap, with only approx 3Mb left in the official sceKernelAllocPartitionMemory() user partition (#2). Because of this, the loader hooks the memory management APIs, and uses any spare RAM not being used by the program code to provide an additional pool. Typically this gives an average-sized app approx another 16Mb to use.
Access to this memory is transparent to your app, so long as you use the standard sceKernelAllocPartitionMemory calls, as before. (The extra memory is added to partition 2, so you don't need to change any parameters). A few notes:
- Alloc calls will be offered to the official Alloc API first. The extra pool is only used if the API can't satisfy the alloc request.
- The extra pool only supports the 'allocate from lowest memory' option.
- Re-merge handling of freed memory is limited. Freeing anything except the most-recently allocated memory from the extra pool will result in a leak.
- It seems that libnewlibc provides its own malloc manager, rather than passing calls directly to the Sony API. It allocates the largest single memory block available at initialisation (this will be the entire extra pool), and services mallocs from that block. So, if you want the maximum available RAM, it is probably best to use sceKernelAllocPartitionMe mory() etc. rather than malloc, when running with libnewlibc.
- Thread management : The loader also hooks some thread management calls (sceKernelRunThread(), sceKernelExitThread(), etc.) so that it can keep track of whether the app has exited.
General tips
A few general coding tips, to make it easier for people running your code under v2.0:
- Although there's handling in place in the loader to check for hard-coded file paths, and warn the user, it's best to avoid these altogether. Various development libraries provide support for relative (rather than absolute) file paths, and even if you're not using one of those, you can easily make your app use relative paths by checking argv[0] in main() : this will contain the full absolute path to your EBOOT.PBP file, so you can process this to build the correct absolute paths to your files without having to assume that your app will be installed in a specific path.
- Make sure you're using the latest PSPSDK toolchain, because that's the version the loader is usually tested against. Older versions of the SDK may use different startup code, which may not behave quite as expected under 2.0.
- Try to use a unique module name in the MODULE_INFO() statement. This helps to distinguish between apps for special case handling. There are an awful lot of apps that still use "HelloWorld" or "SDKSample" or similar as their module name.
- Include an alternative way to exit your app, rather than relying just on the HOME button. HOME doesn't work on v2.0 homebrew (yet), and the available workaround has limitations. Far better to have a menu option that just calls SceExitGame().
EDIT: Updated for the current loader version, 0.9.
Last edited by Fanjita on Fri Dec 02, 2005 9:51 am; edited 1 time in total |
|
| Back to top |
|
 |
mrbrown
Joined: 17 Jan 2004 Posts: 1536
|
Posted: Sun Oct 30, 2005 5:05 am Post subject: |
|
|
| Stickied. |
|
| Back to top |
|
 |
Duo
Joined: 21 Oct 2005 Posts: 25
|
Posted: Mon Oct 31, 2005 11:37 am Post subject: |
|
|
| An option in the compiler that checks for 2.0 compatibility, giving line numbers of incompatible code would be cool. |
|
| Back to top |
|
 |
mrbrown
Joined: 17 Jan 2004 Posts: 1536
|
Posted: Thu Nov 03, 2005 9:29 am Post subject: |
|
|
| Duo wrote: | | An option in the compiler that checks for 2.0 compatibility, giving line numbers of incompatible code would be cool. |
That will never happen. Anyway, the compatiblity requirements listed by Fanjita should be more than enough. |
|
| Back to top |
|
 |
Paolo
Joined: 08 Nov 2005 Posts: 12
|
Posted: Wed Nov 23, 2005 7:33 pm Post subject: |
|
|
| Is there existing examples of using sceKernelAllocPartitionMemory() ...? |
|
| Back to top |
|
 |
Fanjita
Joined: 28 Sep 2005 Posts: 217
|
Posted: Thu Nov 24, 2005 12:01 am Post subject: |
|
|
| Paolo wrote: | | Is there existing examples of using sceKernelAllocPartitionMemory() ...? |
See the SDK files : pspsysmem.h, I think, for example usage.
It's a lot like malloc, the main difference is that you get back a block ID, that you need to call sceKernelGetBlockHeadAddr on to get the actual address of your memory. _________________ Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you! |
|
| Back to top |
|
 |
Paolo
Joined: 08 Nov 2005 Posts: 12
|
Posted: Thu Nov 24, 2005 1:32 am Post subject: |
|
|
The kernel memory manager seems to some kind of frame based memory
allocator, at least the option to allocate from lowest or highest available
address would indicate to that, no?
But, how do I define the partition id -argument? What is it and what should
I use? For example, if I would make a texture manager which allocates a
big chunk of memory from vram, I would use PSP_SMEM_Addr as a block
type, and point the mem address to somewhere beyond the depth buffer?
What would be the partition id?
What benefit does this give compared to malloc?
Sorry if this is too noobish... :) |
|
| Back to top |
|
 |
Fanjita
Joined: 28 Sep 2005 Posts: 217
|
Posted: Thu Nov 24, 2005 4:29 am Post subject: |
|
|
There's a memory map in wiki.ps2dev.org that describes the different partitions.
Ordinarily, you'll use the user partition, which (from memory) I think is 2.
I don't believe that there is an option to allocate from VRAM, but I could be wrong on that.
Incidentally, I've generally found that requesting a specific address doesn't work, even when I'm sure that a block of the right size at that address is free. Perhaps I was doing something wrong, but I couldn't see what it was.
There's no compelling advantage to using the native memory management interface. On v2.0, it will give you access to a slightly larger memory pool, as described above. It will also be slightly faster than using mallocs that just ultimately map to the native calls anyway.
Note though that some libc libraries (newlib is one, I think) seem to just use the native interface to alloc the largest single block they're allowed, and then run their own allocation scheme within that block for malloc calls etc. _________________ Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you! |
|
| Back to top |
|
 |
Fanjita
Joined: 28 Sep 2005 Posts: 217
|
Posted: Fri Dec 02, 2005 9:52 am Post subject: |
|
|
(Updated original post with the latest info - most of the restrictions have now been lifted) _________________ Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you! |
|
| Back to top |
|
 |
mrbrown
Joined: 17 Jan 2004 Posts: 1536
|
Posted: Thu Dec 15, 2005 8:47 am Post subject: |
|
|
| Is there a cheap way to detect if the EBOOT loader is active? I need to manually call _init() to initialize C++, and I also need to avoid calling anything that triggers a kernel access. |
|
| Back to top |
|
 |
Fanjita
Joined: 28 Sep 2005 Posts: 217
|
Posted: Thu Dec 15, 2005 9:21 am Post subject: |
|
|
There are probably a few ways, none of which is extremely reliable.
Simplest would be to check if your thread has the VSH attributes. But that's not future-proof.
Most future-proof is probably to check for the presence of a thread called "restartThread" - I doubt that will change. _________________ Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you! |
|
| Back to top |
|
 |
mrbrown
Joined: 17 Jan 2004 Posts: 1536
|
Posted: Thu Dec 15, 2005 3:03 pm Post subject: About the EBOOT laoder and C++ global constructors... |
|
|
So, we figured out that rRootage was crashing on 2.0 systems because _init() wasn't being called by the EBOOT loader. To recap, _init() is the function that goes through and executes the constructors used in C++ static classes and C functions using GCC's "constructor" attribute.
rRootage uses SDL, and it depends on libSDL_main to provide main() and all of the PSP-specific code (exception handling, exit callback, etc.). SDL's PSP main() code includes a constructor function that normally installs an exception handler for 1.0 and 1.5 systems. If the 2.0 EBOOT loader were to call this function, it would immediately crash as 2.0 doesn't have access to kernel mode. The EBOOT loader can be configured to call _init(), but it's usually safer for it not to, so that more applications will work under 2.0. So we need to be able to call _init() if the EBOOT loader doesn't call it, and we need to make sure that we don't call any functions in our constructors that require kernel access.
What follows is the solution I used for libSDL_main. In the loaderInit() constructor function, I use sceKernelDevkitVersion() to determine the PSP firmware version. If it's less than 0x02000010 we know that we can access the kernel. At the end of this function I set a flag indicating that _init() was called. In main(), we check this flag, and if it's zero we call _init() ourselves.
This solution should fix any applications that depend on C++ static constructors (Fanjita mentioned UAE and PSP-GBA also have this issue).
| Code: | /* If this flag is set to 1, the _init() function was called and all
global/static constructors have been called. */
static int init_was_called = 0;
__attribute__ ((constructor))
void loaderInit()
{
int kmode_is_available = (sceKernelDevkitVersion() < 0x02000010);
if (kmode_is_available) {
/* Do nefarious kernel stuff here */
}
init_was_called = 1;
}
extern void _init(void);
int main(int argc, char *argv[])
{
/* Fanjita's EBOOT loader can be configured to skip the call to _init().
Since we need _init() for C++, we check to see if _init() has been
called. If it hasn't we call it manually, after determining whether or
not we can access the kernel. */
if (!init_was_called) {
_init();
}
...
} |
|
|
| Back to top |
|
 |
mICrO
Joined: 17 Oct 2005 Posts: 25 Location: Madrid (Spain)
|
Posted: Thu Dec 22, 2005 9:40 am Post subject: Re: About the EBOOT laoder and C++ global constructors... |
|
|
So, where its the 'real' _init function?
Because if I reproduce that code in my c++ code its said the tipical: unresolved externall.
| mrbrown wrote: | So, we figured out that rRootage was crashing on 2.0 systems because _init() wasn't being called by the EBOOT loader. To recap, _init() is the function that goes through and executes the constructors used in C++ static classes and C functions using GCC's "constructor" attribute.
rRootage uses SDL, and it depends on libSDL_main to provide main() and all of the PSP-specific code (exception handling, exit callback, etc.). SDL's PSP main() code includes a constructor function that normally installs an exception handler for 1.0 and 1.5 systems. If the 2.0 EBOOT loader were to call this function, it would immediately crash as 2.0 doesn't have access to kernel mode. The EBOOT loader can be configured to call _init(), but it's usually safer for it not to, so that more applications will work under 2.0. So we need to be able to call _init() if the EBOOT loader doesn't call it, and we need to make sure that we don't call any functions in our constructors that require kernel access.
What follows is the solution I used for libSDL_main. In the loaderInit() constructor function, I use sceKernelDevkitVersion() to determine the PSP firmware version. If it's less than 0x02000010 we know that we can access the kernel. At the end of this function I set a flag indicating that _init() was called. In main(), we check this flag, and if it's zero we call _init() ourselves.
This solution should fix any applications that depend on C++ static constructors (Fanjita mentioned UAE and PSP-GBA also have this issue).
| Code: | /* If this flag is set to 1, the _init() function was called and all
global/static constructors have been called. */
static int init_was_called = 0;
__attribute__ ((constructor))
void loaderInit()
{
int kmode_is_available = (sceKernelDevkitVersion() < 0x02000010);
if (kmode_is_available) {
/* Do nefarious kernel stuff here */
}
init_was_called = 1;
}
extern void _init(void);
int main(int argc, char *argv[])
{
/* Fanjita's EBOOT loader can be configured to skip the call to _init().
Since we need _init() for C++, we check to see if _init() has been
called. If it hasn't we call it manually, after determining whether or
not we can access the kernel. */
if (!init_was_called) {
_init();
}
...
} |
|
_________________ mICrO^NewOlds
ja_medina at hotmail dot com
There is no such thing as a moral or an immoral book.
Books are well written or badly written.
(Oscar Wilde) |
|
| Back to top |
|
 |
groepaz

Joined: 01 Sep 2005 Posts: 305
|
|
| Back to top |
|
 |
mICrO
Joined: 17 Oct 2005 Posts: 25 Location: Madrid (Spain)
|
Posted: Sun Dec 25, 2005 7:01 pm Post subject: Channel assigned error on 2.0 |
|
|
I first test my game engine on psp ver 2.0, and dosen't work, i check My log file and get something like :
| Code: |
MGE :-)
25/11/2005 - 09:48:24 Log Init
25/11/2005 - 09:48:24 Init Base app
25/11/2005 - 09:48:24 + Init Control
25/11/2005 - 09:48:25 + Init Control [Ok]
25/11/2005 - 09:48:25 + Init RenderDevice
25/11/2005 - 09:48:26 - Init VRAM Screen
25/11/2005 - 09:48:26 . Init Screen
25/11/2005 - 09:48:27 # Logging Screen class
25/11/2005 - 09:48:28 + Screen Size = 480x272
25/11/2005 - 09:48:29 + Clip Area = (0,0)-(479,271)
25/11/2005 - 09:48:29 . Init Screen [Ok]
25/11/2005 - 09:48:30 - Init VRAM Screen [Ok]
25/11/2005 - 09:48:31 - Init VRAM Screen
25/11/2005 - 09:48:31 . Init Screen
25/11/2005 - 09:48:32 # Logging Screen class
25/11/2005 - 09:48:33 + Screen Size = 480x272
25/11/2005 - 09:48:33 + Clip Area = (0,0)-(479,271)
25/11/2005 - 09:48:34 . Init Screen [Ok]
25/11/2005 - 09:48:35 - Init VRAM Screen [Ok]
25/11/2005 - 09:48:36 - Logging RenderDevice class
25/11/2005 - 09:48:36 . Screen Size = 480x272
25/11/2005 - 09:48:37 . Buffer Width = 512
25/11/2005 - 09:48:37 . Screen Format(RGBA) = 5:6:5:0
25/11/2005 - 09:48:38 + Init RenderDevice [Ok]
25/11/2005 - 09:48:39 + Init CMGESoundDevice
25/11/2005 - 09:48:39 - Init CMGEAudioChannel
25/11/2005 - 09:48:40 . Sound Thread Create [Ok]
25/11/2005 - 09:48:40 . Logging CMGEAudioChannel class
25/11/2005 - 09:48:41 # - id 0
25/11/2005 - 09:48:42 - Init CMGEAudioChannel [Ok]
25/11/2005 - 09:48:42 - Init CMGEAudioChannel
25/11/2005 - 09:48:43 . Sound Thread Create [Ok]
25/11/2005 - 09:48:44 . Logging CMGEAudioChannel class
25/11/2005 - 09:48:44 # - id 1
25/11/2005 - 09:48:45 - Init CMGEAudioChannel [Ok]
25/11/2005 - 09:48:46 - Init CMGEAudioChannel
25/11/2005 - 09:48:46 . Sound Thread Create [Ok]
25/11/2005 - 09:48:47 . Logging CMGEAudioChannel class
25/11/2005 - 09:48:48 # - id 2
25/11/2005 - 09:48:48 - Init CMGEAudioChannel [Ok]
25/11/2005 - 09:48:49 - Init CMGEAudioChannel
25/11/2005 - 09:48:50 . Sound Thread Create [Ok]
25/11/2005 - 09:48:50 . Logging CMGEAudioChannel class
25/11/2005 - 09:48:51 # - id 3
25/11/2005 - 09:48:52 - Init CMGEAudioChannel [Ok]
25/11/2005 - 09:48:52 - Init CMGEAudioChannel
25/11/2005 - 09:48:53 . Fail to assign channel 4
25/11/2005 - 09:48:54 . Logging CMGEAudioChannel class
25/11/2005 - 09:48:54 # - id -2144993277
25/11/2005 - 09:48:55 - Init CMGEAudioChannel [Fail]
25/11/2005 - 09:48:56 - Init CMGEAudioChannel
25/11/2005 - 09:48:56 . Fail to assign channel 5
25/11/2005 - 09:48:57 . Logging CMGEAudioChannel class
25/11/2005 - 09:48:58 # - id -2144993277
25/11/2005 - 09:48:58 - Init CMGEAudioChannel [Fail]
25/11/2005 - 09:48:59 - Init CMGEAudioChannel
25/11/2005 - 09:49:00 . Fail to assign channel 6
25/11/2005 - 09:49:00 . Logging CMGEAudioChannel class
25/11/2005 - 09:49:01 # - id -2144993277
25/11/2005 - 09:49:02 - Init CMGEAudioChannel [Fail]
25/11/2005 - 09:49:02 - Init CMGEAudioChannel
25/11/2005 - 09:49:03 . Fail to assign channel 7
25/11/2005 - 09:49:03 . Logging CMGEAudioChannel class
25/11/2005 - 09:49:04 # - id -2144993277
25/11/2005 - 09:49:05 - Init CMGEAudioChannel [Fail]
25/11/2005 - 09:49:06 - Logging CMGESoundDevice class
25/11/2005 - 09:49:06 + Init CMGESoundDevice [Fail]
25/11/2005 - 09:49:06 + Fail to init Sound device
25/11/2005 - 09:49:07 Init Base app [Fail]
|
Checking my code, i see that:
| Code: |
#if defined (PSP_VER)
//reserve the channel
m_id = sceAudioChReserve(num,max_buffer_size,(m_stereo?PSP_AUDIO_FORMAT_STEREO:PSP_AUDIO_FORMAT_MONO));
#else
m_id=num;
#endif
if(m_id>=0)
{
// channel reserved ok
#if defined (PSP_VER)
char sBuff[255];
sprintf(sBuff,"sound thread%d",m_id);
m_thread = sceKernelCreateThread(sBuff, ProcessSound, 0x12, 0x1000, 0, NULL );
if (m_thread >= 0)
{
CMGELog::SysLog(CMGELog::lInfo,"Sound Thread Create [Ok]");
sceKernelStartThread (m_thread, sizeof(int), &m_id);
}
else
{
CMGELog::SysLog(CMGELog::lError,"Error creating sound thread %s",sBuff);
CMGELog::SysLog(CMGELog::lError,"Sound Thread Create [Fail]");
m_bOk=false;
}
#else
#endif
}
else
{
CMGELog::SysLog(CMGELog::lError,"Fail to assign channel %d",num);
m_bOk=false;
}
|
I used all hardware channels, so I prepare samples and music a bit fastter, and left hardware mixer to mix then all, its use less cpu that mixing with the main MIPS, son for every channel I do:
| Code: |
m_id = sceAudioChReserve(num,max_buffer_size,(m_stereo?PSP_AUDIO_FORMAT_STEREO:PSP_AUDIO_FORMAT_MONO));
|
But thats, in 2.0 using eboot loader, work for channels from 0 to 3, but don't to channels from 4 to 7, seems like they are allready assigned, some how.
So, now, how to fixt it?, should I to call sceAudioChRelease, before reserved it, or should the loader have some 'option' to reset all before calle the eboot? _________________ mICrO^NewOlds
ja_medina at hotmail dot com
There is no such thing as a moral or an immoral book.
Books are well written or badly written.
(Oscar Wilde) |
|
| Back to top |
|
 |
mICrO
Joined: 17 Oct 2005 Posts: 25 Location: Madrid (Spain)
|
Posted: Sun Dec 25, 2005 7:23 pm Post subject: |
|
|
but, if its provide by the crt, why I get an error when the application its linked?
| groepaz wrote: | | it usually is provided by one of the CRT files, crtstart.o most likely. if you are still fiddling with your own toolchain, you have to come up with it yourself. |
_________________ mICrO^NewOlds
ja_medina at hotmail dot com
There is no such thing as a moral or an immoral book.
Books are well written or badly written.
(Oscar Wilde) |
|
| Back to top |
|
 |
Fanjita
Joined: 28 Sep 2005 Posts: 217
|
Posted: Mon Dec 26, 2005 2:01 am Post subject: |
|
|
Micro, you should try unassigning the channels yourself.
If it helps, let me know, and I'll incorporate something into the loader to do it automatically.
Thanks. _________________ Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you! |
|
| Back to top |
|
 |
mICrO
Joined: 17 Oct 2005 Posts: 25 Location: Madrid (Spain)
|
Posted: Thu Dec 29, 2005 8:33 am Post subject: |
|
|
Ok, thats Works, I tested, so if I used sceAudioChRelease to unassiging assigned channels, before assigned myself works OK under eboot loader 0.9.
Fanjita told me that the next version of the loader will take care of it.
| Fanjita wrote: | Micro, you should try unassigning the channels yourself.
If it helps, let me know, and I'll incorporate something into the loader to do it automatically.
Thanks. |
_________________ mICrO^NewOlds
ja_medina at hotmail dot com
There is no such thing as a moral or an immoral book.
Books are well written or badly written.
(Oscar Wilde) |
|
| Back to top |
|
 |
groepaz

Joined: 01 Sep 2005 Posts: 305
|
Posted: Mon Jan 02, 2006 12:16 pm Post subject: |
|
|
| Quote: |
but, if its provide by the crt, why I get an error when the application its linked?
|
probably because the way you are linking the app doesnt pull in crtstart.o :) try using gcc (not ld) for linking, that might fix it...depends on how your toolchain is set up. _________________ http://www.hitmen-console.org
http://hitmen.c02.at/files/yapspd/ |
|
| Back to top |
|
 |
mICrO
Joined: 17 Oct 2005 Posts: 25 Location: Madrid (Spain)
|
Posted: Wed Jan 04, 2006 7:20 am Post subject: |
|
|
Damm, I founded, I put _init declaration, by error, outside off extern "C" {, since I used c++, linker couldn't find it.
Now fixed.
Thanks groepa
| groepaz wrote: | | Quote: |
but, if its provide by the crt, why I get an error when the application its linked?
|
probably because the way you are linking the app doesnt pull in crtstart.o :) try using gcc (not ld) for linking, that might fix it...depends on how your toolchain is set up. |
_________________ mICrO^NewOlds
ja_medina at hotmail dot com
There is no such thing as a moral or an immoral book.
Books are well written or badly written.
(Oscar Wilde) |
|
| Back to top |
|
 |
hubevolution
Joined: 17 Mar 2004 Posts: 32
|
Posted: Wed Mar 15, 2006 5:20 pm Post subject: |
|
|
would these restrictions apply to 2.01+ eLoader too ?
Thx |
|
| Back to top |
|
 |
Fanjita
Joined: 28 Sep 2005 Posts: 217
|
Posted: Wed Mar 15, 2006 8:50 pm Post subject: |
|
|
Actually most of this advice is out of date now.
I'll update the post at some point in the near future, but in the meantime the main things you need to avoid if possible are:
- using true kernel-mode functionality, e.g. API functions / memory access that is only available in kernel mode. A lot of the common items are stubbed out by the loader (e.g. setting exception handlers, reassigning stdio) but not all.
- relying on mainline application initialisation (e.g. global variables, etc.) in attribute(constructor) functions. When trying to run a kernel-mode app, the loader will usually just NOP out the call to _init(), which runs these functions. _________________ Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you! |
|
| Back to top |
|
 |
hubevolution
Joined: 17 Mar 2004 Posts: 32
|
Posted: Wed Mar 15, 2006 8:57 pm Post subject: |
|
|
| thanks for fast reply fanjita ;) |
|
| Back to top |
|
 |
weak
Joined: 13 Jan 2005 Posts: 114 Location: Vienna, Austria
|
Posted: Fri May 19, 2006 6:53 pm Post subject: |
|
|
| fanjita: how about atrac support? i know, loads of work for you, but a lot of games would benefit from atrac support ;) |
|
| 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
|