1P by GN⁺ | ★ favorite | 댓글 1개
  • Trial 게임 엔진을 Nintendo Switch에서 돌리기 위해 Common Lisp 런타임 SBCL을 2년간 포팅했고, 현재 Switch에서 Lisp 코드 컴파일·실행과 공유 라이브러리 연동까지 도달함
  • Switch는 ARM64 Cortex-A57 4코어, 4GB RAM 환경이지만 셸·명령줄·컴파일러가 없고 실행 가능 페이지 생성도 막혀 있어, 일반적인 SBCL 부트스트랩 방식과 맞지 않음
  • 빌드는 Linux ARM64 호스트와 Nintendo SDK를 조합하고, fasteval, immobile-code, elfination으로 코어를 코드와 데이터로 나눈 뒤 최종 패키지로 묶는 구조임
  • Trial REPL 예제는 Switch devkit에서 OpenGL 컨텍스트, 입력 처리, 셰이더 할당까지 수행하지만, 가비지 컬렉터 실행 시 크래시하고 C 콜백 문제로 오디오는 아직 불가능함
  • 남은 핵심 작업은 멀티스레드 GC용 safepoint 안정화, C 콜백 복구, CLOS 런타임 컴파일 회피, 성능 최적화이며 Nintendo NDA 때문에 일부 코드는 공개할 수 없음

Switch에서 SBCL이 어디까지 동작하는가

  • Trial 게임 엔진을 Nintendo Switch에서 실행하기 위해 Charles Zhang과 함께 지난 2년간 SBCL 포팅을 진행함
  • 핵심 난제는 Trial 아래에서 동작하는 Common Lisp 런타임을 Switch 플랫폼에 맞추는 일이었음
  • 현재 가능한 일:
    • 런타임과 컴파일러를 포팅해 Switch에서 임의의 Lisp 코드를 직접 컴파일·실행할 수 있음
    • 공유 라이브러리와 인터페이스할 수 있음
    • Trial이 Switch에서 필요로 하는 여러 운영체제 이식성 라이브러리도 포팅함
  • Trial의 REPL 예제는 Switch devkit에서 실행됨
    • Switch 자체에는 터미널이 없기 때문에 Trial이 OpenGL 컨텍스트를 만들고 입력을 관리하며 셰이더를 할당해 화면에 텍스트를 표시함
  • 아직 막힌 부분:
    • SBCL이 가비지 컬렉터를 동작시키려 하면 곧 크래시함
    • Switch의 고유 제약 때문에 우회하지 못한 부분이 남아 있음
    • C 콜백 메커니즘이 깨져 있어 오디오 출력이 불가능함
    • 성능과 관련해 아직 드러나지 않은 문제가 더 있을 수 있음

비용과 지속 가능성

  • 포팅 작업에는 지금까지 약 17,000달러가 들었고, Charles Zhang에게 월 단위로 비용을 지급해 왔음
  • 수입은 Kandria 판매와 Patreon, GitHub Sponsors, Ko-Fi 후원에서 나옴
    • 좋은 달에는 약 1,200달러
    • 나쁜 달에는 약 600달러
  • Zürich, Switzerland에서 이 수입만으로 생활하기 어렵고, 현재는 부모와 함께 살며 개인 지출을 줄여 버티는 상황임
  • Switch용 Kandria 판매가 포팅 비용을 회수할 수 있을지 의심되기 때문에, 제한된 자원을 어디에 쓸지 결정하기 어려워짐
  • 후원 수입은 당분간 SBCL Switch 포팅과 현재 진행 중인 미공개 게임 프로젝트에 쓰일 예정임

Switch 환경과 포팅 조건

  • 공개적으로 알려진 Switch 환경:
    • 사용자 코드는 ARM64 Cortex-A57 칩에서 실행됨
    • 4코어와 4GB RAM을 사용함
    • Nintendo 3DS용으로 처음 개발된 독점 마이크로커널 운영체제 위에서 동작함
  • SBCL에는 이미 ARM64 Linux 포트가 있어 코드 생성 측면은 해결된 상태임
  • Kandria는 4GB RAM에 쉽게 들어가므로 메모리 용량 자체는 문제가 아님
  • 실제 난점은 Switch의 독점 운영체제와 인터페이스하는 데 있음
    • 일반 PC 운영체제에는 없는 제약이 있음
    • Lisp 같은 시스템에는 특히 문제가 됨
  • Switch는 Trial이 기반으로 하는 OpenGL 렌더링을 지원하는 유일한 콘솔임
    • Xbox는 DirectX만 지원하지만 Microsoft가 개발한 OpenGL → DirectX 계층이 있다고 알려져 있어 가능성이 있을 수 있음
    • Playstation은 완전 독점 그래픽 API를 가진 것으로 알려져 있어 해당 플랫폼 포팅은 고려하고 싶지 않은 대상으로 남음
  • 개발을 위해 Nintendo of Europe에서 접근 권한을 받았고, 약 400달러의 devkit을 구매함
  • devkit과 SDK는 Windows에서만 실행되며, 이후 빌드 과정의 부담으로 이어짐

