What is Play! ?
Play! is a PlayStation2 emulator for Windows, macOS, UNIX, Android, iOS & web browser platforms. For more information about this project please visit the "About" section of this site.

Compatibility Status
Fetching compatibility status...

Development Log

Make "PS2 Invaders v1.6" by "InPulSe Team" work.
Posted on 2005-10-12 00:00:00
Finished the call request acknowledgement.

Added some basic functionality for the PADMAN IOP module. The way this module works is a bit wierd... You first call the open command and provide a pointer to 2 pad status structures that reside on the EE side. The PADMAN module updates these structures every frame with the new data without any request from the EE. It's just kinda wierd that it's updated automatically like this.

All I've done for now is faking the status of the controller as being "stable" for the program to continue without blocking in the pad initialization routines. I haven't think how this module is going to get the input values from the keyboard or joystick yet. The UI will need to call this module providing the button status in some way since it's not acceptable to have this module call the UI directly. But this isn't really important for now.

I've also implemented some menu items to disable DMAC and OS logging in the debugger.

There's an invalid instruction occuring right now (BLEZL). It's also trying to load the AMIGAMOD.IRX module and call some of its functions. The file system and IOP heap modules functions are also being called.

I don't really want to implement the AMIGAMOD module, but I don't think I'll have any choices to implement some basic functions to return values that will allow the demo to continue. But I'd like to implement the missing instruction and have some basic work on the file system module done tomorrow.

Make "PS2 Invaders v1.6" by "InPulSe Team" work.
Posted on 2005-10-10 00:00:00
After further reading, I think I've finally understood the SIF RPC communication protocol... Here
is a simplified description of the binding process:

- A client on the EE sends a BIND command through the SIF1 DMA channel.
- The SIF0 (on the IOP side) DMA channel triggers an interrupt when the transfer is done, invoking the SIF library interrupt handler.
- The interrupt handler looks up for the server to be bound with the client using the SID member of the packet.
- The server is found and the library copies the packet queue address (amongst other things) of this server in a new REND (request end) packet.
- This REND packet is sent back to the EE.
- The EE interrupt handler for the SIF0 (on the EE side) DMA channel is invoked.
- This handler copies the server packet queue address back to the client's binding information structure and signals a semaphore to indicate that the request is finished.

The method invocation process is similar to the binding process. I think what confused me was that there was the server code present on the EE side for some reason. There's also the fact that it will also listen to bind and call requests. Maybe the binding can be done from the IOP to the EE too...

With that understood, I was able to fix my code. I'm now able to acknowledge bind requests and I'm working on calling requests. I've had to use another dirty hack for the extra DMA transfer needed for transfering the marshalled arguments for the call request. I can't be bothered to implement those DMATag things right now. I'll finish the call request acknowledgement tomorrow.

Now I'm facing a design issue though... The proper and more compatible way to implement everything on the IOP side would be to start from booting the BIOS, loading each modules, and executing the code for all of them. But the hardware registers on the IOP side seem far worse than on the EE side... And there's a lot more of interrupt lines, more DMA channels, and most of this stuff isn't very well documented.

On the other side, emulating the modules on an higher-level by catching each SIF call requests and dispatching them to native code that will do the same job without dealing with lower level accuracy is the easiest thing to do. But many custom made IRX modules exist and there's no way someone could implement an high-level emulation for each of them. To give an example, almost every game uses a custom made IRX module for music and sound. And some seem to ship with already existing modules, but I have no idea if those have any changes compared to the ones included in the BIOS.

I think nSX2 and PCSX2 use the latter idea, but I'm not really sure about the way they deal with those custom IRX modules. I'm leaning towards this method too, and I've started to implement it this way... More stuff to ponder about...

Make "PS2 Invaders v1.6" by "InPulSe Team" work.
Posted on 2005-10-08 00:00:00
Humm, apparently I got the SIF RPC protocol wrong. I'm still not sure about it yet, but I know what I've implemented is wrong... I'll probably need to add a virtual IOP now and load the needed modules from the BIOS into the IOP memory space...

Anyhow, more info about this soon.

Make "PS2 Invaders v1.6" by "InPulSe Team" work.
Posted on 2005-10-07 00:00:00
The exception handling logic is now up and running. Making the program counter change in the exception handler caused me some trouble, but I managed to do it by setting the execution quota to 1 and thus forcing the cached code to exit back to the main virtual machine loop. This is something I'd qualify as a shameless hack, but that's the only thing I could do without changing the code recompilation logic significantly. If I get to rewrite this part, I'd probably need to think about including this missing ability.

Also rewrote the "PushConditionBit" function in the recompiler. This function emits the necessary code to take a condition code and push either 0 or 1 depending of the contents of the program status register. The old method was using 5 instructions to complete this task... This new one takes 2 if the condition is true and 3 if the condition is false. This is used quite a lot, but I don't know if it'll give a significant speed boost.

State saving is seriously screwed up with the new OS additions. I'll need to fix those soon.

Now, with the exception handler working, the program on the EE can receive a 0x80000001 packet and set the register accordingly. The main program isn't stuck anymore waiting for the register to be set to something else than 0.

Coming up next is the implementation binding/calling commands...

Make "PS2 Invaders v1.6" by "InPulSe Team" work.
Posted on 2005-10-06 00:00:00
I'm in the process of implementing the exception handler. It's a bit annoying because you must consider that an interrupt could occur while servicing an interrupt. So it must be recursive in some way.

I've decided to call the interrupt handler directly from the INTC module for now. Adding a special instruction at 0x80000180 to trigger the handler wasn't a good idea because virtual memory isn't implemented yet. With the way the address translation is currently implemented, the exception vector memory would fall into the memory the demo can use.

