This course is a deep dive into the world of PlayStation programming! We'll explore the PS1 hardware, understand its sub-components, and learn how to code games using MIPS assembler & the C programming language. We'll also learn how to use a PS1 SDK library paired with a modern development toolchain to be more productive and push fast polygons out of our console.
PS1 Programming with MIPS Assembly & C
We are about to enter the 5th generation of 32-bit consoles. This era brings with it many technology milestones, such as the adoption of CPUs based on RISC architecture and a preference for coding using a high-level language instead of writing games using plain assembly. We will start by learning the basics of MIPS assembly and evolve to use a C compiler with a PS1 SDK to develop our final project.
The tools you'll need
The original SDK was designed for Windows/PC, so you can either use the original 16/32-bit libraries on a 32-bit operating system (Windowx XP), or you can use a modern C compiler with Visual Studio Code on a 64-bit operating system (Windows 10/11). Emulating a Windows system on macOS or Linux is also possible!
Do I need a real PS1?
Not at all. You can easily run all the exercises and the final project on a PlayStation emulator. At the end, we will burn a CD ISO and test it on a real console, but that's optional.
Is this course for you?
This is a self-contained course teaching concepts from the ground up. However, it is expected from students a basic understanding of coding (if-else, loops, functions). If you like retro programming & want to learn more about the early days of 3D games, then this course is definitely for you!
About the Author: Gustavo Pezzi
Watch Online 189 lessons
| # | Lesson Title | Duration | Access |
|---|---|---|---|
| 1 | Starting our Journey Demo | 12:19 | |
| 2 | How to Take this Course | 02:59 | |
| 3 | Placing the PlayStation in History | 10:50 | |
| 4 | PS1 Hardware Overview | 14:10 | |
| 5 | The MIPS CPU | 09:54 | |
| 6 | Memory & Endianness | 07:41 | |
| 7 | Memory Map | 12:13 | |
| 8 | CPU Registers & Load Instructions | 15:53 | |
| 9 | Store, Add, & Subtract Instructions | 07:11 | |
| 10 | Jump & Branch Instructions | 07:03 | |
| 11 | Exercise: Our First MIPS Code | 02:47 | |
| 12 | Going Over Our First MIPS Code | 05:11 | |
| 13 | Installing the ARMIPS Assembler | 06:38 | |
| 14 | Assembling our MIPS Code | 04:09 | |
| 15 | PSX-EXE File Format | 04:43 | |
| 16 | Emulator & Step-By-Step Execution | 08:03 | |
| 17 | Fixing Off-By-One Error | 03:05 | |
| 18 | Pseudo-Instructions | 07:53 | |
| 19 | The MIPS Pipeline | 11:00 | |
| 20 | Some Warm Up Exercises | 06:57 | |
| 21 | Solving our Warm Up Exercises | 15:08 | |
| 22 | Register Shorthand | 04:57 | |
| 23 | Factorial Exercise | 05:40 | |
| 24 | Solving our Factorial Exercise | 08:57 | |
| 25 | Factorial Subroutine | 10:54 | |
| 26 | Negative Numbers | 11:45 | |
| 27 | Sign Extension | 06:24 | |
| 28 | Logical Instructions | 06:07 | |
| 29 | Bitshifting Instructions | 09:30 | |
| 30 | Examples of CISC & RISC Machines | 06:46 | |
| 31 | CISC vs RISC Instructions | 15:46 | |
| 32 | The PlayStation Graphics System | 16:42 | |
| 33 | Drawing Primitives | 05:10 | |
| 34 | GPU Packets | 11:30 | |
| 35 | Sending Display Control Packets to GP1 | 19:03 | |
| 36 | Sending VRAM Access Packets to GP0 | 07:01 | |
| 37 | Clear Display Area | 06:35 | |
| 38 | Drawing a Flat-Shaded Triangle | 04:35 | |
| 39 | Drawing a Flat-Shaded Quad | 02:39 | |
| 40 | Drawing a Gouraud-Shaded Triangle | 01:54 | |
| 41 | Flat-Shaded Triangle Subroutine | 13:08 | |
| 42 | Coding our Flat Triangle Subroutine | 04:36 | |
| 43 | Stack & Stack Pointer | 11:17 | |
| 44 | Stack Parameters | 07:24 | |
| 45 | Stack & Heap Space | 05:16 | |
| 46 | Variables | 07:38 | |
| 47 | Variable Alignment | 06:20 | |
| 48 | Vector Alignment | 13:32 | |
| 49 | Copying Image Data to VRAM | 24:40 | |
| 50 | Using Bitshifting to Multiply & Divide | 06:57 | |
| 51 | 24BPP Display Mode | 14:38 | |
| 52 | Taking Advantage of our Delay Slots | 06:33 | |
| 53 | Moving from MIPS Assembly to C | 05:37 | |
| 54 | Installing Tools on Windows 11 | 14:17 | |
| 55 | Installing Tools on Windows XP | 19:31 | |
| 56 | Compiling a Simple Psy-Q Project | 12:38 | |
| 57 | Double-Buffer Screen | 28:44 | |
| 58 | Psy-Q Integer Data Types | 04:10 | |
| 59 | Psy-Q Primitive Types | 07:30 | |
| 60 | Ordering Table & Primitive Buffer | 17:27 | |
| 61 | Sorting Primitives into the OT | 15:13 | |
| 62 | Sorting a Gouraud Quad into the OT | 05:47 | |
| 63 | A Review of Pointers | 12:14 | |
| 64 | The Arrow Operator | 11:38 | |
| 65 | A Review of 3D Projection | 15:39 | |
| 66 | Vertices & Face Indices | 12:24 | |
| 67 | The Geometry Transformation Engine | 07:11 | |
| 68 | Basic 3D Transformations | 10:05 | |
| 69 | RotTransPers Function | 15:21 | |
| 70 | Coding a Rotating 3D Cube | 14:27 | |
| 71 | Normal Clip | 06:33 | |
| 72 | Coding Quads as Cube Faces | 03:12 | |
| 73 | Reviewing Floating-Point Numbers | 15:10 | |
| 74 | Fixed-Point Numbers | 15:28 | |
| 75 | Implementing a Bouncing Cube | 10:52 | |
| 76 | Different Transform Matrix per Object | 16:11 | |
| 77 | Wait, Can I use Floats? | 02:50 | |
| 78 | GTE Register Set | 10:25 | |
| 79 | Inline GTE Instructions | 15:19 | |
| 80 | RTPT vs. RTPS | 08:36 | |
| 81 | Reading Joypad State | 17:36 | |
| 82 | Joypad Input with BIOS Functions | 17:05 | |
| 83 | Joypad Header & Implementation | 22:16 | |
| 84 | Header File for OT & Primitive Buffer | 25:41 | |
| 85 | Header File for Display Routines | 06:04 | |
| 86 | Camera Space | 10:51 | |
| 87 | The Look-At Transformation | 15:23 | |
| 88 | The LookAt Function | 16:21 | |
| 89 | Coding the Look-At Camera Model | 20:58 | |
| 90 | CD-ROM Basics | 21:32 | |
| 91 | Generating an ISO on Windows XP | 14:35 | |
| 92 | Generating an ISO on Windows 11 | 09:19 | |
| 93 | A Function to Read Files from the CD | 21:07 | |
| 94 | Understanding the MODEL.BIN File | 07:07 | |
| 95 | Dynamically Allocating Buffers | 08:23 | |
| 96 | Heap Initialization on Windows 11 | 07:06 | |
| 97 | Interpreting Bytes as Numbers | 15:03 | |
| 98 | Handling Different Order of Bytes | 09:40 | |
| 99 | Reading Vertices & Faces from a File | 13:20 | |
| 100 | UV Coordinates, TPAGE, & CLUT | 17:28 | |
| 101 | Installing TIM Tool | 03:18 | |
| 102 | TIM File Format | 10:39 | |
| 103 | Read TIM File from the CD | 19:42 | |
| 104 | Textured Cube Faces | 17:44 | |
| 105 | Wobbly Textures | 12:24 | |
| 106 | Polygon Jitter | 02:54 | |
| 107 | Dev Tools CD Samples | 08:33 | |
| 108 | Intro to our Final Project | 09:04 | |
| 109 | Importing Project Assets | 03:54 | |
| 110 | PRM File Layout | 13:38 | |
| 111 | Reading Object Name from PRM File | 14:35 | |
| 112 | Reading Vertices from PRM File | 10:27 | |
| 113 | Handling Different Primitive Types | 22:50 | |
| 114 | Reading Primitives from PRM File | 13:23 | |
| 115 | Drawing Flat-Shaded Object Faces | 24:45 | |
| 116 | Using sizeof with Variable Name | 03:00 | |
| 117 | CMP File Layout | 11:01 | |
| 118 | Reading Number of Textures from File | 06:51 | |
| 119 | Reading TIM Sizes from File | 12:32 | |
| 120 | A Function to Extract LZSS Data | 10:47 | |
| 121 | Texture Structs | 15:12 | |
| 122 | Uploading CMP Textures to VRAM | 18:59 | |
| 123 | Global Texture Store Array | 13:51 | |
| 124 | Rendering Textured Triangles | 06:44 | |
| 125 | Visualizing Textured 3D Objects | 06:56 | |
| 126 | Loading Multiple CMP Files | 11:40 | |
| 127 | Exercise: Linked List of Objects | 08:48 | |
| 128 | Linked List Implementation | 14:36 | |
| 129 | Joypad Press & Release | 02:33 | |
| 130 | Reading Scene Objects from CD | 20:30 | |
| 131 | Camera-Object Distance Check | 11:15 | |
| 132 | Drawing Scene Objects | 08:10 | |
| 133 | Track Sections & Faces | 14:31 | |
| 134 | Structs for Sessions & Faces | 07:48 | |
| 135 | Reading Vertices, Faces, & Sections | 20:46 | |
| 136 | Function to Render Track Sections | 22:59 | |
| 137 | Shrinking Track Vertices | 15:24 | |
| 138 | Exercise: Testing Face Flags | 06:46 | |
| 139 | Drawing Quad Lines | 05:39 | |
| 140 | Avoiding the GTE 16-bit Limitation | 11:47 | |
| 141 | Clamping Overflow Values | 18:20 | |
| 142 | Loading Track Texture Tiles | 24:24 | |
| 143 | Manually Position Textures in VRAM | 15:08 | |
| 144 | Loading Track Face UV Coords | 10:12 | |
| 145 | Flip Face Texture | 05:10 | |
| 146 | Tessellation & Polygon Subdivision | 13:14 | |
| 147 | Drawing Quads Recursively | 12:35 | |
| 148 | A Function to Draw Quads Recursively | 15:29 | |
| 149 | Subdividing UV Coordinates | 09:33 | |
| 150 | T-junctions | 13:03 | |
| 151 | Ship Struct | 08:02 | |
| 152 | Adding the Ship Header File | 03:58 | |
| 153 | Movement in Game Physics | 08:04 | |
| 154 | Changing the Thrust Magnitude | 19:02 | |
| 155 | Applying the Thrust Force | 16:08 | |
| 156 | Yaw, Pitch, & Roll | 09:47 | |
| 157 | Populating our Rotation Matrix | 15:59 | |
| 158 | Coding the Object's Orientation | 14:27 | |
| 159 | Drawing XYZ Axis | 06:15 | |
| 160 | Accelerating in the Nose's Direction | 10:32 | |
| 161 | Placing Camera Behind the Ship | 07:53 | |
| 162 | Yaw Velocity | 19:20 | |
| 163 | Maximum Yaw Velocity | 05:45 | |
| 164 | Roll Left & Right | 11:01 | |
| 165 | Rethinking Section Rendering | 09:33 | |
| 166 | Initializing Ship's Nearest Section | 11:58 | |
| 167 | Update Ship's Nearest Section | 07:44 | |
| 168 | Rendering Track Ahead | 10:52 | |
| 169 | Clamping Track Vertices to 16 bits | 03:24 | |
| 170 | Loading Track Session Normals | 10:00 | |
| 171 | Drawing Section Normals | 07:17 | |
| 172 | Loading the Section Base Vertex | 10:02 | |
| 173 | Projected Ship Height | 10:20 | |
| 174 | Coding the Projected Ship Height | 09:46 | |
| 175 | Track Attraction & Repulsion Forces | 08:20 | |
| 176 | Preventing Negative Height Values | 04:01 | |
| 177 | Audio & SPU | 15:37 | |
| 178 | Converting WAV to VAG | 09:42 | |
| 179 | Playing a VAG Sound Effect | 20:53 | |
| 180 | Pitch & Sampling Frequency | 05:01 | |
| 181 | Exercise: Countdown Audio | 01:36 | |
| 182 | Countdown Sound Effects | 04:54 | |
| 183 | Background Music | 09:32 | |
| 184 | Recording an Audio Track | 06:23 | |
| 185 | Adding Audio Track to ISO | 13:50 | |
| 186 | Play Audio Track Implementation | 10:20 | |
| 187 | Play Background Audio Track | 04:30 | |
| 188 | Adding Scene Objects & Audio | 02:33 | |
| 189 | Conclusion & Next Steps | 09:58 |
Get instant access to all 188 lessons in this course, plus thousands of other premium courses. One subscription, unlimited knowledge.
Learn more about subscription