일반적인 SBCL 빌드와 Switch에서의 충돌

  • SBCL은 주로 Lisp 자체로 작성되어 있으며, 작은 C 런타임도 포함함
  • C 런타임은 일반 C 컴파일러로 빌드하지만, 대상 운영체제 환경에 대한 정보를 알아야 함
  • 런타임 자체에는 Lisp 컴파일러가 없기 때문에, SBCL을 부트스트랩하려면 다른 Lisp 구현이 필요하며 이상적으로는 다른 버전의 SBCL을 사용함
  • PC에서의 5단계 빌드

    • build-config
      • 대상용 빌드 설정 옵션을 모아 이후 빌드 단계가 읽을 수 있는 형식으로 출력함
    • make-host-1
      • 호스트 Lisp 컴파일러로 크로스 컴파일러를 빌드함
      • Lisp 객체의 메모리 배치를 C 구조체로 설명하는 헤더 파일도 생성함
    • make-target-1
      • 대상 C 컴파일러로 C 런타임을 생성함
      • C 런타임에는 가비지 컬렉터와 운영체제 환경과의 접착 코드가 포함됨
      • 운영체제 헤더에서 대상 Lisp 컴파일러와 런타임이 알아야 할 상수도 생성함
    • make-host-2
      • make-host-1에서 만든 Lisp 크로스 컴파일러로 대상 Lisp 시스템, 즉 컴파일러와 표준 라이브러리를 빌드함
      • 런타임이 진입할 수 있는 cold core를 생성함
    • make-target-2
      • cold core를 대상 런타임에 로드하고 부트스트랩을 마무리함
      • Lisp 시스템이 메모리에 로드된 뒤 warm core로 덤프됨
      • 이후에는 새 코드를 로드하고 새 이미지를 자유롭게 덤프할 수 있음
  • Switch에서 문제가 되는 지점

    • SBCL 빌드에는 대상 머신에서 Lisp 코드를 실행하는 단계가 필요함
    • 사용자 Lisp 코드는 C처럼 단순 배치 컴파일만으로 처리할 수 없고, 실행될 때 대상 환경에 있다고 가정함
    • 애플리케이션 배포도 make-target-2와 비슷하게 Lisp 코드를 점진적으로 컴파일한 뒤 런타임이 붙은 core를 덤프함
    • SBCL 런타임은 시작 시 core blob을 메모리에 매핑하고, 코드 페이지를 실행 가능으로 표시한 뒤 사용자 지정 진입 함수로 점프함
    • Switch에서는 이 방식 전체가 문제가 됨

Switch용 빌드 전략

  • Switch는 PC 환경이 아니며 셸, 명령줄, 컴파일러 제품군이 없음
  • 운영체제가 실행 가능 페이지 생성을 허용하지 않기 때문에, 빌드 단계를 Switch에서 실행할 수 있더라도 일반적인 Lisp 점진 컴파일은 불가능함
  • 대부분의 코드는 플랫폼 독립적이므로 ARM64용으로 컴파일할 수 있음
  • 주변 운영체제 환경을 건드리는 부분만 Switch 대상임을 알게 만들고, Linux 같은 다른 ARM64 환경에서 구현을 만들 수 있음
  • Switch용 빌드 단계

    • build-config
      • 호스트 시스템에서 실행하며 Switch 빌드를 나타내는 특수 플래그를 사용함
      • fasteval contrib를 활성화함
      • Switch에서는 런타임 컴파일을 할 수 없으므로 fasteval이 컴파일러 호출이 필요한 지점을 대신함
    • make-host-1
      • 큰 변화는 없고 Switch 플랫폼 준비용 헤더를 생성함
    • make-target-1
      • Nintendo SDK가 제공하는 C 컴파일러로 Switch용 C 런타임을 크로스 컴파일함
      • Switch OS는 POSIX 호환이 아니므로 SBCL에 커스텀 런타임 대상을 만들고, 동적 링킹·페이지 매핑 같은 운영체제 차이를 스텁 처리하거나 감쌈
    • 두 번째 build-config, make-host-1, make-target-1
      • Switch와 같은 기능 집합을 가진 일반 ARM64 Linux 시스템을 만듦
      • 일부 Lisp 프로세스에는 최종 대상이 Switch임을 알리는 특수 플래그를 사용함
    • make-host-2, make-target-2
      • 약간 특수한 Linux ARM64용 SBCL 빌드를 얻고, 이후 사용자 코드를 컴파일함
    • 사용자 코드 컴파일
      • Linux가 아니라 Switch에서 실행 중이라고 믿게 만들기 위해 *features*를 수정함
      • :nx를 포함하고 :linux, :unix, :posix는 제외함
      • ASDF를 무력화한 뒤 Trial 같은 프로그램을 일반적인 방식에 가깝게 컴파일하고 새 core를 덤프함

