PS2 Linux Programming


Development Framework Wrapper Classes





Developing for the PlayStation2 under Linux requires the careful allocation of memory and alignment of data within memory. There are also several initialisation steps required when using the SPS2 Direct Access Environment. In this tutorial a set of wrapper classes will be described which encapsulates the initialisation and use of SPS2 and handles the allocation and use of memory. Note that the internal functionality and operation of these classes will not be described, but rather the use and purpose of the class methods will be presented.



Framework Files


The development framework consists of the following 12 files:


dma.c, dma.cpp, PS2Defines.h, ps2mathis.h, ps2maths.cpp, ps2matrix4x4.h, ps2matrix4x4.cpp, ps2vector4.h, ps2vector4.cpp, singleton.h, sps2wrap.h and sps2wrap.cpp.


sps2wrap handles the initialisation and use of SPS2 and the allocation of memory. Two different types of memory can be allocated: static memory which is used to store data that does not change from frame to frame, and dynamic memory which contains data that does/can change from frame to frame. An example of static data is the vertex data for a 3D model while dynamic data may be the matrices that are used to transform the vertex data of a model.


dma contains a set of classes which are used to compile and organise data within memory. The data is then sent, normally to VIF1 using the direct memory access controller, for further processing.


ps2matrix4x4 and ps2vector4 contain respectively a set of classes to handle the organisation and manipulation of matrix and vector data, PS2Defines.h contain defines and typedefs which are used by the classes of the framework and singleton.h contains a singleton class which is used to help organise the operation of the framework.



Minimal Program


A minimal program to initialise SPS2, allocate some memory and set up a render loop is given below.


#include <sps2lib.h>

#include <sps2tags.h>

#include <sps2util.h>

#include <sps2regstructs.h>

#include <assert.h>

#include <memory.h>

#include <signal.h>

#include "PS2Defines.h"

#include "ps2maths.h"

#include "ps2matrix4x4.h"

#include "pad.h"

#include "sps2wrap.h"

#include "dma.h"




bool g_bLoop = true;


void sig_handle(int sig)


    g_bLoop = false;



int main()



    SPS2Manager.Initialise(4096);  // 4096 * 4K Pages = 16MB Total

    VIFStaticDMA.Initialise(1536); // 1536 * 4K Pages = 6MB Static DMA

    VIFDynamicDMA.Initialise(256); // 256 * 4K Pages * 2 Buffers = 2MB Dynamic DMA


    // Register our signal function for every possible signal (e.g. ctrl + c)

    for(int sig=0; sig<128; sig++)

        signal(sig, sig_handle);


    // Set up the DMA packet to clear the screen. We want to clear to blue.

    SPS2Manager.InitScreenClear(0, 0, 0x40);


    // Render Loop







        // Do rendering here





    return 0;


The header files are all required to use the framework. All the memory is allocated in 4kByte units called a page. SPS2Manager.Initialise() is called first to allocate the required amount of pages, then VIFStaticDMA.Initialise() and VIFDynamic.Initialise() are called to initialise static and dynamic memory respectively within the memory allocated with SPS2Manager.Initialise(). Note that the dynamic memory is double buffered. One of the buffers can be transferred to the VIF for processing whilst the other buffer is being filled with data for the next frame to be rendered. Double buffering helps the programmer to take advantage of the parallelism of the PS2.


All of the 128 possible signals are registered with the signal handler function at the top of the code. Any interrupt signal will set the g_bloop variable to false thus terminating the program.


SPS2Manager.InitScreenClear() initialises the packet that will be used each frame to clear the screen. The parameters passed to this method are the Red, Green and Blue components of the background colour respectively.


The render loop consists of three calls: VIFDynamicDMA.Fire() ends the DMA chain being compiled in the current buffer, checks to see that the VIF DMA channel is idle, then starts the transfer of the current buffer of data. SPS2Manager.BeginScene() inserts data into the new buffer about to be  compiled, to clear the screen to the colour specified earlier. SPS2Manager.EndScene() waits for the previous frame of data to be rendered to the offscreen buffer then swaps the on-screen and off-screen buffers. Notice that using this scheme allows for the transfer of data to the VIF to be ongoing whilst the next buffer of data is being compiled, and as stated above this takes advantage of the parallelism of the PS2.


The processing steps being undertaken in the render loop are described again below to help the understanding of the scheme.




Wait for the transfer of VIFBuffer0 to complete.

End the DMA chain being written to VIFBuffer1.

Start transfer of VIFBuffer1.

Point to the start of VIFBuffer0 for writing.



Enter clear screen data into VIFBuffer0



Enter render data into VIFBuffer0



Wait for VIFBuffer1 data to be rendered by the GS

Wait for a Vertical synchronisation pulse from the monitor/television

Swap the video buffers



Wait for the transfer of VIFBuffer1 to complete.

End the DMA chain being written to VIFBuffer0.

Start transfer of VIFBuffer0.

Point to the start of VIFBuffer1 for writing.



Enter clear screen data into VIFBuffer1



Enter render data into VIFBuffer1



Wait for VIFBuffer0 data to be rendered by the GS

Wait for a Vertical synchronisation pulse from the monitor/television

Swap the video buffers


Repeat steps








This tutorial has presented a basic framework for rendering under PS2 Linux.




Dr Henry S Fortuna

University of Abertay Dundee