I'm going to add a little instruction in the BIOS memory area for the user interrupt handlers to return to when they're done. This instruction will retrigger the exception handler code. It should be able to continue its execution when called from this instruction.

There's some stuff I've been thinking to change/add while playing around in the code today:

- Merge all the DMAC channel handling logic into one. It's just getting annoying to replicate all the code for a channel.

- Change the way the disassembler works. The way it works now is that there is a big switch statement in a function which decides which string to use. The problem with this is that there's no way to dynamically change the strings you'd like to use. This isn't an urgent change, but it would be nice to have.

Make "PS2 Invaders v1.6" by "InPulSe Team" work.
Posted on 2005-10-05 00:00:00
Implemented two more system calls: SifSetReg and SifGetReg.

Also implemented registers in the SIF module. The program plays with registers that have the most significant bit set (ex.: 0x80000000, 0x80000001) though, and I don't know what these are for. I'm just assuming they are some user-usable registers for now.

The program is now stuck at sending a 0x80000002 (Initialize) command to the SIF, then waiting for an "sreg" to be set to something else than zero. Sregs can only be set by the interrupt handler for the SIF0 DMA channel if it receives a 0x80000001 (SetSREG) command.

I was assuming at the beginning that once the SIF received a command, it would reply back to the EE with the same command, but it doesn't seem to be the case for 0x80000002. For added confusion, there's also a 0x80000002 command sent earlier and the only difference between those 2 instances is the value set in the SIF command header: The earliest sets a member to 0, and the latest sets it to 1. So, I'm assuming that this 1 must have a special meaning that makes a 0x80000001 to be sent that changes the value of the sreg. No clue what "sreg" stands for too...

So, I've pretty much set up everything up to the point where I gotta trigger an interrupt on the EE. Of course, this interrupt must be processed by the BIOS or OS first. Then, it's going to be thier responsibility to call the various interrupt handlers. Two things are bugging me though:

- I don't know if I should call the OS directly when an interrupt occurs or have the EE jump normally to the exception vector (0x80000180) and have the OS hook this address.

- And I'm not sure about the way I'm going to call the interrupt handler... I have its address and I can change the program counter to it, but once it's done executing, it needs to come back and reinvoke the OS code. I'll probably need to save the state of the OS just before executing the interrupt routine or something in the lines of this.

I'll ponder those a bit more and I'll try to find a working solution for tomorrow.

Make "PS2 Invaders v1.6" by "InPulSe Team" work.
Posted on 2005-10-04 00:00:00
Tidied the OS (Operating System) code a little bit. Also started to implement some system calls that are required for that whole SIF thing. System calls I've added are (in no particular order):

CreateSema()
DeleteSema()
AddDmacHandler()

Of course, the implementation of these can't be better than my understanding of them... Which mean they probably (read surely) don't have the same behavior as the ones provided by the PS2 BIOS. But they should do the job for this particular case I'm studying right now.

Tomorrow, I gotta implement the rest of the needed system calls needed for basic SIF handling. Then I should be able to start the work on triggering the interrupt from the DMAC when the SIF needs to send a reply to the EE.

Make "PS2 Invaders v1.6" by "InPulSe Team" work.
Posted on 2005-10-03 00:00:00
Implemented the missing opcodes JALR, SLLV, SRAV.

I'm still reading and implementing the SIF stuff slowly. I think I'm starting to understand the RPC protocol. I implemented the function to receive the SIF commands, now all I need to do is do the appropriate processing on the different commands and call the interrupt handler on the DMAC channel 5. More information about this tomorrow.

Make "PS2 Invaders v1.6" by "InPulSe Team" work.
Posted on 2005-10-02 00:00:00
This demo has nothing out of the ordinary graphics wise, but it uses the IOP for sound, controller input and memory card saving. I don't know much about the mechanics of the IOP and the communication between the EE and IOP yet.

I've been spending my time reading about it and that's what I can say from my reading session:

- Both sides have interrupt handlers set on the DMAC interrupt line to be informed when new data has arrived.
- DMA channel 5 is used for incoming messages by the EE.
- DMA channels 6 or 7 is used for incoming messages by the IOP.
- On the EE side, this program calls SifSendCmd system call to send data to the IOP.
- There's a set of registers on the IOP that are accessible through system calls on the EE side (SifGetReg and SifSetReg). These registers contain the address of the DMA buffer on the IOP side amongst other things.

That's pretty much what I can say about it right now. I'll keep on reading on the next days to understand it better.

I've had to implement DI and MFC0 in the EE core. The program seems to test the 16th bit of the Status register, which I'm not sure about its use. It's marked as "implementation specific" in the general COP0 documentation from MIPS.

There's also a missing instruction (JALR) which prevents the demo from showing stuff, so no screen shots for now.

Make "cubemastah.elf" work.
Posted on 2005-10-01 00:00:00
Finally got the depth testing (z-buffering) to work. Apparently, with OpenGL, big values for the near and far clipping planes will make the z value of a pixel to go towards 0 and since this demo used a "greater" condition for testing it was making all the pixels fail. I'm using a value of -65535 for now for the far clipping plane position even though the GS supports 32-bits values for the z component. If bigger values start to appear in other programs, I'll have to do something else, but for now, this will do the job.

I also found out why depth testing was disabled one frame out of two. It was caused by a bug with the recompiler that prevented instructions in the delay slot of branching instructions that appear at the start of a block to be executed. Fixed that.

Here's the final result:


Screenshot #000032


This should be all for this demo. I also tested the previous ones and none seemed to be broken by the new additions/fixes. I also found another demo that was working while playing around with the program:


Screenshot #000033


It's nothing surprising though since this demo was written by the same author as the Cube Mastah demo.

Next I'll try to use a demo that uses either the VU or the IOP for added challenge.

<< Older Log Entries Newer Log Entries >>