immobile-code와 elfination으로 core를 패키징

  • Switch에서는 일반적인 core 매핑 전략을 사용할 수 없으므로, Switch용 런타임에 새 core를 붙이는 방식이 동작하지 않음
  • 해결책으로 SBCL의 상대적으로 덜 알려진 기능인 immobile-codeelfination을 사용함
  • 일반적인 SBCL은 런타임에 컴파일한 코드를 어떤 페이지에 넣고 그 페이지를 실행 가능으로 표시함
    • 나중에 코드가 필요 없어지면 가비지 컬렉션 대상이 될 수 있음
    • 공간을 회수하고 나머지 코드를 압축할 수 있음
  • immobile-code는 다른 전략을 사용함
    • 코드를 특별히 예약된 코드 페이지에 넣고 그 자리에 유지함
    • 코드는 가비지 컬렉션될 수 없음
    • 대신 전통적인 운영체제 실행 파일 지원을 활용할 수 있음
    • 실행 파일에는 운영체제가 코드로 알고 있는 미리 표시된 섹션이 있고, 프로그램 시작 시 운영체제가 매핑을 처리함
  • elfination 단계는 core를 일반 실행 파일에 필요한 별도의 코드와 데이터 섹션으로 변환함
    • elfinator가 core를 분석함
    • 주소 공간 배치 난수화에 필요한 위치 독립 코드가 되도록 어셈블리를 다시 작성함
    • 순수 코드 어셈블리 파일과 순수 데이터 페이로드 파일로 분리함
  • 최종 단계:
    • elfinator로 어셈블리 파일 생성
    • 최종 바이너리 링크
    • Nintendo SDK의 authoring 도구로 메타데이터, 공유 라이브러리, 애셋, 애플리케이션 바이너리를 하나의 최종 패키지로 묶음

빌드 인프라와 공개 가능한 범위

  • 빌드에는 최소한 대부분의 빌드를 수행할 ARM64 Linux 머신이 필요함
  • Nintendo SDK 컴파일러와 authoring 도구를 실행하려면 AMD64 Windows 머신이나 Wine을 사용하는 AMD64 Linux 머신이 필요함
  • 실제 구성은 총 세 대에 가까움
    • AMD64 “driver”
    • ARM64 빌드 호스트
    • devkit과 통신하는 Windows VM
  • 캐싱과 머신 간 동기화 로직을 갖춘 특수 빌드 시스템을 작성해 자동화함
    • MSYS2/Windows 환경에서도 구동 가능해야 해 경로 변환 문제가 있었음
  • ARM64에서 elfinator와 immobile-code를 동작하게 하고, pathname-utils, libmixed, cl-gamepad 같은 지원 라이브러리도 포팅함
  • Nintendo NDA 때문에 많은 세부 사항은 공개할 수 없음
  • 공개 가능한 작업은 upstream했고, Lisp 라이브러리들은 private fork를 두지 않음
  • Nintendo SDK와 직접 연결하지 않기 위해 별도의 C 라이브러리를 만들고, Lisp 라이브러리들은 이 커스텀 인터페이스를 통해 운영체제 기능에 접근함
    • Lisp 쪽은 공개하고 작은 C 라이브러리만 비공개로 유지하기 위한 구조임

