aboutsummaryrefslogtreecommitdiff
path: root/examples/system
diff options
context:
space:
mode:
authorJohn Wilbert M. Villamor <lameguy64@gmail.com>2020-04-24 19:01:28 +0800
committerJohn Wilbert M. Villamor <lameguy64@gmail.com>2020-04-24 19:01:28 +0800
commit1aa0e17df7c325a41de8cf8a57f52ed853f08bf3 (patch)
tree5ec7f69ca0104f2b0a41e2ee7d3cb0cf0c9c54c5 /examples/system
parente82da2abe4c264d4b48a48d79cf9b8e4c4fb8ab6 (diff)
downloadpsn00bsdk-1aa0e17df7c325a41de8cf8a57f52ed853f08bf3.tar.gz
Refined toolchain instructions, organized examples, added automatic retry for CdRead(), added FIOCSCAN ioctl in psxsio TTY driver, added tty and console examples.
Diffstat (limited to 'examples/system')
-rw-r--r--examples/system/childexec/ball16c.h16
-rw-r--r--examples/system/childexec/child.c319
-rw-r--r--examples/system/childexec/child_exe.s6
-rw-r--r--examples/system/childexec/makefile38
-rw-r--r--examples/system/childexec/parent.c305
-rw-r--r--examples/system/console/ball16c.h16
-rw-r--r--examples/system/console/main.c284
-rw-r--r--examples/system/console/makefile60
-rw-r--r--examples/system/timer/main.c154
-rw-r--r--examples/system/timer/makefile39
-rw-r--r--examples/system/tty/main.c145
-rw-r--r--examples/system/tty/makefile60
12 files changed, 1442 insertions, 0 deletions
diff --git a/examples/system/childexec/ball16c.h b/examples/system/childexec/ball16c.h
new file mode 100644
index 0000000..c79f273
--- /dev/null
+++ b/examples/system/childexec/ball16c.h
@@ -0,0 +1,16 @@
+unsigned int ball16c_size=192;
+unsigned char ball16c[] = {
+0x10,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0xc0,0x03,0x10,
+0x01,0x10,0x00,0x01,0x00,0x00,0x00,0x31,0xc6,0x73,0xce,0x94,0xd2,0x07,0x9d,
+0xd6,0xda,0x38,0xe3,0xef,0xbd,0x9b,0xef,0x8c,0xb1,0xc6,0x98,0xde,0xfb,0x4a,
+0xa9,0xa4,0x90,0xad,0xb5,0x00,0x00,0x8c,0x00,0x00,0x00,0xc0,0x03,0x00,0x01,
+0x04,0x00,0x10,0x00,0x00,0x00,0x10,0x22,0x12,0x02,0x00,0x00,0x00,0x10,0x32,
+0x33,0x23,0x11,0x04,0x00,0x00,0x23,0x55,0x66,0x35,0x72,0x47,0x00,0x20,0x52,
+0x86,0x68,0x36,0x12,0x97,0x0a,0x20,0x65,0xbb,0x8b,0x36,0x12,0x91,0x04,0x31,
+0x85,0xbb,0x68,0x35,0x12,0x97,0xdc,0x32,0x86,0x8b,0x56,0x35,0x73,0x97,0xa4,
+0x32,0x66,0x68,0x55,0x23,0x71,0x9e,0xac,0x32,0x65,0x56,0x33,0x13,0x71,0xce,
+0xa4,0x21,0x33,0x33,0x23,0x11,0xe7,0xc9,0xd4,0x12,0x22,0x22,0x13,0x71,0xe7,
+0xc9,0xda,0x10,0x17,0x11,0x77,0x77,0x9e,0x4c,0x0d,0x40,0x77,0x71,0xe7,0x9e,
+0xc9,0xd4,0x0d,0x00,0x94,0x99,0x99,0xcc,0x4c,0xda,0x00,0x00,0xa0,0xc4,0xc4,
+0x44,0xda,0x0d,0x00,0x00,0x00,0xd0,0xaa,0xda,0x0d,0x00,0x00
+};
diff --git a/examples/system/childexec/child.c b/examples/system/childexec/child.c
new file mode 100644
index 0000000..fb38b63
--- /dev/null
+++ b/examples/system/childexec/child.c
@@ -0,0 +1,319 @@
+#include <stdio.h>
+#include <psxapi.h>
+#include <psxgpu.h>
+#include <psxgte.h>
+#include <psxpad.h>
+#include <inline_c.h>
+
+/* OT and Packet Buffer sizes */
+#define OT_LEN 256
+#define PACKET_LEN 1024
+
+/* Screen resolution */
+#define SCREEN_XRES 320
+#define SCREEN_YRES 240
+
+/* Screen center position */
+#define CENTERX SCREEN_XRES>>1
+#define CENTERY SCREEN_YRES>>1
+
+
+/* Double buffer structure */
+typedef struct {
+ DISPENV disp; /* Display environment */
+ DRAWENV draw; /* Drawing environment */
+ int ot[OT_LEN]; /* Ordering table */
+ char p[PACKET_LEN]; /* Packet buffer */
+} DB;
+
+/* Double buffer variables */
+DB db[2];
+int db_active = 0;
+char *db_nextpri;
+
+
+/* For easier handling of vertex indices */
+typedef struct {
+ short v0,v1,v2,v3;
+} INDEX;
+
+/* Cube vertices */
+SVECTOR cube_verts[] = {
+ { -100, -100, -100, 0 },
+ { 100, -100, -100, 0 },
+ { -100, 100, -100, 0 },
+ { 100, 100, -100, 0 },
+ { 100, -100, 100, 0 },
+ { -100, -100, 100, 0 },
+ { 100, 100, 100, 0 },
+ { -100, 100, 100, 0 }
+};
+
+/* Cube face normals */
+SVECTOR cube_norms[] = {
+ { 0, 0, -ONE, 0 },
+ { 0, 0, ONE, 0 },
+ { 0, -ONE, 0, 0 },
+ { 0, ONE, 0, 0 },
+ { -ONE, 0, 0, 0 },
+ { ONE, 0, 0, 0 }
+};
+
+/* Cube vertex indices */
+INDEX cube_indices[] = {
+ { 0, 1, 2, 3 },
+ { 4, 5, 6, 7 },
+ { 5, 4, 0, 1 },
+ { 6, 7, 3, 2 },
+ { 0, 2, 5, 7 },
+ { 3, 1, 6, 4 }
+};
+
+/* Number of faces of cube */
+#define CUBE_FACES 6
+
+
+/* Light color matrix */
+/* Each column represents the color matrix of each light source and is */
+/* used as material color when using gte_ncs() or multiplied by a */
+/* source color when using gte_nccs(). 4096 is 1.0 in this matrix */
+/* A column of zeroes disables the light source. */
+MATRIX color_mtx = {
+ ONE, 0, 0, /* Red */
+ ONE, 0, 0, /* Green */
+ ONE, 0, 0 /* Blue */
+};
+
+/* Light matrix */
+/* Each row represents a vector direction of each light source. */
+/* An entire row of zeroes disables the light source. */
+MATRIX light_mtx = {
+ /* X, Y, Z */
+ -2048 , -2048 , -2048,
+ 0 , 0 , 0,
+ 0 , 0 , 0
+};
+
+char pad_buff[2][34];
+
+/* Function declarations */
+void init();
+void display();
+
+
+/* Main function */
+int main() {
+
+ int i,p,xy_temp;
+
+ SVECTOR rot = { 0 }; /* Rotation vector for Rotmatrix */
+ VECTOR pos = { 0, 0, 400 }; /* Translation vector for TransMatrix */
+ MATRIX mtx,lmtx; /* Rotation matrices for geometry and lighting */
+
+ POLY_F4 *pol4; /* Flat shaded quad primitive pointer */
+
+
+ /* Init graphics and GTE */
+ init();
+
+
+ /* Main loop */
+ while( 1 ) {
+
+ PADTYPE *pad = (PADTYPE*)pad_buff[0];
+
+ if( pad->stat == 0 ) {
+
+ // For digital pad, dual-analog and dual-shock
+ if( ( pad->type == 0x4 ) || ( pad->type == 0x5 ) || ( pad->type == 0x7 ) ) {
+
+ if( !(pad->btn&PAD_SELECT) ) {
+ break;
+ }
+
+ }
+
+ }
+
+ /* Set rotation and translation to the matrix */
+ RotMatrix( &rot, &mtx );
+ TransMatrix( &mtx, &pos );
+
+ /* Multiply light matrix by rotation matrix so light source */
+ /* won't appear relative to the model's rotation */
+ MulMatrix0( &light_mtx, &mtx, &lmtx );
+
+ /* Set rotation and translation matrix */
+ gte_SetRotMatrix( &mtx );
+ gte_SetTransMatrix( &mtx );
+
+ /* Set light matrix */
+ gte_SetLightMatrix( &lmtx );
+
+ /* Make the cube SPEEN */
+ rot.vx += 16;
+ rot.vz += 16;
+
+
+ /* Draw the cube */
+ pol4 = (POLY_F4*)db_nextpri;
+
+ for( i=0; i<CUBE_FACES; i++ ) {
+
+ /* Load the first 3 vertices of a quad to the GTE */
+ gte_ldv3(
+ &cube_verts[cube_indices[i].v0],
+ &cube_verts[cube_indices[i].v1],
+ &cube_verts[cube_indices[i].v2] );
+
+ /* Rotation, Translation and Perspective Triple */
+ gte_rtpt();
+
+ /* Compute normal clip for backface culling */
+ gte_nclip();
+
+ /* Get result*/
+ gte_stopz( &p );
+
+ /* Skip this face if backfaced */
+ if( p < 0 )
+ continue;
+
+ /* Calculate average Z for depth sorting */
+ gte_avsz4();
+ gte_stotz( &p );
+
+ /* Skip if clipping off */
+ /* (the shift right operator is to scale the depth precision) */
+ if( (p>>2) > OT_LEN )
+ continue;
+
+ /* Initialize a quad primitive */
+ setPolyF4( pol4 );
+
+ /* Set the projected vertices to the primitive */
+ gte_stsxy0( &pol4->x0 );
+ gte_stsxy1( &pol4->x1 );
+ gte_stsxy2( &pol4->x2 );
+
+ /* Compute the last vertex and set the result */
+ gte_ldv0( &cube_verts[cube_indices[i].v3] );
+ gte_rtps();
+ gte_stsxy( &pol4->x3 );
+
+ /* Load primitive color even though gte_ncs() doesn't use it. */
+ /* This is so the GTE will output a color result with the */
+ /* correct primitive code. */
+ gte_ldrgb( &pol4->r0 );
+
+ /* Load the face normal */
+ gte_ldv0( &cube_norms[i] );
+
+ /* Normal Color Single */
+ gte_ncs();
+
+ /* Store result to the primitive */
+ gte_strgb( &pol4->r0 );
+
+ /* Sort primitive to the ordering table */
+ addPrim( db[db_active].ot+(p>>2), pol4 );
+
+ /* Advance to make another primitive */
+ pol4++;
+
+ }
+
+ /* Update nextpri variable */
+ /* (IMPORTANT if you plan to sort more primitives after this) */
+ db_nextpri = (char*)pol4;
+
+ /* Swap buffers and draw the primitives */
+ display();
+
+ }
+
+ StopPAD();
+
+ return 0;
+
+}
+
+void init() {
+
+ /* Reset the GPU, also installs a VSync event handler */
+ ResetGraph( 0 );
+
+ /* Set display and draw environment areas */
+ /* (display and draw areas must be separate, otherwise hello flicker) */
+ SetDefDispEnv( &db[0].disp, 0, 0, SCREEN_XRES, SCREEN_YRES );
+ SetDefDrawEnv( &db[0].draw, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES );
+
+ /* Enable draw area clear and dither processing */
+ setRGB0( &db[0].draw, 63, 0, 127 );
+ db[0].draw.isbg = 1;
+ db[0].draw.dtd = 1;
+
+
+ /* Define the second set of display/draw environments */
+ SetDefDispEnv( &db[1].disp, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES );
+ SetDefDrawEnv( &db[1].draw, 0, 0, SCREEN_XRES, SCREEN_YRES );
+
+ setRGB0( &db[1].draw, 63, 0, 127 );
+ db[1].draw.isbg = 1;
+ db[1].draw.dtd = 1;
+
+
+ /* Apply the drawing environment of the first double buffer */
+ PutDrawEnv( &db[0].draw );
+
+
+ /* Clear both ordering tables to make sure they are clean at the start */
+ ClearOTagR( db[0].ot, OT_LEN );
+ ClearOTagR( db[1].ot, OT_LEN );
+
+ /* Set primitive pointer address */
+ db_nextpri = db[0].p;
+
+ /* Initialize the GTE */
+ InitGeom();
+
+ /* Set GTE offset (recommended method of centering) */
+ gte_SetGeomOffset( CENTERX, CENTERY );
+
+ /* Set screen depth (basically FOV control, W/2 works best) */
+ gte_SetGeomScreen( CENTERX );
+
+ /* Set light ambient color and light color matrix */
+ gte_SetBackColor( 63, 63, 63 );
+ gte_SetColorMatrix( &color_mtx );
+
+ InitPAD(pad_buff[0], 34, pad_buff[1], 34);
+ StartPAD();
+ ChangeClearPAD(0);
+
+}
+
+void display() {
+
+ /* Wait for GPU to finish drawing and vertical retrace */
+ DrawSync( 0 );
+ VSync( 0 );
+
+ /* Swap buffers */
+ db_active ^= 1;
+ db_nextpri = db[db_active].p;
+
+ /* Clear the OT of the next frame */
+ ClearOTagR( db[db_active].ot, OT_LEN );
+
+ /* Apply display/drawing environments */
+ PutDrawEnv( &db[db_active].draw );
+ PutDispEnv( &db[db_active].disp );
+
+ /* Enable display */
+ SetDispMask( 1 );
+
+ /* Start drawing the OT of the last buffer */
+ DrawOTag( db[1-db_active].ot+(OT_LEN-1) );
+
+} \ No newline at end of file
diff --git a/examples/system/childexec/child_exe.s b/examples/system/childexec/child_exe.s
new file mode 100644
index 0000000..842ac88
--- /dev/null
+++ b/examples/system/childexec/child_exe.s
@@ -0,0 +1,6 @@
+.section .data
+
+.global child_exe # Insert spoopypasta
+.type child_exe, @object
+child_exe:
+ .incbin "child.exe" \ No newline at end of file
diff --git a/examples/system/childexec/makefile b/examples/system/childexec/makefile
new file mode 100644
index 0000000..79a27b6
--- /dev/null
+++ b/examples/system/childexec/makefile
@@ -0,0 +1,38 @@
+include ../../sdk-common.mk
+
+INCLUDE +=
+LIBDIRS +=
+
+LIBS = -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lc -lpsxapi
+
+CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
+CPPFLAGS = $(CFLAGS) -fno-exceptions
+AFLAGS = -g -msoft-float
+LDFLAGS = -g -gc-sections -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x
+
+LDFLAGS_P = $(LDFLAGS) -Ttext=0x80010000
+LDFLAGS_C = $(LDFLAGS) -Ttext=0x80030000
+
+CC = $(PREFIX)gcc
+LD = $(PREFIX)ld
+
+all: child parent
+
+child: build/child.o
+ $(LD) $(LDFLAGS_C) $(LIBDIRS) build/child.o $(LIBS) -o child.elf
+ elf2x child.elf
+
+parent: build/parent.o build/child_exe.o
+ $(LD) $(LDFLAGS_P) $(LIBDIRS) build/parent.o build/child_exe.o $(LIBS) -o parent.elf
+ elf2x parent.elf
+
+build/%.o: %.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.s
+ @mkdir -p $(dir $@)
+ $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
+
+clean:
+ rm -rf build parent.elf parent.exe child.elf child.exe
diff --git a/examples/system/childexec/parent.c b/examples/system/childexec/parent.c
new file mode 100644
index 0000000..7f577e4
--- /dev/null
+++ b/examples/system/childexec/parent.c
@@ -0,0 +1,305 @@
+/*
+ * LibPSn00b Example Programs
+ *
+ * Child Program Execution Example
+ * 2019 Meido-Tek Productions / PSn00bSDK Project
+ *
+ * This is a modification of the balls example, modified to execute
+ * a child program for this example.
+ *
+ * Example by Lameguy64
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <psxetc.h>
+#include <psxapi.h>
+#include <psxgte.h>
+#include <psxgpu.h>
+#include <psxpad.h>
+#include "ball16c.h"
+
+
+#define MAX_BALLS 1024
+
+#define OT_LEN 8
+
+#define SCREEN_XRES 640
+#define SCREEN_YRES 480
+
+#define CENTER_X SCREEN_XRES/2
+#define CENTER_Y SCREEN_YRES/2
+
+
+/* Display and drawing environments */
+DISPENV disp;
+DRAWENV draw;
+
+char pribuff[2][65536]; /* Primitive packet buffers */
+unsigned int ot[2][OT_LEN]; /* Ordering tables */
+char *nextpri; /* Pointer to next packet buffer offset */
+int db = 0; /* Double buffer index */
+
+
+/* Ball struct and array */
+typedef struct {
+ short x,y;
+ short xdir,ydir;
+ unsigned char r,g,b,p;
+} BALL_TYPE;
+
+BALL_TYPE balls[MAX_BALLS];
+
+
+/* TIM image parameters for loading the ball texture and drawing sprites */
+TIM_IMAGE tim;
+
+
+void run_child();
+
+char pad_buff[2][34];
+
+
+void init() {
+
+ int i;
+
+ /* Reset GPU (also installs event handler for VSync) */
+ printf("Init GPU... ");
+ ResetGraph( 0 );
+ printf("Done.\n");
+
+
+ printf("Set video mode... ");
+
+ /* Set display and draw environment parameters */
+ SetDefDispEnv( &disp, 0, 0, SCREEN_XRES, SCREEN_YRES );
+ SetDefDrawEnv( &draw, 0, 0, SCREEN_XRES, SCREEN_YRES );
+ disp.isinter = 1; /* Enable interlace (required for hires) */
+
+ /* Set clear color, area clear and dither processing */
+ setRGB0( &draw, 63, 0, 127 );
+ draw.isbg = 1;
+ draw.dtd = 1;
+
+ /* Apply the display and drawing environments */
+ PutDispEnv( &disp );
+ PutDrawEnv( &draw );
+
+ /* Enable video output */
+ SetDispMask( 1 );
+
+ printf("Done.\n");
+
+
+ /* Upload the ball texture */
+ printf("Upload texture... ");
+ GetTimInfo( (unsigned int*)ball16c, &tim ); /* Get TIM parameters */
+
+ LoadImage( tim.prect, tim.paddr ); /* Upload texture to VRAM */
+ if( tim.mode & 0x8 ) {
+ LoadImage( tim.crect, tim.caddr ); /* Upload CLUT if present */
+ }
+
+ printf("Done.\n");
+
+
+ /* Calculate ball positions */
+ printf("Calculating balls... ");
+
+ for(i=0; i<MAX_BALLS; i++) {
+
+ balls[i].x = (rand()%624);
+ balls[i].y = (rand()%464);
+ balls[i].xdir = 1-(rand()%3);
+ balls[i].ydir = 1-(rand()%3);
+ if( !balls[i].xdir ) balls[i].xdir = 1;
+ if( !balls[i].ydir ) balls[i].ydir = 1;
+ balls[i].xdir *= 2;
+ balls[i].ydir *= 2;
+ balls[i].r = (rand()%256);
+ balls[i].g = (rand()%256);
+ balls[i].b = (rand()%256);
+
+ }
+
+ printf("Done.\n");
+
+ InitPAD(pad_buff[0], 34, pad_buff[1], 34);
+ StartPAD();
+ ChangeClearPAD(0);
+
+}
+
+int main(int argc, const char* argv[]) {
+
+ SPRT_16 *sprt;
+ DR_TPAGE *tpri;
+
+ int i,counter=0;
+
+
+ /* Init graphics and stuff before doing anything else */
+ init();
+
+
+ /* Main loop */
+ printf("Entering loop...\n");
+
+ while(1) {
+
+ PADTYPE *pad = (PADTYPE*)pad_buff[0];
+
+ if( pad->stat == 0 ) {
+
+ // For digital pad, dual-analog and dual-shock
+ if( ( pad->type == 0x4 ) || ( pad->type == 0x5 ) || ( pad->type == 0x7 ) ) {
+
+ if( !(pad->btn&PAD_START) ) {
+ DrawSync(0);
+ run_child();
+ }
+
+ }
+
+ }
+
+ /* Clear ordering table and set start address of primitive */
+ /* buffer for next frame */
+ ClearOTagR( ot[db], OT_LEN );
+ nextpri = pribuff[db];
+
+ /* Sort a balls snake */
+ sprt = (SPRT_16*)nextpri;
+ srand( 64 );
+ for( i=0; i<32; i++ ) {
+
+ setSprt16( sprt );
+ setXY0( sprt,
+ (CENTER_X-8)+(isin((counter-(i<<4))<<3)>>5),
+ (CENTER_Y-8)-(icos((counter-(i<<2))<<3)>>5) );
+ setRGB0( sprt, rand()%256, rand()%256, rand()%256 );
+ setUV0( sprt, 0, 0 );
+ setClut( sprt, tim.crect->x, tim.crect->y );
+
+ addPrim( ot[db]+(OT_LEN-1), sprt );
+ sprt++;
+
+ }
+
+ /* Sort the balls */
+ for( i=0; i<MAX_BALLS; i++ ) {
+
+ setSprt16( sprt );
+ setXY0( sprt, balls[i].x, balls[i].y );
+ setRGB0( sprt, balls[i].r, balls[i].g, balls[i].b );
+ setUV0( sprt, 0, 0 );
+ setClut( sprt, tim.crect->x, tim.crect->y );
+
+ addPrim( ot[db]+(OT_LEN-1), sprt );
+ sprt++;
+
+ balls[i].x += balls[i].xdir;
+ balls[i].y += balls[i].ydir;
+
+ if( ( balls[i].x+16 ) > 640 ) {
+ balls[i].xdir = -2;
+ } else if( balls[i].x < 0 ) {
+ balls[i].xdir = 2;
+ }
+
+ if( ( balls[i].y+16 ) > 480 ) {
+ balls[i].ydir = -2;
+ } else if( balls[i].y < 0 ) {
+ balls[i].ydir = 2;
+ }
+
+ }
+ nextpri = (char*)sprt;
+
+
+ /* Sort a TPage primitive so the sprites will draw pixels from */
+ /* the correct texture page in VRAM */
+ tpri = (DR_TPAGE*)nextpri;
+ setDrawTPage( tpri, 0, 0,
+ getTPage( 0, 0, tim.prect->x, tim.prect->y ) );
+ addPrim( ot[db]+(OT_LEN-1), tpri );
+ nextpri += sizeof(DR_TPAGE);
+
+ /* Wait for GPU and VSync */
+ DrawSync( 0 );
+ VSync( 0 );
+
+ /* Since draw.isbg is non-zero this clears the screen */
+ PutDrawEnv( &draw );
+
+ /* Begin drawing the new frame */
+ DrawOTag( ot[db]+(OT_LEN-1) );
+
+ /* Alternate to the next buffer */
+ db = !db;
+
+ /* Increment counter for the snake animation */
+ counter++;
+
+ }
+
+ return 0;
+
+}
+
+// PS-EXE header structure
+typedef struct {
+ char id[16];
+ struct EXEC param;
+ char pad[1972];
+} EXE_HEAD;
+
+// Child program address
+extern char child_exe[];
+
+// Manually defined as its not defined in psxapi by default
+void SetDefaultExitFromException();
+
+void run_child() {
+
+ // So child header is readable
+ EXE_HEAD *exe = (EXE_HEAD*)child_exe;
+
+ // Copy child executable to its intended adddress
+ memcpy((void*)exe->param.t_addr, child_exe+2048, exe->param.t_size);
+
+ // Enter critical section to prepare for program execution
+ EnterCriticalSection();
+
+ // Stop pads, enable auto acknowledge
+ StopPAD();
+ ChangeClearPAD(1);
+ ChangeClearRCnt(3, 1);
+
+ // Set default exception handler just in case
+ //SetDefaultExitFromException();
+
+ // Last three function calls could be relegated to
+ // a StopCallback() function in the future.
+
+ // Execute child
+ printf("Child exec!\n");
+ Exec(&exe->param, 0, 0);
+
+ // Reset previous handler
+ EnterCriticalSection();
+ RestartCallback();
+ ExitCriticalSection();
+
+ // Re-init and re-enable pads
+ InitPAD(pad_buff[0], 34, pad_buff[1], 34);
+ StartPAD();
+ ChangeClearPAD(0);
+
+ // Set this program's display mode
+ PutDispEnv(&disp);
+
+}
diff --git a/examples/system/console/ball16c.h b/examples/system/console/ball16c.h
new file mode 100644
index 0000000..c79f273
--- /dev/null
+++ b/examples/system/console/ball16c.h
@@ -0,0 +1,16 @@
+unsigned int ball16c_size=192;
+unsigned char ball16c[] = {
+0x10,0x00,0x00,0x00,0x08,0x00,0x00,0x00,0x2c,0x00,0x00,0x00,0xc0,0x03,0x10,
+0x01,0x10,0x00,0x01,0x00,0x00,0x00,0x31,0xc6,0x73,0xce,0x94,0xd2,0x07,0x9d,
+0xd6,0xda,0x38,0xe3,0xef,0xbd,0x9b,0xef,0x8c,0xb1,0xc6,0x98,0xde,0xfb,0x4a,
+0xa9,0xa4,0x90,0xad,0xb5,0x00,0x00,0x8c,0x00,0x00,0x00,0xc0,0x03,0x00,0x01,
+0x04,0x00,0x10,0x00,0x00,0x00,0x10,0x22,0x12,0x02,0x00,0x00,0x00,0x10,0x32,
+0x33,0x23,0x11,0x04,0x00,0x00,0x23,0x55,0x66,0x35,0x72,0x47,0x00,0x20,0x52,
+0x86,0x68,0x36,0x12,0x97,0x0a,0x20,0x65,0xbb,0x8b,0x36,0x12,0x91,0x04,0x31,
+0x85,0xbb,0x68,0x35,0x12,0x97,0xdc,0x32,0x86,0x8b,0x56,0x35,0x73,0x97,0xa4,
+0x32,0x66,0x68,0x55,0x23,0x71,0x9e,0xac,0x32,0x65,0x56,0x33,0x13,0x71,0xce,
+0xa4,0x21,0x33,0x33,0x23,0x11,0xe7,0xc9,0xd4,0x12,0x22,0x22,0x13,0x71,0xe7,
+0xc9,0xda,0x10,0x17,0x11,0x77,0x77,0x9e,0x4c,0x0d,0x40,0x77,0x71,0xe7,0x9e,
+0xc9,0xd4,0x0d,0x00,0x94,0x99,0x99,0xcc,0x4c,0xda,0x00,0x00,0xa0,0xc4,0xc4,
+0x44,0xda,0x0d,0x00,0x00,0x00,0xd0,0xaa,0xda,0x0d,0x00,0x00
+};
diff --git a/examples/system/console/main.c b/examples/system/console/main.c
new file mode 100644
index 0000000..988b428
--- /dev/null
+++ b/examples/system/console/main.c
@@ -0,0 +1,284 @@
+/*
+ * LibPSn00b Example Programs
+ *
+ * Text Console Example
+ * 2020 Meido-Tek Productions / PSn00bSDK Project
+ *
+ * This example demonstrates a tty text console implementation for gameplay
+ * sections, or sections with continuously updating graphics. The console is
+ * brought up by the tilde key in which, execution of the gameplay section would
+ * get paused until the console is exited. A fully asynchronous implementation
+ * should be possible, but this is beyond the scope of this simple example.
+ *
+ *
+ * Example by Lameguy64
+ *
+ * Changelog:
+ *
+ * April 23, 2020 - Initial version.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ioctl.h>
+#include <sys/fcntl.h>
+#include <psxapi.h>
+#include <psxetc.h>
+#include <psxgte.h>
+#include <psxgpu.h>
+#include <psxsio.h>
+#include "ball16c.h"
+
+
+#define MAX_BALLS 1024
+
+#define OT_LEN 8
+
+#define SCREEN_XRES 640
+#define SCREEN_YRES 480
+
+#define CENTER_X SCREEN_XRES/2
+#define CENTER_Y SCREEN_YRES/2
+
+
+/* Display and drawing environments */
+DISPENV disp;
+DRAWENV draw;
+
+char pribuff[2][65536]; /* Primitive packet buffers */
+unsigned int ot[2][OT_LEN]; /* Ordering tables */
+char *nextpri; /* Pointer to next packet buffer offset */
+int db = 0; /* Double buffer index */
+
+
+/* Ball struct and array */
+typedef struct {
+ short x,y;
+ short xdir,ydir;
+ unsigned char r,g,b,p;
+} BALL_TYPE;
+
+BALL_TYPE balls[MAX_BALLS];
+
+
+/* TIM image parameters for loading the ball texture and drawing sprites */
+TIM_IMAGE tim;
+
+
+void init() {
+
+ int i;
+
+ /* Reset GPU (also installs event handler for VSync) */
+ printf("Init GPU... ");
+ ResetGraph( 0 );
+ printf("Done.\n");
+
+
+ printf("Set video mode... ");
+
+ /* Set display and draw environment parameters */
+ SetDefDispEnv( &disp, 0, 0, SCREEN_XRES, SCREEN_YRES );
+ SetDefDrawEnv( &draw, 0, 0, SCREEN_XRES, SCREEN_YRES );
+ disp.isinter = 1; /* Enable interlace (required for hires) */
+
+ /* Set clear color, area clear and dither processing */
+ setRGB0( &draw, 63, 0, 127 );
+ draw.isbg = 1;
+ draw.dtd = 1;
+
+ /* Apply the display and drawing environments */
+ PutDispEnv( &disp );
+ PutDrawEnv( &draw );
+
+ /* Enable video output */
+ SetDispMask( 1 );
+
+ printf("Done.\n");
+
+
+ /* Upload the ball texture */
+ printf("Upload texture... ");
+ GetTimInfo( (unsigned int*)ball16c, &tim ); /* Get TIM parameters */
+
+ LoadImage( tim.prect, tim.paddr ); /* Upload texture to VRAM */
+ if( tim.mode & 0x8 ) {
+ LoadImage( tim.crect, tim.caddr ); /* Upload CLUT if present */
+ }
+
+ printf("Done.\n");
+
+
+ /* Calculate ball positions */
+ printf("Calculating balls... ");
+
+ for( i=0; i<MAX_BALLS; i++ )
+ {
+ balls[i].x = (rand()%624);
+ balls[i].y = (rand()%464);
+ balls[i].xdir = 1-(rand()%3);
+ balls[i].ydir = 1-(rand()%3);
+ if( !balls[i].xdir ) balls[i].xdir = 1;
+ if( !balls[i].ydir ) balls[i].ydir = 1;
+ balls[i].xdir *= 2;
+ balls[i].ydir *= 2;
+ balls[i].r = (rand()%256);
+ balls[i].g = (rand()%256);
+ balls[i].b = (rand()%256);
+ }
+
+ printf("Done.\n");
+
+}
+
+
+void do_console(void)
+{
+ char line[32];
+
+ /* Print console banner */
+ printf("\nConsole mode! Enter 'exit' to return to gameplay.\n");
+
+ /* The parser loop */
+ while(1)
+ {
+ /* Print a prompt character and read a line of input */
+ putchar('>');
+ gets(line);
+
+ /* Exit the parser if the text entered is exit */
+ if( strcmp(line, "exit") == 0 )
+ break;
+
+ /* Print the input */
+ printf("You entered: %s\n", line);
+ }
+}
+
+
+int main(int argc, const char* argv[]) {
+
+ SPRT_16 *sprt;
+ DR_TPAGE *tpri;
+
+ int i,counter=0;
+
+
+ /* Init graphics and stuff before doing anything else */
+ init();
+
+
+ /* Uncomment this line if you don't have tty interfaces
+ * provided by n00brom or similar development environments with tty */
+ AddSIO(115200);
+
+
+ /* Main loop */
+ printf("Entering loop...\n");
+
+ while(1)
+ {
+ /* FIOCSCAN will return a non-zero value when there's
+ * input pending in tty, file handle 0 is usually stdin */
+ if( ioctl(0, FIOCSCAN, 0) )
+ {
+ /* Get the character */
+ i = getchar();
+
+ /* If the key that's pressed is a tilde, enter the console */
+ if( i == '`' )
+ do_console();
+ }
+
+ /* Clear ordering table and set start address of primitive
+ * buffer for next frame */
+ ClearOTagR(ot[db], OT_LEN);
+ nextpri = pribuff[db];
+
+ /* Sort a balls snake */
+ sprt = (SPRT_16*)nextpri;
+ srand(64);
+ for( i=0; i<32; i++ )
+ {
+ setSprt16(sprt);
+ setXY0(sprt,
+ (CENTER_X-8)+(isin((counter-(i<<4))<<3)>>5),
+ (CENTER_Y-8)-(icos((counter-(i<<2))<<3)>>5));
+ setRGB0(sprt, rand()%256, rand()%256, rand()%256);
+ setUV0(sprt, 0, 0);
+ setClut(sprt, tim.crect->x, tim.crect->y);
+
+ addPrim(ot[db]+(OT_LEN-1), sprt);
+ sprt++;
+
+ }
+
+ /* Sort the balls */
+ for( i=0; i<MAX_BALLS; i++ )
+ {
+ setSprt16(sprt);
+ setXY0(sprt, balls[i].x, balls[i].y);
+ setRGB0(sprt, balls[i].r, balls[i].g, balls[i].b);
+ setUV0(sprt, 0, 0 );
+ setClut(sprt, tim.crect->x, tim.crect->y);
+
+ addPrim(ot[db]+(OT_LEN-1), sprt);
+ sprt++;
+
+ balls[i].x += balls[i].xdir;
+ balls[i].y += balls[i].ydir;
+
+ if( ( balls[i].x+16 ) > 640 )
+ {
+ balls[i].xdir = -2;
+ }
+ else if( balls[i].x < 0 )
+ {
+ balls[i].xdir = 2;
+ }
+
+ if( ( balls[i].y+16 ) > 480 )
+ {
+ balls[i].ydir = -2;
+ }
+ else if( balls[i].y < 0 )
+ {
+ balls[i].ydir = 2;
+ }
+
+ }
+
+ nextpri = (char*)sprt;
+
+
+ /* Sort a TPage primitive so the sprites will draw pixels from
+ * the correct texture page in VRAM */
+ tpri = (DR_TPAGE*)nextpri;
+ setDrawTPage(tpri, 0, 0,
+ getTPage(0, 0, tim.prect->x, tim.prect->y));
+ addPrim(ot[db]+(OT_LEN-1), tpri);
+ nextpri += sizeof(DR_TPAGE);
+
+ /* Wait for GPU and VSync */
+ DrawSync(0);
+ VSync(0);
+
+ /* Since draw.isbg is non-zero this clears the screen */
+ PutDrawEnv(&draw);
+
+ /* Begin drawing the new frame */
+ DrawOTag(ot[db]+(OT_LEN-1));
+
+ /* Alternate to the next buffer */
+ db = !db;
+
+ /* Increment counter for the snake animation */
+ counter++;
+
+ }
+
+ return 0;
+
+}
diff --git a/examples/system/console/makefile b/examples/system/console/makefile
new file mode 100644
index 0000000..0c27b55
--- /dev/null
+++ b/examples/system/console/makefile
@@ -0,0 +1,60 @@
+include ../../sdk-common.mk
+
+# Project target name
+TARGET = console.elf
+
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES = $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+# Determine object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
+
+# Project specific include and library directories
+# (use -I for include dirs, -L for library dirs)
+INCLUDE +=
+LIBDIRS +=
+
+# Libraries to link
+LIBS = -lpsxsio -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lc
+
+# C compiler flags
+CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
+
+# C++ compiler flags
+CPPFLAGS = $(CFLAGS) -fno-exceptions
+
+# Assembler flags
+AFLAGS = -g -msoft-float
+
+# Linker flags
+LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
+ -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x
+
+# Toolchain programs
+CC = $(PREFIX)gcc
+CXX = $(PREFIX)g++
+AS = $(PREFIX)as
+LD = $(PREFIX)ld
+
+all: $(OFILES)
+ $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
+ elf2x -q $(TARGET)
+
+build/%.o: %.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(AFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.s
+ @mkdir -p $(dir $@)
+ $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
+
+clean:
+ rm -rf build $(TARGET) $(TARGET:.elf=.exe)
diff --git a/examples/system/timer/main.c b/examples/system/timer/main.c
new file mode 100644
index 0000000..7d9f7b3
--- /dev/null
+++ b/examples/system/timer/main.c
@@ -0,0 +1,154 @@
+#include <stdio.h>
+#include <psxgpu.h>
+#include <psxapi.h>
+#include <psxetc.h>
+
+/* OT and Packet Buffer sizes */
+#define OT_LEN 256
+#define PACKET_LEN 1024
+
+/* Screen resolution */
+#define SCREEN_XRES 320
+#define SCREEN_YRES 240
+
+/* Screen center position */
+#define CENTERX SCREEN_XRES>>1
+#define CENTERY SCREEN_YRES>>1
+
+
+/* Double buffer structure */
+typedef struct {
+ DISPENV disp; /* Display environment */
+ DRAWENV draw; /* Drawing environment */
+} DB;
+
+/* Double buffer variables */
+DB db[2];
+int db_active = 0;
+
+
+/* Function declarations */
+void init();
+void display();
+
+
+volatile int timer_calls = 0;
+volatile short *timer2_ctrl = (short*)0x1F801124;
+void timer_func()
+{
+ timer_calls++;
+}
+
+volatile int vsync_count = 0;
+volatile int tick_count = 0;
+volatile int tick_value = 0;
+
+void vsync_func()
+{
+ vsync_count++;
+ if( vsync_count > 60 )
+ {
+ tick_value = timer_calls-tick_count;
+ tick_count = timer_calls;
+ vsync_count = 0;
+ }
+}
+
+/* Main function */
+int main() {
+
+ int counter;
+
+ /* Init graphics and GTE */
+ init();
+
+
+ EnterCriticalSection();
+ //SetRCnt(RCntCNT2, 0xF040, RCntMdINTR);
+
+ // NTSC clock base
+ counter = 4304000/560;
+
+ // PAL clock base
+ //counter = 5163000/560;
+
+ SetRCnt(RCntCNT2, counter, RCntMdINTR);
+ *timer2_ctrl = 0x1E58;
+ InterruptCallback(6, timer_func);
+ StartRCnt(RCntCNT2);
+ ChangeClearRCnt(2, 0);
+ ExitCriticalSection();
+
+ VSyncCallback(vsync_func);
+
+ /* Main loop */
+ while( 1 ) {
+
+ FntPrint(-1, "TIMER COUNT=%d\n", timer_calls);
+ FntPrint(-1, "TICKS/SEC=%d\n", tick_value);
+
+ /* Swap buffers and draw text */
+ display();
+
+ }
+
+ return 0;
+
+}
+
+void init() {
+
+ /* Reset the GPU, also installs a VSync event handler */
+ ResetGraph( 0 );
+ //SetVideoMode(MODE_PAL);
+
+ /* Set display and draw environment areas */
+ /* (display and draw areas must be separate, otherwise hello flicker) */
+ SetDefDispEnv( &db[0].disp, 0, 0, SCREEN_XRES, SCREEN_YRES );
+ SetDefDrawEnv( &db[0].draw, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES );
+
+ /* Enable draw area clear and dither processing */
+ setRGB0( &db[0].draw, 63, 0, 127 );
+ db[0].draw.isbg = 1;
+ db[0].draw.dtd = 1;
+
+
+ /* Define the second set of display/draw environments */
+ SetDefDispEnv( &db[1].disp, SCREEN_XRES, 0, SCREEN_XRES, SCREEN_YRES );
+ SetDefDrawEnv( &db[1].draw, 0, 0, SCREEN_XRES, SCREEN_YRES );
+
+ //db[0].disp.screen.y = 24;
+ //db[1].disp.screen.y = 24;
+
+ setRGB0( &db[1].draw, 63, 0, 127 );
+ db[1].draw.isbg = 1;
+ db[1].draw.dtd = 1;
+
+
+ /* Apply the drawing environment of the first double buffer */
+ PutDrawEnv( &db[0].draw );
+
+ FntLoad(960, 0);
+ FntOpen(0, 8, 320, 216, 0, 100);
+
+}
+
+void display() {
+
+ FntFlush(-1);
+
+ /* Wait for GPU to finish drawing and vertical retrace */
+ DrawSync( 0 );
+ VSync( 0 );
+
+ /* Swap buffers */
+ db_active ^= 1;
+
+ /* Apply display/drawing environments */
+ PutDrawEnv( &db[db_active].draw );
+ PutDispEnv( &db[db_active].disp );
+
+ /* Enable display */
+ SetDispMask( 1 );
+
+} \ No newline at end of file
diff --git a/examples/system/timer/makefile b/examples/system/timer/makefile
new file mode 100644
index 0000000..c35c445
--- /dev/null
+++ b/examples/system/timer/makefile
@@ -0,0 +1,39 @@
+include ../../sdk-common.mk
+
+TARGET = timer.elf
+
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES = $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+OFILES = $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o))
+
+INCLUDE +=
+LIBDIRS +=
+
+LIBS = -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lc
+
+CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
+CPPFLAGS = $(CFLAGS) -fno-exceptions
+AFLAGS = -g -msoft-float
+LDFLAGS = -g -Ttext=0x80010000 -gc-sections -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x
+
+CC = $(PREFIX)gcc
+CXX = $(PREFIX)g++
+AS = $(PREFIX)as
+LD = $(PREFIX)ld
+
+all: $(OFILES)
+ $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
+ elf2x -q $(TARGET)
+
+build/%.o: %.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.s
+ @mkdir -p $(dir $@)
+ $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
+
+clean:
+ rm -rf build $(TARGET) $(TARGET:.elf=.exe)
diff --git a/examples/system/tty/main.c b/examples/system/tty/main.c
new file mode 100644
index 0000000..8333746
--- /dev/null
+++ b/examples/system/tty/main.c
@@ -0,0 +1,145 @@
+/*
+ * LibPSn00b Example Programs
+ *
+ * Teletype Example
+ * 2020 Meido-Tek Productions / PSn00bSDK Project
+ *
+ * This example showcases the uses of tty through stdio facilities. If you've
+ * written text console applications before, this one is not too dissimilar to
+ * that. Escape codes for formatting and such should work as this is more
+ * dependant on the terminal program used than the PS1 console itself.
+ *
+ *
+ * Example by Lameguy64
+ *
+ * Changelog:
+ *
+ * April 23, 2020 - Initial version.
+ *
+ */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <psxgpu.h>
+
+/* Memory viewer thing, you may use this in your own applications
+ * for testing or analysis */
+void memory_browser(unsigned int addr)
+{
+ int i,j,key;
+ unsigned char *ptr,*pptr;
+
+ while(1)
+ {
+ /* Set cursor position to top-left */
+ printf("\033[1;1H");
+ printf("MEMVIEW 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 0123456789ABCDEF");
+
+ ptr = (unsigned char*)addr;
+
+ /* Print contents from current location of memory */
+ for(j=0; j<23; j++)
+ {
+ printf("\n%04X: ", (unsigned int)ptr);
+ pptr = ptr;
+ for(i=0; i<16; i++)
+ {
+ printf("%02X ", *ptr);
+ ptr++;
+ }
+ printf(" ");
+ for(i=0; i<16; i++)
+ {
+ if(( *pptr < 32 ) || ( *pptr > 127 ) )
+ {
+ printf(".");
+ }
+ else
+ {
+ printf("%c", *pptr);
+ }
+ pptr++;
+ }
+ }
+
+ /* Parse input */
+ while(1)
+ {
+ key = getchar();
+ if( key == 0x1B )
+ {
+ key = getchar();
+
+ if( key == 0x5B )
+ {
+ key = getchar();
+ if( key == 0x41 ) // Up
+ {
+ addr -= 16;
+ break;
+ }
+ else if( key == 0x42 ) // Down
+ {
+ addr += 16;
+ break;
+ }
+ if( key == 0x35 ) // Page up
+ {
+ addr -= 16*23;
+ break;
+ }
+ else if( key == 0x36 ) // Page down
+ {
+ addr += 16*23;
+ break;
+ }
+ }
+ }
+
+ }
+ }
+
+}
+
+
+int main(int argc, const char *argv[])
+{
+ int i;
+ char strbuff[32];
+
+ /* Mostly to get interrupts going for this example */
+ ResetGraph( 0 );
+
+ /* Uncomment if you don't have an environment that provides tty access
+ * by default */
+ //AddSIO(115200);
+
+ /* A standby loop until 'Y' is entered */
+ while(1)
+ {
+ /* Print banner */
+ printf("Hello world!\n");
+ printf("Press 'Y' to proceed with this demonstration.\n");
+
+ /* Get input for a Y character */
+ i = getchar();
+ if( tolower(i) == 'y' )
+ break;
+ }
+
+ /* Do a classic text input prompt and display the inputted text */
+ printf("Enter a string, any string (no more than 32 characters):\n");
+ gets(strbuff);
+
+ printf("You've entered: %s\n\n", strbuff);
+
+ /* Prompt entering into the memory browser */
+ printf("Press a key to enter a memory browser demo...\n");
+ printf("Make sure your terminal or text console supports vt100 escape codes!\n");
+ getchar();
+
+ /* Start the memory browser interface */
+ memory_browser(0x80010000);
+
+ return 0;
+}
diff --git a/examples/system/tty/makefile b/examples/system/tty/makefile
new file mode 100644
index 0000000..a3884ad
--- /dev/null
+++ b/examples/system/tty/makefile
@@ -0,0 +1,60 @@
+include ../../sdk-common.mk
+
+# Project target name
+TARGET = tty.elf
+
+# Searches for C, C++ and S (assembler) files in local directory
+CFILES = $(notdir $(wildcard *.c))
+CPPFILES = $(notdir $(wildcard *.cpp))
+AFILES = $(notdir $(wildcard *.s))
+
+# Determine object files
+OFILES = $(addprefix build/,$(CFILES:.c=.o)) \
+ $(addprefix build/,$(CPPFILES:.cpp=.o)) \
+ $(addprefix build/,$(AFILES:.s=.o))
+
+# Project specific include and library directories
+# (use -I for include dirs, -L for library dirs)
+INCLUDE +=
+LIBDIRS +=
+
+# Libraries to link
+LIBS = -lpsxetc -lpsxgpu -lpsxgte -lpsxspu -lpsxapi -lc
+
+# C compiler flags
+CFLAGS = -g -O2 -fno-builtin -fdata-sections -ffunction-sections
+
+# C++ compiler flags
+CPPFLAGS = $(CFLAGS) -fno-exceptions
+
+# Assembler flags
+AFLAGS = -g -msoft-float
+
+# Linker flags
+LDFLAGS = -g -Ttext=0x80010000 -gc-sections \
+ -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x
+
+# Toolchain programs
+CC = $(PREFIX)gcc
+CXX = $(PREFIX)g++
+AS = $(PREFIX)as
+LD = $(PREFIX)ld
+
+all: $(OFILES)
+ $(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o $(TARGET)
+ elf2x -q $(TARGET)
+
+build/%.o: %.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.cpp
+ @mkdir -p $(dir $@)
+ $(CXX) $(AFLAGS) $(INCLUDE) -c $< -o $@
+
+build/%.o: %.s
+ @mkdir -p $(dir $@)
+ $(CC) $(AFLAGS) $(INCLUDE) -c $< -o $@
+
+clean:
+ rm -rf build $(TARGET) $(TARGET:.elf=.exe)