PlayStation 1
Overview
Every Instruction on this page is for Linux.
The PlayStation 1 port is currently under development in the Git "main" branch.
If I use the word PSX it is equivalent to the PlayStation 1.
Requirements
GNU BinUtils
Compiler needs GNU Binutils. Download a recent version from https://ftp.gnu.org/gnu/binutils/ . Then run shell commands:
./tar -xf <binutils.tar.gz> ./cd <binutils> ./mkdir build ./cd build ../configure --prefix=/usr/local/mipsel-unknown-elf --target=mipsel-unknown-elf --with-float=soft make -j$(nproc) sudo make install export PATH="/usr/local/mipsel-unknown-elf/bin:$PATH"
Now you can go two ways:
1) Let the binaries as they are and always use the compiler option
-XP/usr/local/mipsel-unknown-elf/bin/mipsel-unknown-elf-
2) Create symlinks
sudo ln -s /usr/local/mipsel-unknown-elf/bin/mipsel-unknown-elf-as /usr/bin/mipsel-ps1-as sudo ln -s /usr/local/mipsel-unknown-elf/bin/mipsel-unknown-elf-ld /usr/bin/mipsel-ps1-ld sudo ln -s /usr/local/mipsel-unknown-elf/bin/mipsel-unknown-elf-objcopy /usr/bin/mipsel-ps1-objcopy
PSY-Q-SDK
To compile something You need the converted PSY-Q-SDK to the ELF format
You can go two ways:
1) Clone it directly
git clone https://key-real@git.code.sf.net/p/psy-q-sdk-elf/code psy-q-sdk
2) Use the original and convert it by your self
- Download the official SDK:
https://www.psxdev.net/downloads.html
- Download the converter:
https://gitlab.com/jype/psyq2elf
from now on I assume the SDK is in following Folder:
/home/ps1/psy-q-sdk
Real Hardware
You need a PlayStation 1 with the MOD CHIP.
Emulator
- I recommend to use PCSX-REDUX https://github.com/grumpycoders/pcsx-redux
(I use Arch Linux and it is in my AUR Repo: pcsx-redux-git)
- DuckStation
https://github.com/stenzek/duckstation?tab=readme-ov-file#downloading-and-running
(I use Arch Linux and it is in my AUR Repo: duckstation-git)
- ePSXe
https://www.epsxe.com/
(I use Arch Linux and it is in my AUR Repo: epsxe)
PSX BIOS
You can use
a) the original Sony BIOS:
https://gist.github.com/juanbrujo/cf55d223ad01927a48f9ebac9f50bdee
b) OpenBIOS from the PCSX-REDUX project:
https://github.com/grumpycoders/pcsx-redux/tree/main/src/mips/openbios
Building
1) Get the newest version of FPC trunk:
git clone https://gitlab.com/freepascal.org/fpc/source.git fpc
2) Compile and install the the compiler:
make clean
If you created the symlinks to the mipsel binutils just do:
sudo make crossinstall OS_TARGET=ps1 CPU_TARGET=mipsel
If not do:
sudo make crossinstall OS_TARGET=ps1 CPU_TARGET=mipsel CROSSOPT="-XP/usr/local/mipsel-unknown-elf/bin/mipsel-unknown-elf-"
Compiling programs
When compiling programs, you should always enable smartlinking by adding these two options to the compiler:
-CX -XX
and you have to specify the path to the PSY-Q-SDK:
-Fl/home/ps1/psy-q-sdk
so your compile command should look like this:
ppcrossmipsel test.pas -Tps1 -CX -XX -Fl/home/ps1/psy-q-sdk
or if you have no symlinks to binutils:
ppcrossmipsel test.pas -Tps1 -CX -XX -Fl/home/ps1/psy-q-sdk -XP/usr/local/mipsel-unknown-elf/bin/mipsel-unknown-elf-
Hello World example
{$MODE OBJFPC}
uses libstd;
begin
printf('HELLO from FPC'#10);
end.
Here's what this program produces in the PCSX-Redux emulator when You switch MainMenu->Debug->Show Logs:
HELLO from FPC
Cube example
{$MODE OBJFPC}
uses libstd, libetc, libgpu, libgte;
const
MODE_NTSC = 0;
MODE_PAL = 1;
OTSIZE = 4096; // Ordering table size
vertices : array [0..7] of SVECTOR = ( // Cube
(vx: -128; vy: -128; vz: -128; pad: 0 ),
(vx: 128; vy: -128; vz: -128; pad: 0 ),
(vx: 128; vy: -128; vz: 128; pad: 0 ),
(vx: -128; vy: -128; vz: 128; pad: 0 ),
(vx: -128; vy: 128; vz: -128; pad: 0 ),
(vx: 128; vy: 128; vz: -128; pad: 0 ),
(vx: 128; vy: 128; vz: 128; pad: 0 ),
(vx: -128; vy: 128; vz: 128; pad: 0 ));
faces : array [0..35] of smallint = ( // Cube
0, 3, 2, // top
0, 2, 1, // top
4, 0, 1, // front
4, 1, 5, // front
7, 4, 5, // bottom
7, 5, 6, // bottom
5, 1, 2, // right
5, 2, 6, // right
2, 3, 7, // back
2, 7, 6, // back
0, 4, 7, // left
0, 7, 3 // left
);
type
DoubleBuff = packed record // Screen
draw : DRAWENV;
disp : DISPENV;
ot : array[0..OTSIZE] of dword; // Ordering table
end;
var
screen : array [0..1] of DoubleBuff; // Struct to hold the display & draw buffers
currbuff : byte; // Holds the current buffer number (0 or 1)
i : longint;
otz : longint; // Current Ordering table Entry
poly : array [0..11] of POLY_G3; // Cube
rotation : SVECTOR;
translation : VECTOR;
transform : MATRIX;
p : pointer;
flg : pointer;
nclip : longint; // Is cliped?
procedure setRGB0(var c: DRAWENV; r, g, b: byte);
begin
c.r0:=r;
c.g0:=g;
c.b0:=b;
end;
procedure ScreenInit(width, height: dword);
var
mode : byte;
begin
// Init
ResetGraph(0);
InitGeom();
SetGraphDebug(0);
// Set Display Mode
if height = 240 then mode:= MODE_NTSC;
if height = 256 then mode:= MODE_PAL;
SetVideoMode(mode);
// Init Buffers
SetDefDispEnv(@screen[0].disp, 0, 0, width, height);
SetDefDispEnv(@screen[1].disp, 0, height, width, height);
SetDefDrawEnv(@screen[0].draw, 0, height, width, height);
SetDefDrawEnv(@screen[1].draw, 0, 0, width, height);
// Set screen Offset
screen[0].disp.screen.x:= 0;
screen[0].disp.screen.y:= 0;
screen[1].disp.screen.x:= 0;
screen[1].disp.screen.y:= 0;
screen[0].disp.screen.h:= height;
screen[0].disp.screen.w:= 0;
screen[1].disp.screen.h:= height;
screen[1].disp.screen.w:= 0;
// Enable background clearing
screen[0].draw.isbg:= 1;
screen[1].draw.isbg:= 1;
// Set the background clear color
setRGB0(screen[0].draw, 0, 0, 0);
setRGB0(screen[1].draw, 0, 0, 0);
// Initialize and setup the GTE geometry offsets
SetGeomOffset(width div 2, height div 2);
SetGeomScreen(100);
SetDispMask(1);
// Set the current initial buffer
currbuff:= 0;
PutDispEnv(@screen[currbuff].disp);
PutDrawEnv(@screen[currbuff].draw);
end;
procedure DisplayFrame;
begin
// Set the current display & draw buffers
PutDispEnv(@screen[currbuff].disp);
PutDrawEnv(@screen[currbuff].draw);
// Draw Primetive
DrawOTag(@screen[currbuff].ot[OTSIZE - 1]);
// Draw Font
FntFlush(-1);
if currbuff = 0 then currbuff:= 1 else currbuff:= 0;
// Sync and wait for vertical blank
DrawSync(0);
VSync(0);
end;
begin
ScreenInit(320, 256);
// Setup Font
FntLoad(960, 256);
SetDumpFnt(FntOpen(0, 100, 200, 200, 0, 512));
rotation.vx:= 0;
rotation.vy:= 0;
rotation.vz:= 0;
translation.vx:= 0;
translation.vy:= 0;
translation.vz:= 500;
repeat
// Clear Ordering table
ClearOTagR(@screen[currbuff].ot[currbuff], OTSIZE);
// Transform
rotation.vx += 6;
rotation.vy += 8;
rotation.vz += 12;
RotMatrix(@rotation, @transform);
TransMatrix(@transform, @translation);
SetRotMatrix(@transform);
SetTransMatrix(@transform);
// Draw Polys
for i:= 0 to 11 do begin
setPolyG3(@poly[i]);
poly[i].r0:= 255; poly[i].g0:=0; poly[i].b0:= 0;
poly[i].r1:= 0; poly[i].g1:=255; poly[i].b1:= 0;
poly[i].r2:= 0; poly[i].g2:=0; poly[i].b2:= 255;
nclip:= RotAverageNclip3(@vertices[faces[i * 3 + 0]], @vertices[faces[i * 3 + 1]], @vertices[faces[i * 3 + 2]], @poly[i].x0, @poly[i].x1, @poly[i].x2, @p, @otz, @flg);
if nclip <= 0 then continue;
if (otz > 0) and (otz < OTSIZE) then addPrim(@screen[currbuff].ot[otz], @poly[i]);
end;
FntPrint('Hello from FPC');
DisplayFrame;
until false;
end.
Here's what this program produces in the PCSX-Redux emulator:
Create a PSX .iso
You need:
https://github.com/Lameguy64/mkpsxiso
and run:
mkpsxiso iso.xml
File iso.xml:
<?xml version="1.0" encoding="UTF-8"?> <iso_project image_name="myimage.iso" cue_sheet="myimage.cue"> <track type="data"> <identifiers system="PLAYSTATION" application="PLAYSTATION" volume="MYDISC" volume_set="MYDISC" publisher="MYPUBLISHER" data_preparer="MKPSXISO"/> <directory_tree> <file name="system.cnf" type="data" source="system.cnf"/> <file name="MAIN.PSX-EXE" type="data" source="test.psx-exe"/> </directory_tree> </track> </iso_project>
File system.cnf:
BOOT=cdrom:\MAIN.PSX-EXE;1 TCB=4 EVENT=10 STACK=801FFFF0
this file describes the boot process.
Information Sources
- full specification: https://psx-spx.consoledev.net/
- Psy-Q-SDK reference doc: https://dn720005.ca.archive.org/0/items/SCE-RunTimeLibRef-Mar2000/LibRef47.pdf
- MIPS Assembly: https://www.cs.unibo.it/~solmi/teaching/arch_2002-2003/AssemblyLanguageProgDoc.pdf
- Cool Course: https://pikuma.com/courses/ps1-programming-mips-assembly-language
- Discord Server: PSX.Dev