🎮

Wasm3 + TinyGo on PSP!

2024/12/17に公開

本題

以前 PSP上でWASMを実行するデモ という記事を書きましたが、これはエミュレータでは動きますが実機では以下のようなエラーになってしまうという問題がありました。

これについていろいろと試しましたが解決しないため、別のアプローチを取ったところ、うまくいきました。今回はそれに関する記事です。

先に成果物からお見せしますと、以下のコードをTinyGoでWASMにして、C言語 + Wasm3で作ったランタイムで実行しました。

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)))
}

実機での動作は以下のようになっています。

しっかりと出力できていますね。

ランタイム側では以下のように定義しています。

#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;
}

今回はデモということでpspDebugScreenPrintfのみですが、その他の関数も同じようにラップしてWASM側に渡せば、理論上TinyGoでのPSPアプリケーション開発が可能になるはずです。今後はその方向で開発を進めたいと思います。

その他細かいことはGitHubリポジトリを参照してください。

おまけ(1) Wasm3をフォークした

Wasm3をフォークしてPSP向けに改造しました。これを使うと環境構築が多少楽になります。

wasm3-for-psp

おまけ(2) ハマったところ

  1. Wasm3のクロスコンパイル。ChatGPTのおかげでうまいこといけました。

  2. TinyGoに渡す引数。最終的に tinygo build -o hello.wasm -target=wasm -no-debug main.go となりましたが、-target=wasiだとうまくいかないとか-no-debugが無いとエラーになったりとか模索に模索を重ねました。

  3. main関数をラップしてexportすること。target=wasiだと_startという名前でexportしてくれるが、今回のようにtarget=wasmの場合は一工夫いる。

以上!

Discussion