절대 포인터와 로드 시 재배치

  • elfination은 처음부터 위치 독립 실행 Lisp 코드를 만들도록 설계된 기능이 아니었음
  • Lisp 코드는 보통 절대 포인터를 많이 포함함
  • SBCL 컴파일러와 런타임에서 로드 시 절대 포인터 재배치를 지원하기 위한 작업이 필요했음
  • 코드 객체에는 보통 코드 상수가 들어 있으며, 더 이상 절대 포인터를 갖지 않도록 해야 했음
    • GC는 실행 섹션을 수정할 수 없음
    • OS 로더도 절대 포인터 재배치를 위해 실행 섹션을 수정할 수 없음
  • 해결 방식:
    • 코드 상수 같은 절대 포인터를 text 영역 밖의 읽기/쓰기 가능 공간으로 옮김
    • 코드 안의 상수 참조를 이 읽기/쓰기 공간에서 로드하도록 다시 작성함
    • 로더와 이동 GC가 해당 공간의 포인터를 수정할 수 있음

가비지 컬렉터와 safepoint 문제

  • SBCL의 표준 GC는 gencgc, 즉 세대별 가비지 컬렉터임
  • gencgc는 객체 세대를 분리해 서로 다른 빈도로 스캔하고, 객체를 다른 세대 위치로 복사해 공간을 압축함
  • 이 구조 자체는 Switch에서 본질적인 문제가 아니지만, 멀티스레딩이 문제를 만듦
  • 여러 스레드가 있으면 한 스레드가 객체를 접근하는 중일 수 있어 객체를 마음대로 이동할 수 없음
  • 가장 쉬운 해결책은 GC 시작 전에 모든 스레드를 멈춰 세우는 것임
  • Unix와 Switch의 차이

    • Unix 시스템에서는 signal 메커니즘으로 다른 스레드에 신호를 보내 park하도록 만들 수 있음
    • Switch에는 signal 메커니즘이 없고, 스레드를 interrupt할 수도 없음
    • 각 스레드가 스스로 park해야 한다는 사실을 알아차리게 만들어야 하며, 일반적인 전략은 safepoint
    • safepoint는 컴파일러가 추가 코드를 삽입해 스레드가 park해야 하는지 확인하게 함
    • 체크를 추가하는 비용이 있으므로 가능한 적게 해야 함
    • 너무 드물게 체크하면 모든 스레드가 park될 때까지 GC가 시작할 수 없어 다른 스레드가 멈춤
    • 체크에 많은 명령이 필요하면 CPU 캐시 라인과 파이프라이닝 최적화를 방해함
  • 기존 SBCL safepoint의 한계

    • SBCL의 현재 safepoint 시스템은 Windows용으로 작성됨
    • Windows도 프로세스 간 signal handler는 없지만, Switch와 달리 현재 스레드용 signal handling은 있음
    • 기존 방식:
      • 각 스레드는 safepoint가 word 하나를 쓰는 페이지를 유지함
      • GC가 시작되면 그 페이지를 읽기 전용으로 표시함
      • 다른 스레드가 safepoint에 도달해 페이지에 쓰려 하면 segmentation fault가 발생하고 해당 스레드가 park함
      • 단일 쓰기 명령만 필요해 효율적임
    • Switch에서는 이 기법도 사용할 수 없어 더 복잡한 체크를 삽입해야 함
    • safepoint는 Windows 외 플랫폼에서 필요하지 않았기 때문에 다른 곳에서 테스트되지 않았고, Switch용 수정과 별개로 불안정함
    • 코드베이스에서 해당 부분은 크게 정리되어야 할 수 있지만, 완전 재작성까지 가지 않기를 바라는 상태임

CLOS 런타임 컴파일 회피

  • CLOS는 메서드 디스패치에 필요한 discriminating function 컴파일을 일반적으로 제네릭 함수의 첫 호출까지 미룸
  • CLOS는 매우 동적이며 메서드를 거의 언제든 추가·삭제할 수 있어, 시스템이 완성된 시점을 알기 어렵기 때문임
  • Switch에서는 컴파일러를 호출할 수 없으므로 이 지연 컴파일 방식을 그대로 사용할 수 없음
  • 현재 전략은 fast evaluator에 의존하는 것임
    • compile 함수를 스텁 처리함
    • 컴파일 대신 evaluator로 코드를 실행하는 lambda를 생성함
    • compile에 의존하는 사용자 코드에도 동작함
    • 실제 컴파일보다 실행 속도는 훨씬 느림

