I will attach the GitHub repository first: wasm3-tinygo-psp.
Main Topic
For some time now, I have wanted to run Golang on the PSP.
However, native compilation to the PSP is impossible (probably).
Certainly, Golang does support GOARCH=mipsle
, but it assumes the presence of an operating system. If you attempt to achieve this, you would likely have to navigate a very difficult and thorny path.
So, I chose another way. In other words, the approach is to convert it into WASM using TinyGo.
Now, let’s take a look at the actual code.
package main
import "unsafe"
//go:wasmimport debug println
func println(ptr unsafe.Pointer, len int32)
//export start
func start() {
main()
}
func main() {
message := "Hello, WebAssembly, from Golang!"
println(unsafe.Pointer(unsafe.StringData(message)), int32(len(message)))
}
Essentially, we are simply calling the functions provided by the runtime. It’s just a Hello World example.
About runtime
There was also an option to use Rust and wasmi for the runtime, but although it worked on emulators like PPSSPP, errors occurred on the actual hardware (as shown in the screenshot below).
I suspect it may be related to kernel mode, but since I ultimately couldn’t resolve it, I took a different approach.
Ultimately, the combination of C and Wasm3 worked successfully.
Regarding println
, which was mentioned in the earlier code, it is defined on the runtime side as follows.
#define printf pspDebugScreenPrintf
static const void* host_debug_println(IM3Runtime runtime, IM3ImportContext ctx, uint64_t *stack, void *mem)
{
uint32_t ptr = (uint32_t) stack[0];
uint32_t length = (uint32_t) stack[1];
uint8_t* bytes = (uint8_t*)mem + ptr;
char buffer[256];
if (length >= sizeof(buffer)) {
length = sizeof(buffer)-1;
}
memcpy(buffer, bytes, length);
buffer[length] = '\0';
printf("%s\n", buffer);
return NULL;
}
Since this is just a demo, this is all for now. However, if you also wrap other functions and make them callable from WASM, you should be able to develop full-fledged applications.
Challenges Faced
Cross-compiling Wasm3
It was necessary to compile Wasm3 using the PSP toolchain.
I created a forked repository to make it easy for everyone to set up the environment, so please take a look for reference: wasm3-for-psp.
TinyGo build options
In the end, I ended up with the command tinygo build -o hello.wasm -target=wasm -no-debug main.go
, but it took me quite a bit of time just to arrive at such a simple command. I still have a lot to learn.
Export main
function
If you are using -target=wasi
, TinyGo exports the main function as _start
. But in this case, I had to define and export a separate start
function.
And then…
This time, I used TinyGo to compile Golang code into WASM, but if other languages can also be compiled into WASM, I believe they can be executed using a similar method. I am passionate about Golang, so I would be happy if someone could give it a try.
That’s all. Thank you for reading.