Maison >développement back-end >Golang >Golang sur PSP (et autres langues)

Golang sur PSP (et autres langues)

Linda Hamilton
Linda Hamiltonoriginal
2025-01-03 12:33:431025parcourir

J'ai décidé d'essayer d'utiliser Golang sur la PSP et j'ai exploré plusieurs approches, notamment le portage de Clang, l'utilisation de TinyGo et la compilation de Golang en JavaScript avec GopherJS. Ensuite, je suis tombé sur un utilisateur nommé aethiopicuschan sur le homebrew Discord PSP, qui tentait le même objectif en utilisant WebAssembly. Son exemple fonctionnait sur PPSSPP mais pas sur le matériel réel.

Quoi qu'il en soit, j'ai dû suspendre mon projet à cause des examens à venir. Mais, quelques mois plus tard, j'ai trouvé un article dans lequel aethiopicuschan avait réussi à compiler Golang en WASM et à l'exécuter sur la PSP à l'aide d'un interpréteur WASM.
Son approche utilisait un interpréteur Wasm appelé Wasm3 pour exécuter le code, mais je savais que je pouvais faire mieux. Je connaissais des projets comme Wasm2C qui convertissent vos binaires Wasm en C.
Enthousiasmé, j'ai approfondi le sujet et découvert un article sur la compilation de WebAssembly en code C portable. Ils ont utilisé un compilateur appelé w2c2, qui, je suppose, est la suite.

Après des heures de bricolage avec CMake, j'ai réussi à créer un exemple fonctionnel en utilisant TinyGo et en ciblant WASI. J'ai également enveloppé une fonction raylib, InitWindow (la psp a d'ailleurs un port raylib), dans le but de porter les liaisons raylib-go sur cette plateforme WASM-to-C. L'exemple lie avec succès la fonction C InitWindow au code WASM compilé.

Comme vous pouvez le voir, cela ressemble à n'importe quel autre code Golang

package main

import "time"

import rl "github.com/gen2brain/raylib-go/raylib"

func main() {

    rl.InitWindow(480, 272, "Psp test")
    for {
        time.Sleep(time.Millisecond * 16)
    }
}

mais dans le package rl, nous importons une fonction C, nous lui donnons également une signature de fonction. Gardez cela à l’esprit.


package rl

//go:wasmimport rl InitWindow
func c_InitWindow(width int32, height int32, title string)

// InitWindow - Initialize Window and OpenGL Graphics

func InitWindow(width int32, height int32, title string) {
    c_InitWindow(width, height, title)
}

Décomposons ce code étape par étape.

#define __GLIBC_USE

#include <raylib.h>
#include <stdio.h>
#include <time.h>

#include <pspkernel.h>
PSP_MODULE_INFO("WasiExample", 0, 1, 0);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER);
#include "pspdebug.h"
#define printf pspDebugScreenPrintf

d'abord, nous importons les bibliothèques psp et configurons la plaque chauffante, nous importons également le port raylib

ici nous importons le module compilé app.h
nous importons également le "runtime" wasi qui est fourni par w2c2

// // the compiled wasm -> C code
#include "app.h"
// // wasi runtime
#include "w2c2_base.h"
#include "wasi.h"

extern wasmMemory* e_memory;  // the WASM memory.
void trap(Trap trap)
{
  fprintf(stderr, "TRAP: %s\n", trapDescription(trap));
  abort();
}

wasmMemory* wasiMemory(void* instance)
{
  return app_memory((appInstance*)instance);
}
extern char** environ;

La fonction piège est une plaque chauffante,
la fonction wasiMemory est une fonction d'assistance que j'ai créée pour une autre fonction d'assistance

char* getCStringFromMemory(void* memoryptr, U32 offset, U32 length)
{
  wasmMemory* memory = wasiMemory(memoryptr);
  char* str = (char*)(memory->data + offset);
  char* result = (char*)malloc(
    length + 1);  // Allocate space for the string + null terminator
  if (result == NULL) {
    fprintf(stderr, "Memory allocation failed\n");
    return NULL;
  }

  // Copy the string from WASI memory to local memory
  for (U32 i = 0; i < length; ++i) {
    result[i] = str[i];
  }
  result[length] = '<pre class="brush:php;toolbar:false">void rl__InitWindow(
  void* memoryptr, U32 width, U32 height, U32 offset, U32 length)
{
  char* title = getCStringFromMemory(memoryptr, offset, length);
  InitWindow(width, height, title);
  bool ready = IsWindowReady();
  if (ready) {
    // this will print to the psp screen.
    printf("Window was created");
  }
}

'; // Null-terminate the string return result; }

tout ce que fait cette fonction, c'est qu'elle prend le pointeur mémoire pour un pointeur mémoire de chaîne (dans wasm, nous traitons les chaînes en passant un décalage mémoire et la longueur de la chaîne), et renvoie une chaîne C en utilisant le décalage et la longueur.

c'est la fonction C que nous appelons depuis notre code golang, j'ai dû la définir moi-même.

int main(int argc, char* argv[])
{
  pspDebugScreenInit();
  appInstance i;
  appInstantiate(&i, NULL);
  if (!wasiInit(argc, argv, environ)) {
    fprintf(stderr, "failed to initialize WASI\n");
    return 1;
  }

  app__start(&i);
  appFreeInstance(&i);
  return 0;
}

nous lisons les arguments transmis par le wasm transpilé et les transmettons à Raylib.


c'est encore un passe-partout, tout ce que nous faisons est d'exécuter la fonction principale du code golang, qui est exporté sous app_start()

Golang on PSP (and other languages)

Ça marche!

Ceci est une capture d'écran d'un émulateur PSP.
mais cela fonctionne également sur le matériel d'origine.

Laissez vos questions dans la section commentaires !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn