>백엔드 개발 >Golang >PSP(및 기타 언어)의 Golang

PSP(및 기타 언어)의 Golang

Linda Hamilton
Linda Hamilton원래의
2025-01-03 12:33:431021검색

저는 PSP에서 Golang을 사용해 보기로 결정하고 Clang 포팅, TinyGo 사용, GopherJS를 사용하여 Golang을 JavaScript로 컴파일하는 등 여러 가지 접근 방식을 탐색했습니다. 그러다가 PSP 홈브류 Discord에서 WebAssembly를 사용하여 동일한 목표를 시도하는 aethiopicuschan이라는 사용자를 만났습니다. 그의 예는 PPSSPP에서는 작동했지만 실제 하드웨어에서는 작동하지 않았습니다.

아무튼, 다가오는 시험 때문에 프로젝트를 보류해야 했어요. 그러나 몇 달 후, aethiopicuschan이 Golang을 WASM으로 성공적으로 컴파일하고 WASM 인터프리터를 사용하여 PSP에서 실행한 기사를 발견했습니다.
그의 접근 방식은 Wasm3이라는 Wasm 인터프리터를 사용하여 코드를 실행했지만 나는 더 잘할 수 있다는 것을 알았습니다. 나는 Wasm 바이너리를 C로 변환하는 Wasm2C와 같은 프로젝트에 대해 알고 있었습니다.
신이 나서 주제에 대해 더 깊이 파고들었고 WebAssembly를 이식 가능한 C 코드로 컴파일하는 방법에 대한 기사를 발견했습니다. 그들은 w2c2라는 컴파일러를 사용했는데, 아마도 후속작인 것 같습니다.

몇 시간 동안 CMake를 수정한 후 TinyGo를 사용하고 WASI를 대상으로 하는 작업 예제를 만들 수 있었습니다. 또한 raylib-go 바인딩을 이 WASM-to-C 플랫폼으로 포팅하는 것을 목표로 raylib 함수인 InitWindow(psp에는 raylib 포트가 있음)를 래핑했습니다. 이 예제는 C InitWindow 함수를 컴파일된 WASM 코드에 성공적으로 바인딩합니다.

보시다시피 다른 골랭 코드와 비슷해 보입니다

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

그러나 rl 패키지에서는 C 함수를 가져오고 함수 시그니처도 제공합니다. 꼭 기억해두세요.


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

이 코드를 단계별로 분석해 보겠습니다.

#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

먼저 psp 라이브러리를 가져오고 보일러 플레이트를 설정한 다음 raylib 포트도 가져옵니다.

여기서 컴파일된 모듈 app.h를 가져옵니다
또한 w2c2에서 제공하는 wasi "런타임"을 가져옵니다

// // 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;

트랩 기능은 보일러플레이트,
wasiMemory 함수는 다른 도우미 함수를 위해 제가 만든 도우미 함수입니다

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

이 함수가 하는 일은 문자열 메모리 포인터에 대한 메모리 포인터를 취하고(wasm에서는 메모리 오프셋과 문자열 길이를 전달하여 문자열을 처리함) 오프셋과 길이를 사용하여 C 문자열을 반환하는 것뿐입니다.

이것은 golang 코드에서 호출하는 C 함수이므로 직접 정의해야 했습니다.

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

트랜파일된 wasm이 전달한 인수를 읽고 이를 raylib에 전달합니다.


이것은 또 다른 상용구입니다. 우리가 하는 일은 app_start()로 내보내지는 golang 코드의 주요 기능을 실행하는 것뿐입니다.

Golang on PSP (and other languages)

그것은 작동합니다!

PSP 에뮬레이터의 스크린샷입니다.
하지만 원래 하드웨어에서도 작동합니다.

궁금한 점은 댓글로 남겨주세요!

위 내용은 PSP(및 기타 언어)의 Golang의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.