남은 작업과 성능 리스크

  • fasteval 방식은 주로 fallback임
  • 최종 이미지를 덤프하기 직전에 가능한 많은 CLOS 상태를 고정하고, 가능한 많은 코드를 사전 컴파일하는 방법을 탐색하고자 함
  • Charles가 몇 년 전에 복원한 block compilation mode도 더 조사할 예정임
  • Switch의 상대적으로 약한 프로세서 때문에 추가 최적화가 필요할 수 있음
    • Trial 엔진 쪽
    • Kandria 코드 쪽
  • 지금까지는 10년 전 컴퓨터도 게임 요구사항을 충분히 처리했기 때문에 최적화를 비교적 적게 해도 됐음
  • 우선순위가 높은 작업:
    • 가비지 컬렉터를 완전히 동작하게 만들기
      • 현재는 부팅 후 Trial 메인 루프까지 들어갈 수 있음
      • multi-generation compaction에 도달하면 실패함
    • C에서 오는 콜백을 다시 동작하게 만들기
      • SBCL 코드베이스의 해당 부분은 수작업 어셈블리 루틴이 많음
      • immobile-code와 elfination에 맞게 조정이 필요할 수 있음
      • Trial은 libmixed를 통한 사운드 재생에만 콜백을 필요로 함
    • Trial의 selftest suite가 Switch에서 완전히 통과하기 전 필요한 추가 이식성 기능 작업

NDA로 제한되는 공개 범위

  • 포팅 작업 전체를 공개하고 싶지만 Nintendo NDA 때문에 공개할 수 없음
  • 공개 가능한 부분은 upstream하거나 공개함
  • Nintendo SDK와 직접 연결되는 일부 코드는 NDA에 서명하지 않은 사람에게 공유할 수 없음
  • Nintendo Switch에서 Common Lisp 게임을 출시하려는 사람이 있다면, NDA 서명 후 포팅 작업 접근 권한을 받을 수 있음
  • Patron을 위한 월간 업데이트에서는 진행 상황을 더 자세히 공유할 예정임

댓글과 토론

