summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeon Rinkel <[email protected]>2023-11-20 19:02:31 +0100
committerLeon Rinkel <[email protected]>2023-11-20 19:02:31 +0100
commitfb174cb2a4c1d66d56f88b2251356514c8c685bb (patch)
tree372f79cc35a67117ccd6c1eb7a8b5e020b4866c6
parenta9388f9cbee01859fdf3a084b9d38b22b64d60d5 (diff)
Add PSn00bSDK template and load executable from ROM
-rw-r--r--README.md16
-rw-r--r--rom.s38
-rw-r--r--template/CMakeLists.txt21
-rw-r--r--template/CMakePresets.json26
-rw-r--r--template/iso.xml83
-rw-r--r--template/main.c173
-rw-r--r--template/system.cnf4
7 files changed, 361 insertions, 0 deletions
diff --git a/README.md b/README.md
index 256eb35..e29fc5c 100644
--- a/README.md
+++ b/README.md
@@ -4,3 +4,19 @@ Custom ROM for PSX PIO. Can't do anything special yet. I'm just trying to get
comfortable with the PSX.
![Screenshot of rendered rectangles in emulator](Screenshot%202023-11-15%20at%2016.29.58.png)
+
+## Build
+
+Build executable.
+
+```sh
+cd template
+cmake --preset default .
+cmake --build ./build
+```
+
+Build loader.
+
+```sh
+armips rom.s
+```
diff --git a/rom.s b/rom.s
index baa2d06..53f27a7 100644
--- a/rom.s
+++ b/rom.s
@@ -113,6 +113,39 @@ midboot:
li t0, 0x002a002a
sw t0, GP0(a0)
+ ; wait a bit
+ li t0, 0xffffff
+delay:
+ subi t0, 1
+ bnez t0, delay
+ nop
+
+ ; load executable
+ la a0, executable
+ lw t1, 0x18(a0) ; destinaion
+ lw t2, 0x1c(a0) ; length
+ addiu t3, a0, 0x800 ; source, header is 800h bytes
+copy_loop:
+ lb t4, 0x0(t3)
+ nop
+ addiu t3, t3, 1
+ sb t4, 0x0(t1)
+ nop
+ addiu t1, t1, 1
+ subi t2, 1
+ bnez t2, copy_loop
+ nop
+
+ lw t1, 0x10(a0) ; initial pc
+ lw t2, 0x30(a0) ; sp base
+ lw t3, 0x34(a0) ; sp offset
+ lw gp, 0x14(a0) ; initial gp
+ add sp, t2, t3
+ li sp, 0x801FFFF0
+
+ jr t1
+ nop
+
end:
j end
nop
@@ -129,4 +162,9 @@ puts:
message: .ascii "call me, beep me!"
+ .align 4
+executable:
+ .incbin "template/build/template.exe"
+ .align 4
+
.close
diff --git a/template/CMakeLists.txt b/template/CMakeLists.txt
new file mode 100644
index 0000000..e665c7e
--- /dev/null
+++ b/template/CMakeLists.txt
@@ -0,0 +1,21 @@
+# PSn00bSDK example CMake script
+# (C) 2021 spicyjpeg - MPL licensed
+
+cmake_minimum_required(VERSION 3.21)
+
+project(
+ PSn00bSDK-template
+ LANGUAGES C CXX ASM
+ VERSION 1.0.0
+ DESCRIPTION "PSn00bSDK template"
+ HOMEPAGE_URL "http://lameguy64.net/?page=psn00bsdk"
+)
+
+psn00bsdk_add_executable(template GPREL main.c)
+
+psn00bsdk_add_cd_image(
+ iso # Target name
+ template # Output file name (= template.bin + template.cue)
+ iso.xml # Path to config file
+ DEPENDS template system.cnf
+)
diff --git a/template/CMakePresets.json b/template/CMakePresets.json
new file mode 100644
index 0000000..97d8428
--- /dev/null
+++ b/template/CMakePresets.json
@@ -0,0 +1,26 @@
+{
+ "version": 3,
+ "cmakeMinimumRequired": {
+ "major": 3,
+ "minor": 21,
+ "patch": 0
+ },
+ "configurePresets": [
+ {
+ "name": "default",
+ "displayName": "Default configuration",
+ "description": "Use this preset to build the project using PSn00bSDK.",
+ "generator": "Ninja",
+ "toolchainFile": "$env{PSN00BSDK_LIBS}/cmake/sdk.cmake",
+ "binaryDir": "${sourceDir}/build",
+ "cacheVariables": {
+ "CMAKE_BUILD_TYPE": "Debug",
+ "PSN00BSDK_TC": "",
+ "PSN00BSDK_TARGET": "mipsel-none-elf"
+ },
+ "warnings": {
+ "dev": false
+ }
+ }
+ ]
+}
diff --git a/template/iso.xml b/template/iso.xml
new file mode 100644
index 0000000..96ea23a
--- /dev/null
+++ b/template/iso.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ This file is processed by CMake and used by mkpsxiso to build the CD image.
+
+ NOTE: all paths are relative to the build directory; if you want to include
+ a file from the source tree, you'll have to prepend its path with
+ ${PROJECT_SOURCE_DIR}.
+-->
+<iso_project>
+ <track type="data">
+ <!--
+ The "volume", "volume_set", "publisher", "data_preparer" and
+ "copyright" strings below can be freely modified. The ISO9660
+ specification, however, imposes the following limitations:
+
+ - "volume" and "volume_set" must be 32 characters or less, and can
+ only contain uppercase letters, digits and underscores.
+ - "publisher" and "data_preparer" can be up to 128 characters long
+ and can additionally contain spaces and some special characters.
+ - "copyright" should be a path to a file on the disc, even one that
+ does not exist (but in practice it can be set to anything).
+
+ "system" and "application" must always be set to "PLAYSTATION" in
+ order for the disc to be recognized as valid.
+ -->
+ <identifiers
+ system ="PLAYSTATION"
+ volume ="PSN00BSDK_TEMPLATE"
+ volume_set ="PSN00BSDK_TEMPLATE"
+ publisher ="MEIDOTEK"
+ data_preparer ="PSN00BSDK ${PSN00BSDK_VERSION}"
+ application ="PLAYSTATION"
+ copyright ="README.TXT;1"
+ />
+
+ <!--
+ You may optionally include a license file using the <license> tag.
+ Some consoles, particularly Japanese or PAL models with a modchip,
+ require the disc to contain valid license data and will refuse to
+ boot if it is missing. License files are usually not required on
+ US consoles or when booting via softmods or cheat cartridges.
+
+ License files are region-specific and are not distributed with
+ PSn00bSDK for obvious reasons, but can be dumped from an official
+ game using dumpsxiso or extracted from the Sony SDK.
+ -->
+ <!--<license file="${PROJECT_SOURCE_DIR}/license.dat" />-->
+
+ <!--
+ Files and directories can be added to the disc by placing <file>
+ and <dir> tags below. All file names are case-insensitive and must
+ be in 8.3 format, i.e. no more than 8 characters for the name and 3
+ for the optional extension. Directories cannot have extensions.
+
+ A boot configuration file (SYSTEM.CNF) or executable (PSX.EXE) must
+ be present in the root directory. Due to BIOS limitations the root
+ directory cannot hold more than 30 files or directories, and the
+ entire disc must contain 45 directories or less. Subdirectories can
+ contain any number of files.
+ -->
+ <directory_tree>
+ <file name="SYSTEM.CNF" type="data" source="${PROJECT_SOURCE_DIR}/system.cnf" />
+ <file name="TEMPLATE.EXE" type="data" source="template.exe" />
+ <!--
+ This file is only required if you are using dynamic linking
+ (see the system/dynlink example). It contains the executable's
+ symbol map and can be used to obtain the address of a function
+ or global variable by its name.
+ -->
+ <!--<file name="TEMPLATE.MAP" type="data" source="template.map" />-->
+
+ <dummy sectors="1024"/>
+ </directory_tree>
+ </track>
+
+ <!--
+ CD-DA tracks can be added to the CD image by using one or more <track>
+ tags. The source attribute must be a path to an audio file in WAV, FLAC
+ or MP3 format (using WAV or FLAC is highly recommended to preserve
+ audio quality if you have a lossless copy of the source track).
+ -->
+ <!--<track type="audio" source="${PROJECT_SOURCE_DIR}/track2.wav" />-->
+</iso_project>
diff --git a/template/main.c b/template/main.c
new file mode 100644
index 0000000..7f738d3
--- /dev/null
+++ b/template/main.c
@@ -0,0 +1,173 @@
+/*
+ * PSn00bSDK basic graphics example
+ * (C) 2020-2023 Lameguy64, spicyjpeg - MPL licensed
+ *
+ * A comprehensive "advanced hello world" example showing how to set up the
+ * screen with double buffering, draw basic graphics (a bouncing square) and use
+ * PSn00bSDK's debug font API to quickly print some text, all while following
+ * best practices. This is not necessarily the simplest hello world example and
+ * may look daunting at first glance, but it is a good starting point for more
+ * complex programs.
+ *
+ * In order to avoid cluttering the program with global variables (as many Sony
+ * SDK examples and other PSn00bSDK examples written before this one do) two
+ * custom structures are employed:
+ *
+ * - a RenderBuffer structure containing the DISPENV and DRAWENV objects that
+ * represent the location of the framebuffer in VRAM, as well as the ordering
+ * table (OT) used to sort GPU commands/primitives by their Z index and the
+ * actual buffer commands will be written to;
+ * - a RenderContext structure holding two RenderBuffer instances plus some
+ * variables to keep track of which buffer is currently being drawn and how
+ * much of its primitive buffer has been filled up so far.
+ *
+ * A C++ version of this example is also available (see examples/hellocpp).
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <psxgpu.h>
+
+// Length of the ordering table, i.e. the range Z coordinates can have, 0-15 in
+// this case. Larger values will allow for more granularity with depth (useful
+// when drawing a complex 3D scene) at the expense of RAM usage and performance.
+#define OT_LENGTH 16
+
+// Size of the buffer GPU commands and primitives are written to. If the program
+// crashes due to too many primitives being drawn, increase this value.
+#define BUFFER_LENGTH 8192
+
+/* Framebuffer/display list class */
+
+typedef struct {
+ DISPENV disp_env;
+ DRAWENV draw_env;
+
+ uint32_t ot[OT_LENGTH];
+ uint8_t buffer[BUFFER_LENGTH];
+} RenderBuffer;
+
+typedef struct {
+ RenderBuffer buffers[2];
+ uint8_t *next_packet;
+ int active_buffer;
+} RenderContext;
+
+void setup_context(RenderContext *ctx, int w, int h, int r, int g, int b) {
+ // Place the two framebuffers vertically in VRAM.
+ SetDefDrawEnv(&(ctx->buffers[0].draw_env), 0, 0, w, h);
+ SetDefDispEnv(&(ctx->buffers[0].disp_env), 0, 0, w, h);
+ SetDefDrawEnv(&(ctx->buffers[1].draw_env), 0, h, w, h);
+ SetDefDispEnv(&(ctx->buffers[1].disp_env), 0, h, w, h);
+
+ // Set the default background color and enable auto-clearing.
+ setRGB0(&(ctx->buffers[0].draw_env), r, g, b);
+ setRGB0(&(ctx->buffers[1].draw_env), r, g, b);
+ ctx->buffers[0].draw_env.isbg = 1;
+ ctx->buffers[1].draw_env.isbg = 1;
+
+ // Initialize the first buffer and clear its OT so that it can be used for
+ // drawing.
+ ctx->active_buffer = 0;
+ ctx->next_packet = ctx->buffers[0].buffer;
+ ClearOTagR(ctx->buffers[0].ot, OT_LENGTH);
+
+ // Turn on the video output.
+ SetDispMask(1);
+}
+
+void flip_buffers(RenderContext *ctx) {
+ // Wait for the GPU to finish drawing, then wait for vblank in order to
+ // prevent screen tearing.
+ DrawSync(0);
+ VSync(0);
+
+ RenderBuffer *draw_buffer = &(ctx->buffers[ctx->active_buffer]);
+ RenderBuffer *disp_buffer = &(ctx->buffers[ctx->active_buffer ^ 1]);
+
+ // Display the framebuffer the GPU has just finished drawing and start
+ // rendering the display list that was filled up in the main loop.
+ PutDispEnv(&(disp_buffer->disp_env));
+ DrawOTagEnv(&(draw_buffer->ot[OT_LENGTH - 1]), &(draw_buffer->draw_env));
+
+ // Switch over to the next buffer, clear it and reset the packet allocation
+ // pointer.
+ ctx->active_buffer ^= 1;
+ ctx->next_packet = disp_buffer->buffer;
+ ClearOTagR(disp_buffer->ot, OT_LENGTH);
+}
+
+void *new_primitive(RenderContext *ctx, int z, size_t size) {
+ // Place the primitive after all previously allocated primitives, then
+ // insert it into the OT and bump the allocation pointer.
+ RenderBuffer *buffer = &(ctx->buffers[ctx->active_buffer]);
+ uint8_t *prim = ctx->next_packet;
+
+ addPrim(&(buffer->ot[z]), prim);
+ ctx->next_packet += size;
+
+ // Make sure we haven't yet run out of space for future primitives.
+ assert(ctx->next_packet <= &(buffer->buffer[BUFFER_LENGTH]));
+
+ return (void *) prim;
+}
+
+// A simple helper for drawing text using PSn00bSDK's debug font API. Note that
+// FntSort() requires the debug font texture to be uploaded to VRAM beforehand
+// by calling FntLoad().
+void draw_text(RenderContext *ctx, int x, int y, int z, const char *text) {
+ RenderBuffer *buffer = &(ctx->buffers[ctx->active_buffer]);
+
+ ctx->next_packet = (uint8_t *)
+ FntSort(&(buffer->ot[z]), ctx->next_packet, x, y, text);
+
+ assert(ctx->next_packet <= &(buffer->buffer[BUFFER_LENGTH]));
+}
+
+/* Main */
+
+#define SCREEN_XRES 320
+#define SCREEN_YRES 240
+
+int main(int argc, const char **argv) {
+ // Initialize the GPU and load the default font texture provided by
+ // PSn00bSDK at (960, 0) in VRAM.
+ ResetGraph(0);
+ FntLoad(960, 0);
+
+ // Set up our rendering context.
+ RenderContext ctx;
+ setup_context(&ctx, SCREEN_XRES, SCREEN_YRES, 63, 0, 127);
+
+ int x = 0, y = 0;
+ int dx = 1, dy = 1;
+
+ for (;;) {
+ // Update the position and velocity of the bouncing square.
+ if (x < 0 || x > (SCREEN_XRES - 64))
+ dx = -dx;
+ if (y < 0 || y > (SCREEN_YRES - 64))
+ dy = -dy;
+
+ x += dx;
+ y += dy;
+
+ // Draw the square by allocating a TILE (i.e. untextured solid color
+ // rectangle) primitive at Z = 1.
+ TILE *tile = (TILE *) new_primitive(&ctx, 1, sizeof(TILE));
+
+ setTile(tile);
+ setXY0 (tile, x, y);
+ setWH (tile, 64, 64);
+ setRGB0(tile, 255, 255, 0);
+
+ // Draw some text in front of the square (Z = 0, primitives with higher
+ // Z indices are drawn first).
+ draw_text(&ctx, 8, 16, 0, "Hello world!");
+
+ flip_buffers(&ctx);
+ }
+
+ return 0;
+}
diff --git a/template/system.cnf b/template/system.cnf
new file mode 100644
index 0000000..e221726
--- /dev/null
+++ b/template/system.cnf
@@ -0,0 +1,4 @@
+BOOT=cdrom:\template.exe;1
+TCB=4
+EVENT=10
+STACK=801FFFF0