Hacker News 의견들
  • 지난 몇 주 동안 Common Lisp로 게임 개발을 시험해 보려고 Trial(https://github.com/Shirakumo/trial)을 써봤는데 아주 즐거웠음
    게임이 실행 중인 상태에서 거의 모든 요소를 바꿀 수 있다는 점이 정말 큰 장점이라, 이 포팅이 성공하길 바람

    • Lisp 계열 언어는 게임 제작에 잘 맞아 보임. 재컴파일 없이 대화식으로 코드 평가가 가능하다는 건 기능 개발, 점진적 개발, 버그 수정에서 큰 차이를 만듦
      코드 변경 사이에 애플리케이션 상태를 유지할 수 있는 것도 매우 유용해 보이고, Common Lisp도 막연히 생각했던 것보다 훨씬 빠른 언어로 보임
      개인적으로는 게임 개발뿐 아니라 전반적으로 자료구조 사용, 특히 맵을 다루는 방식이 투박한 게 가장 큰 단점이지만, 그 절충은 감수할 만해 보임
  • 이건 정말 멋짐. SBCL은 훌륭한 언어 구현이고, “진짜” 게임 콘솔에서 Common Lisp 개발을 해보고 싶었음
    Shinmera가 이 작업을 한다는 것도 좋은 의미로 놀라움. 예전에 #lispgames와 Lisp Discord에서 몇 번 봤지만 이런 저수준 개발에도 관심이 있는지는 몰랐음
    SBCL 내부를 잠깐 들여다봤다가 겁먹고 물러난 적이 있어서 더 대단해 보임. SBCL에 스레딩과 SDL2를 붙인 조합이 지금은 Raspberry Pi에서 동작하는지도 궁금함

    • SBCL 쪽 작업은 내가 하는 게 아니고, 그건 전부 의뢰한 Charles의 작업임. 내가 맡은 건 Trial이 여러 환경에서 동작하도록 하는 이식성 부분, 전체 빌드 구조, 초기 런타임 스텁임
      그리고 앞서 말했듯이 *her :)
    • “her”가 맞지 않나?
  • 흥미롭고 자세한 글을 써준 저자에게 감사함. 이런 수준의 공식 콘솔 포팅 세부사항은 보통 콘솔 수명이 끝나고 몇 년이 지나서야 드러나는 느낌임
    이런 깊이 있는 작업을 읽다 보면, 하루 종일 반복적인 소프트웨어를 쓰고 있는 내 일을 떠올리며 부러워지기도 함

    • 내가 일하던 시절 기준으로는 이런 공식 도구도 대개 꽤 임시방편으로 짜깁기된 물건이었고, 디버깅 지원을 제외하면 오래된 플랫폼용 최신 홈브루 도구체인이 더 나은 경우도 많았음
      개발킷에는 보통 더 좋은 훅이 있었지만, 동시에 GDB 중심 흐름을 피하는 장점도 있었음. 양쪽을 다 겪어보니 그렇게까지 부러워할 만한 세계인지는 잘 모르겠음
    • Ruby on Rails로 또 하루를 시작하려던 참이라, 나중에 내 관심을 쏟을 만한 취미나 오픈소스 프로젝트가 뭐가 있을지 생각하고 있었음
      어쩌면 내 관심이 필요로 하는 프로젝트가 아니라, 내 관심이 나중에 필요로 할 프로젝트일지도 모르겠음 :D
  • “전부 공개하고 싶지만 NDA 때문에 그렇게 할 수 없다”는 부분을 보니, 제약 없는 홈브루 SDK(https://switchbrew.org/wiki/Setting_up_Development_Environment) 대신 공식 SDK를 쓴 이유가 궁금함
    완전히 추측하자면, Nintendo가 서드파티 SDK로 빌드한 게임의 공식 출시를 허용하지 않기 때문일 수도 있겠음

    • 홈브루로 만든 게임은 출시할 수 없고 반드시 공식 SDK를 써야 함. 게다가 탈옥된 Switch를 가진 사람은 거의 없어서, 에뮬레이터가 아니면 게임을 실행하기도 매우 어려워짐
  • 관련해서 https://opengoal.dev가 있음
    배경을 보면 Naughty Dog는 PS2의 Jak & Daxter 시리즈를 만들 때 Lisp와 비슷한 자체 언어인 GOAL을 썼음. 디버깅 정보를 충분히 남겨둔 덕분에 역공학이 가능했고, OpenGOAL 프로젝트가 이를 해냈음
    지금은 GOAL 컴파일러가 이식된 모든 플랫폼에서 이 게임들을 실행할 수 있음. 내가 알기로는 현재 x86 정도이고, Switch로 이식되면 멋질 듯함

  • Kandria를 방금 샀음. 게임을 많이 하는 편은 아니라 많이 플레이하진 않을 것 같지만, Shinmera가 Lisp 세계의 경계를 분명히 넓히고 있어서 지원할 만하다고 봄

  • 그녀의 작업은 정말 대단함. 가끔 Common Lisp를 쓰는 입장이라 이런 작업이 매우 기쁨

  • Nintendo나 Sony 같은 회사가 이런 노력을 직접 지원해줬으면 좋겠음. 결국 콘솔용 게임, 즉 IP를 만드는 또 다른 방법인데, 플랫폼 차원에서 Github Accelerator 같은 걸 시작했을 때 단점이 뭐가 있을지 모르겠음

    • 플랫폼 보유자가 요구하는 어떤 절차든 게임 개발자들이 자기 비용으로 통과한다는 건 이미 잘 알려져 있음. 어느 플랫폼에 출시할지 정할 때 기술 세부사항을 두고 까다롭게 굴 만한 협상력이 개발자들에게 별로 없음
      Nintendo는 Switch 출시를 유도할 새 인센티브를 만들 필요가 없음. 이미 1억 4천만 대 이상 판매와 높은 게임 구매율이라는 가장 큰 인센티브가 있기 때문임
      그래도 예전만큼 절차가 많지는 않음. 요즘 시스템은 대부분 범용 CPU와 GPU 아키텍처로 수렴했고, 차이가 있어도 작은 장식 수준인 경우가 많음
    • 과거에는 그런 지원이 있었지만, 사람들이 한 일은 대부분 MAME과 다른 에뮬레이터를 포팅하거나 8비트·16비트 시절 게임을 복제하는 것이었음
      그래서 좋은 걸 누리기 어려워지는 것임
  • 이런 글을 보러 HN에 옴. 원 글쓴이와 동료에게 박수를 보냄. 불가능하다는 건 알지만, Nintendo가 자기 시스템을 조금만 더 개방적으로 다뤄준다면 정말 큰 축복일 것 같음

  • 어디에도 설명이 없어서 덧붙이면, SBCL은 “Steel Bank Common Lisp”임
    “Steel Bank Common Lisp(SBCL)은 고성능 Common Lisp 컴파일러다. 관대한 라이선스의 오픈소스/자유 소프트웨어이며, ANSI Common Lisp용 컴파일러와 런타임 시스템 외에도 디버거, 통계 프로파일러, 코드 커버리지 도구, 여러 확장을 포함한 대화형 환경을 제공한다”
    https://www.sbcl.org/