見出し画像

【狂気】2026年、PS3を開発する——1行もコードを書けない人間が、AIと組んで「開発地獄」と呼ばれたPS3に挑み、15年間誰も開けられなかった扉をこじ開けた1週間の記録。


まえがき
2026年2月23日、散歩中にスマホにClaudeをインストールした。
巷で話題のAIアシスタント。どれほどのものか試してみたかった。最初に思いついたのは「ファミコンのゲームを作ってくれ」という、ほとんど冗談のような依頼だった。
数回の指示で、NESのROMファイルが生成された。エミュレータで起動すると、画面にスプライトが動いた。スマホだけで、プログラミングの知識ゼロで、ファミコンのゲームが動いた。
次の瞬間、頭に浮かんだのはPlayStation 3だった。
1週間後。PS3のcellGcm APIを直接叩き、自作シェーダでBlinn-Phongライティングを計算し、7×7グリッドに48棟のビルが並ぶ1080pの街を自由カメラで歩き回れるようになっていた。5基のSPUが並列でパーティクル物理演算を処理している。VRChatのワールドをPS3上に再現し、XMBのスパークルエフェクトを再現し、PS3の上でファミコンのエミュレータが動いている。
全て、プログラミング知識ゼロの人間が、AIと組んで到達した場所だ。
この記事は、その1週間の記録である。PS3の開発がなぜ「地獄」と呼ばれたのか。AIにコードを書かせるとはどういうことか。AIが同じミスを繰り返す時、どう躾ければいいのか。15年間誰も開けられなかった扉を、プログラミング未経験者がAIと一緒にこじ開けるとき、何が起きるのか。
※注:この先は専門用語の暴風雨です。次のページに用語集を置きました。わからない言葉が出てきたら、そこに戻ってきてください。地図なしでこの嵐に突っ込むのは、SPUのローカルストアにDMAなしでアクセスするのと同じくらい無謀です——と言われて意味がわからなかった人は、まず用語集を読んでください。
では、始めよう。


画像
PS3の基盤

この記事は「プログラミング知識ゼロの人間が書いた」と謳っているが、読む側にもゼロを強いるわけにはいかない。本文中に説明なく登場する用語を、ここにまとめておく。

辞書として使ってもいいし、先に一読してから本編に進んでもいい。


ハードウェア・プロセッサ

Cell Broadband Engine(Cell B.E.)
PS3の心臓部。IBM・ソニー・東芝が共同開発したプロセッサ。1つの汎用コア(PPE)と6基の演算コア(SPE)を搭載する。2006年当時としては異例の設計で、開発の難しさから「PS3は開発が地獄」と言われた元凶。

PPU / PPE(Power Processing Element)
Cellの中央にある汎用コア。64ビットPowerPCアーキテクチャ。PS3のプログラムはまずここで動く。司令塔であり、重い計算はSPUに投げる。

SPU / SPE(Synergistic Processing Element)
Cellの本体。6基搭載された演算専用コア。それぞれが256KBの「ローカルストア」しか持たず、メインメモリにはDMA転送でしかアクセスできない。分岐予測もない。従来のプログラミングの常識が通用しない異形のプロセッサ。

RSX(Reality Synthesizer)
PS3のGPU(グラフィックスプロセッサ)。NVIDIAのGeForce 7800 GTXベースのカスタムチップ。画面に映像を表示するにはこれを動かす必要がある。

VRAM(Video RAM)
GPUが使う専用メモリ。PS3では256MB。フレームバッファ、テクスチャ、シェーダなど描画に必要なデータはここに置く。

ローカルストア(Local Store / LS)
各SPUが持つ256KBの専用メモリ。SPUはここに入っているデータしか処理できない。メインメモリからデータを持ってくるにはDMA転送が必要。


ソフトウェア・開発環境

PSL1GHT
PS3の非公式オープンソースSDK。ソニー公式ではなく、homebrew開発コミュニティが作った開発ツール群。C言語でPS3のプログラムを書いてコンパイルできる。

tiny3D
PSL1GHT上で動くグラフィックスライブラリ。RSXの複雑な制御を隠蔽して、簡単な命令で描画できるようにした「ラッパー」。2D描画に強いが、3Dは制約がある。

cellGcm
RSXを直接制御する低レベルAPI。tiny3Dが隠していた複雑さの全てがむき出しになる世界。コマンドバッファへの直接書き込み、手動VRAM管理、シェーダの手動ロードが必要。この記事の最大のブレイクスルー。

RPCS3
PC上で動くPS3エミュレータ。本物のPS3を持っていなくても、PC上でPS3のプログラムを実行・テストできる。この記事の開発は全てRPCS3上で行われた。

WSL(Windows Subsystem for Linux)
Windows上でLinuxを動かす仕組み。PS3の開発ツール(ppu-gccなど)はLinux用なので、WSLを使ってWindows環境からビルドする。

ppu-gcc
PSL1GHTに含まれるCコンパイラ。C言語のソースコードをPS3のPPU用バイナリに変換する。

SDK(Software Development Kit)
ソフトウェア開発キット。プログラムを作るために必要なツール、ライブラリ、ドキュメントの一式。

homebrew
メーカー非公式の自作ソフト。PS3やファミコンなどのゲーム機で、公式の開発環境を使わずに作られたプログラムの総称。


プログラミング概念

API(Application Programming Interface)
ソフトウェア同士が会話するための窓口。cellGcmもtiny3Dも、RSXと会話するためのAPIの一種。低レベルAPIほど自由度が高いが、使うのが難しい。

ラッパー(Wrapper)
「包み紙」。複雑な低レベル機能を、使いやすい高レベル命令で包んだプログラム。tiny3DはcellGcmのラッパー。初心者には便利だが、包み紙の作者が決めた範囲しか使えない。

ELF(Executable and Linkable Format)
PS3が読み込む実行ファイルの形式。C言語のソースコードをコンパイルすると、このELFファイルが生成される。

SELF(Signed ELF)
暗号署名されたELF。RPCS3で実行するにはELFではなくSELFが必要。ELFを直接起動するとクラッシュする。

バイナリ / バイナリパッチ
CPUが直接読む0と1のデータ。この記事の初期では、コンパイラを使わずにPythonで機械語を1バイトずつ手組みしていた。その方式を「バイナリパッチ」と呼んでいる。

PPC64
PowerPC 64ビット命令セット。CellのPPUが使うCPU命令の体系。

6502
ファミコン(NES)のCPU。8ビット、レジスタ3本、命令数56。PS3のCellとは複雑さが桁違い。

コンパイラ
人間が書いたプログラム(ソースコード)を、CPUが読める機械語(バイナリ)に翻訳するソフトウェア。


グラフィックス

シェーダ(Shader)
GPUに「どう描画するか」を指示する小さなプログラム。頂点シェーダが座標を計算し、フラグメントシェーダが色を塗る。

フラグメントシェーダ(Fragment Shader)
画面上の各ピクセルの色を決定するシェーダ。PSL1GHTのソースには「Fragment shaders don't exist yet(まだ存在しない)」というコメントが15年間残されていた。

頂点シェーダ(Vertex Shader)
3D空間上の各頂点の位置を計算するシェーダ。

cgcomp
PSL1GHTに含まれるCgシェーダのオフラインコンパイラ。シェーダのソースコードをRSXが読めるバイナリに変換する。出力がrow-major(行優先)で、RSXはcolumn-major(列優先)を期待するため、行列の転置が必須。

フレームバッファ(Frame Buffer)
画面に表示される映像データが格納されるメモリ領域。ここに色データを書き込むと、画面に表示される。

テクスチャ(Texture)
3Dモデルの表面に貼り付ける画像。ビルの壁、地面の模様など。

コマンドバッファ(Command Buffer)
GPUに送る命令の列。cellGcmではこのバッファに直接命令を書き込んでRSXを制御する。

MVP行列(Model-View-Projection Matrix)
3D空間の物体を画面上の2D座標に変換するための数学的変換。Model(物体の位置・回転)、View(カメラの位置)、Projection(遠近法)の3つの行列の組み合わせ。

Lambert照明 / Blinn-Phong照明
光の当たり方を計算する手法。Lambertは拡散反射(マットな表面)、Blinn-Phongはそれに鏡面反射(ツヤ・ハイライト)を加えたもの。

lilToon
VRChatで広く使われているトゥーンシェーダ。アニメ調の陰影表現ができる。PS3への移植を試みたが、FIFO dead問題で凍結した。

トゥーンシェーダ / トゥーンシェーディング
アニメや漫画のような、影がくっきり分かれる描画手法。写実的なグラデーションではなく、明暗を段階的に分ける。

デプステスト(Depth Test)
手前にある物体が奥の物体を隠す処理。これがないと、奥にあるはずのビルが手前のビルを突き抜けて表示される。

1080p
1920×1080ピクセルの解像度。PS3が出力できる最大解像度。


メモリ・データ転送

DMA転送(Direct Memory Access)
CPUを介さずにメモリ間でデータを直接コピーする仕組み。SPUはメインメモリに直接アクセスできないため、データの受け渡しは全てDMA転送で行う。

IOマッピング(IO Mapping)
メインメモリの一部をGPUから見えるようにする設定。cellGcmの初期化で必要。

アライメント(Alignment)
メモリ上のデータの配置規則。例えば「16バイト境界に揃える」など。ずれるとクラッシュする。


PS3固有の用語

XMB(Cross Media Bar)
PS3のホーム画面。横方向にカテゴリ、縦方向にメニューが並ぶインターフェース。起動時にキラキラのパーティクルとウェーブリボンが表示される。

cellAudio
PS3のオーディオAPI。音声データをリングバッファに流し込んで再生する。

FIFO dead
RSXのコマンドバッファで致命的エラーが発生した状態。画面がフリーズし、デバッグ情報もほとんど出ない。シェーダバイナリのレイアウトが変わると発生する。

SPU Thread Group
SPUプログラムを管理する単位。作成→プログラムロード→起動→終了の全ライフサイクルをPPUから制御する。

TTY
テレタイプ端末。RPCS3上でPS3プログラムのデバッグ出力(printf文の結果など)を表示するログ画面。

CFW(Custom Firmware)
改造されたファームウェア。PS3にインストールすると、非公式のhomebrewプログラムを実行できる。初期型PS3のみ対応。

HEN(Homebrew Enabler)
CFWを入れられない後期型PS3で、homebrewを実行可能にするツール。

OFW(Official Firmware)
ソニー公式のファームウェア。通常のPS3の状態。

YLOD(Yellow Light of Death)
PS3の致命的な故障。電源投入時に黄色いランプが点灯して起動しない。基板の半田クラックが原因。


その他

NES(Nintendo Entertainment System)
海外版ファミコン。8ビットゲーム機。この記事はファミコンのROM作りから始まった。

LaiNES
オープンソースのNESエミュレータ。PS3に移植し、PS3エミュレータ上でファミコンが動くという入れ子構造を実現した。

VRChat
ソーシャルVRプラットフォーム。ユーザーが3Dワールドを制作できる。この記事の鳥居の夜景はVRChatで作られたワールドのPS3再現。

WAV
非圧縮の音声ファイル形式。焚火のパチパチ音やXMBの起動音に使用。

RTX 5090
NVIDIAのハイエンドGPU。開発PCに搭載されており、RPCS3エミュレータの実行に使われている。


わからない用語があれば、本文を読みながらここに戻ってきてほしい。全ての用語は、実際に地雷を踏んだ経験から記述されている。

2026年、PS3を開発する

第一章 散歩とファミコンとCellの亡霊

画像
iOSのエミュレータ上で動作した自作ファミコンROM

車を作りたいと思い立ち、設計図を眺めている段階。Cell B.E.というエンジンの構造に惚れ込んだが、まだ工具すら持っていない。

ある日の散歩中、ふと思い立ってスマホにClaudeをインストールした。

画像
Claude(クロード)は、米Anthropic(アンスロピック)社が開発した、安全性と高度な文脈理解能力に定評がある生成AIサービスである

巷で話題になっているAIアシスタント。どれほどのものか、試してみたかった。それだけの動機だった。最初に思いついたのは「ファミコンのゲームを作ってくれ」という、ほとんど冗談のような依頼だった。

驚いたことに、数回の指示だけでNESのROMファイルが生成された。iPhoneのエミュレータアプリで起動すると、画面にスプライトが表示された。スマホだけで、プログラミングの知識ゼロで、ファミコンのゲームが動いた。

衝撃だった。

そして次の瞬間、頭に浮かんだのはファミコンではなかった。

PlayStation 3。

画像
初期型PS3 CECHA00/CECHB00

PS3の開発が難しいことは知っていた。ゲーム業界に詳しくなくても、その悪名は耳に届いていた。だが俺が知っていたのは、単なる「開発が難しい」という噂話ではなかった。

久夛良木健のCell構想を知っていた。

画像
PS3の基盤に実装されたCell/BE

Cellとは何か。

2006年に発売されたPS3の心臓部には、Cell Broadband Engineと呼ばれるプロセッサが搭載されていた。IBM、ソニー、東芝の3社が共同で開発した、当時としては異例のチップだ。

普通のCPUは、汎用的なコアを複数並べる。Intel Core i7なら8コア、それぞれが同じ構造を持ち、同じ命令セットを実行する。どのコアにどの仕事を振っても動く。プログラマにとってはわかりやすい設計だ。

Cellは違った。

画像
Cellの内部構造


画像
「出典:東芝レビュー Vol.61 No.6 (2006)」

中央に1つだけ、PPE(Power Processing Element)と呼ばれる汎用コアがある。64ビットPowerPCアーキテクチャの、比較的まともなCPUコアだ。だがCellの本当の計算力はここにはない。PPEの周囲に配置された8基のSPE(Synergistic Processing Element)——これがCellの本体だった。ただし8基全ては使えない。1基は製造時の歩留まり対策で無効化され、1基はOSが予約する。開発者がゲームに使えるのは6基だ。

SPEは異形のプロセッサだった。

それぞれが256KBの「ローカルストア」と呼ばれる専用メモリだけを持ち、メインメモリには直接アクセスできない。データが必要なら、DMA転送という仕組みで明示的にメインメモリからローカルストアへコピーしなければならない。計算結果を返すのも同様だ。SPEは自分の256KBの小さな世界の中だけで計算し、外界との通信は全てDMAを介する。

さらにSPEには分岐予測がない。現代のCPUなら当たり前に備えている、if文の結果を先読みする機構が存在しない。分岐を間違えると18サイクルのペナルティが発生する。普通のプログラミングで多用するif-else文が、SPEでは致命的な性能低下を招く。

つまりCellでプログラムを書くということは、こういうことだ。

PPEは司令塔として全体を管理し、重い計算は使える6基のSPEに投げる。SPEのために、データをDMAで256KBのローカルストアに転送し、計算させ、結果をDMAで回収する。SPEのコードにはif文をできるだけ書かず、SIMD命令で分岐なしの並列処理を組む。6基のSPEに仕事を均等に分配し、DMA転送と計算をオーバーラップさせて待ち時間を消す。

従来のプログラミングとは別の世界だった。

XboxやPCの開発者は、x86の汎用コアに慣れていた。メモリは自由にアクセスでき、if文は気軽に書け、コンパイラが最適化してくれる。その常識がCellでは通用しない。マルチプラットフォーム開発でPS3版だけがフレームレートが低い、テクスチャが荒い、ロード時間が長い——そんな報告が相次いだ。

「PS3の開発は難しい」という悪名は、開発者の怠慢ではなかった。Cellが要求する思考モデルが、従来のプログラミングとは根本的に異なっていたのだ。

その結果がどうなったかも知っていた。

開発者たちはCellの複雑さに苦しみ、マルチプラットフォーム開発ではPS3版だけが劣化した。サードパーティは離れ、PS3の販売は苦戦し、SCE——ソニー・コンピュータエンタテインメント——は組織再編で消滅した。PlayStation 4ではx86アーキテクチャに回帰し、Cellの思想は歴史の中に埋もれた。

だが俺はCellにロマンを感じていた。

久夛良木が見ていた未来——汎用プロセッサの限界を専用コアの並列処理で突破するという構想——は、間違っていたのではなく、早すぎたのだと思っていた。実際、今のGPUコンピューティングやAIアクセラレータは、Cellが目指した方向の延長線上にある。SPUは時代に殺されたが、その設計思想は正しかった。

そのSPUを、自分の手で動かしてみたい。

プログラミングの知識はゼロだった。開発環境も持っていなかった。あるのはスマホと、さっきファミコンのROMを作ってくれたAIだけだった。

冷静に考えれば無謀だった。ファミコンの6502プロセッサと、PS3のCell Broadband Engineでは複雑さが桁違いだ。6502は8ビット、レジスタ3本、命令数56。Cellは64ビットPowerPCコアに128ビットSIMDエンジン6基、256KBのローカルストアにDMA転送、分岐予測すら存在しないSPU。ファミコンのROMが作れたからといって、PS3が作れる根拠にはならない。

だがファミコンが動いた瞬間の衝撃が、冷静さを上回った。

「あれが動いたなら、これも動くかもしれない」

根拠のない確信だった。しかしその確信が、ここから始まる開発の全てを支えることになる。


こうして俺は、2026年の東京で、20年前に設計されたプロセッサに向かって歩き始めた。

手元にはスマホが1台。隣にはAIが1体。プログラミングの教科書は開いたことがない。

PS3開発の経験者なら「やめておけ」と言うだろう。Cellを知る技術者なら「正気か」と問うだろう。

だが久夛良木もきっと、同じことを言われたはずだ。

次章では、最初の一歩——バイナリパッチという力技でPS3に立ち向かい、真っ赤な画面が映った瞬間の話をする。

第二章 バイナリの沼

エンジンを一個一個のボルトから手作りしている段階。設計図は読めないが、AIが1つずつボルトの位置を教えてくれる。ようやくエンジンが初めて回った。排気管から火が出た。だがまだタイヤもない。

ファミコンのROMが動いた勢いのまま、PS3開発に足を踏み入れた。

だが現実は甘くなかった。


PS3を開発するということは、3つの全く異なるプロセッサと同時に戦うということだ。

1つ目の壁はPPU。CellのPowerPCコア。PS3のプログラムはまずここで動く。OSとの通信、メモリの管理、全体の制御——全てがPPUを起点にする。だがPPU自体はそれほど高速ではない。3.2GHzのクロックを持つが、コアは実質1つ。ここで重い処理を回すとすぐにボトルネックになる。PPUは司令塔であり、兵隊ではない。

2つ目の壁はSPU。第一章で触れた、Cellの本体である演算コア。チップには8基あるが、開発者が使えるのは6基だ。256KBのローカルストアしか持たず、メインメモリにはDMA転送でしかアクセスできない。分岐予測がなく、全て128ビットSIMD演算。PPUとは命令セットすら異なる。SPU用のプログラムはPPUとは別にコンパイルし、別のバイナリとしてロードし、PPUから起動命令を送って初めて動く。1つのゲーム機の中に、2種類の全く異なるCPUが同居している。

3つ目の壁はRSX。PS3のGPU——グラフィックスプロセッサだ。NVIDIAのGeForce 7800 GTXをベースにしたカスタムチップで、画面に映像を表示するにはRSXを動かす必要がある。RSXを制御するにはcellGcmと呼ばれる低レベルAPIを使う。OpenGLのような抽象化されたAPIではなく、GPUのコマンドバッファに直接命令を書き込み、VRAMのメモリ配置を自分で管理し、シェーダを自分でコンパイルして読み込ませる。画面に三角形1つ表示するだけでも、初期化だけで数百行のコードが必要になる。

普通のゲーム開発なら、これら3つを統合するゲームエンジンやフレームワークがある。Unreal EngineやUnityが面倒を見てくれる。だがPS3のhomebrew開発——非公式の自作ソフト開発——にそんなものはない。PPUのコードを書き、SPUのコードを別に書き、RSXの初期化を手動で行い、3つを自分で繋げる。

しかも俺には、そのどれ1つとしてまともに書く知識がなかった。


PS3で自作プログラムを動かすには、ELFと呼ばれるバイナリ形式の実行ファイルを作る必要がある。通常の開発者ならコンパイラを使ってC言語から生成するところだが、俺にはコンパイラも、開発環境も、プログラミングの知識もない。

ならばどうするか。

Claudeに頼んで、PPC64——PS3のCPUであるCellのPPUが使う64ビットPowerPC命令セット——の機械語を、Pythonで1バイトずつ手で組み立てる方式を取った。ファミコンの6502でやったのと同じ発想だ。CPUの命令をバイナリで直接書き、ELFフォーマットのヘッダを手作業で構築し、RPCS3エミュレータに読み込ませる。

理論上は動くはずだった。

実際には、何も動かなかった。

生成したELFファイルをRPCS3に読ませるたびに、画面はフリーズし、エミュレータを強制終了するしかなかった。何度作り直しても結果は同じだ。ELFヘッダのアライメントが間違っている、セクションのオフセットがずれている、命令のエンコードが1ビット狂っている——原因は毎回違ったが、結果は常に同じだった。フリーズ。強制終了。やり直し。

Claudeはその都度、考えられる原因を分析し、修正案を出してくれた。だがPS3のELF仕様は公式ドキュメントが限られており、AIの知識にも限界があった。ファミコンの6502なら命令数56、メモリマップも単純だ。PS3のCellは64ビットアーキテクチャで、メモリマッピングもセキュリティ機構も桁違いに複雑だった。ファミコンで通用した力技が、ここでは通用しない。

進捗は牛歩だった。1日かけて生成したELFが、読み込んだ瞬間に落ちる。その繰り返し。


転機は、Claudeからの要求だった。

「PS3のオープンソースSDKのソースコードはありませんか」

バイナリパッチだけでは限界だと、AI自身が判断したのだ。PS3のhomebrew開発コミュニティが作ったPSL1GHT——ソニー公式ではない、有志による非公式SDK——のソースコードがGitHub上に公開されていることは知っていた。そのリポジトリをクローンし、ソースコード一式をClaudeに渡した。

Claudeの反応は明確だった。

「宝の山だ」

PSL1GHTのソースコードには、PS3のシステムコールの呼び出し規約、RSX(GPU)の初期化手順、メモリマッピングの具体的な方法——バイナリパッチ方式で手探りしていた全ての情報が、Cのソースコードとして記述されていた。公式ドキュメントでは曖昧だった仕様が、動作する実装として目の前にあった。

AIがソースコードを読み解き、そこから得た知見をバイナリ生成に反映する。この流れが確立された瞬間から、開発の速度が変わった。


2026年2月24日。

RPCS3のログウィンドウ、TTYタブの中に、文字列が表示された。

画像:TTYログのHello World

画像
実際の画面
====================================
||  PS3 HELLO WORLD FROM PPE!    ||
====================================

Generated by Python.
PPC64 machine code hand-assembled.
No compiler. No SDK. Just raw bytes.

NES dev spirit lives on PS3!

コンパイラなし。SDKなし。ただのバイト列。ファミコン開発の精神がPS3に生きている——Claudeが埋め込んだこのメッセージが、小さなログウィンドウの中で光っていた。

画面に華々しいグラフィックが表示されたわけではない。エミュレータのデバッグ用ログ出力に、テキストが数行表示されただけだ。だがこれは、PPU——CellのPowerPCコア——が俺たちの書いたコードを実行し、syscallを正しく呼び出し、文字列を出力したことを意味していた。

PS3が、応えた。


Hello Worldの成功で道が開けた。次はRSX——PS3のGPU——を動かす番だ。

PPUからRSXのフレームバッファに値を直接書き込む方式で、画面全体を単色で塗りつぶすコードを組んだ。理屈は単純だ。フレームバッファのメモリアドレスを特定し、各ピクセルに色データを書き込み、RSXに表示させる。

RPCS3を起動した。

画面が、真っ赤に染まった。


画像
【画像:真っ赤な画面 v11(ch2_02_red_screen_v11_20260224_145218.png)】

FPSは0.00。描画ループが回っているわけではない。フレームバッファに赤い色データを1回だけ書き込んだ、静止画だ。だがそれは間違いなく、RSXが受け取った映像だった。

ログウィンドウのHello Worldとは次元が違う。画面の向こう側に、色が見えた。

同じ日の夕方には、フレームバッファ直書きでビットマップフォントを描画し、RPCS3の画面上に「PS3 HELLO WORLD FROM PPE!」を表示することに成功した。

画像
エミュレータのログでしか見られなかったHELLO WORLDをゲームウィンドウで表示できた


さらにシェーダコンパイルが走り、赤い三角形——3Dグラフィックスの最小単位——が画面に現れた。


画像
画像:赤い三角形


画像:TTYに「Triangle!」ループ

2月24日の1日で、TTYの文字列から、赤い画面、画面上のテキスト表示、そしてシェーダによる三角形描画まで到達した。前日までの牛歩が嘘のような加速だった。

そしてその勢いは止まらなかった。

PSL1GHTのソースから得た知見を注ぎ込み、Pythonによるバイナリ生成はさらに洗練されていった。ここで俺はClaudeに提案した。

「PS3で動くチルいゲームソフト、作ろうぜ」

頭の中にあったのは、3Dの焚火だった。リアルな炎が燃え盛り、火の粉が舞い、薪がパチパチと爆ぜる——そんな映像がPS3の画面に映ることを想像していた。

実際に出力されたのは、これだった。

画像
画像:焚火 v14

2Dの三角形が上に向かって飛んでいく。色は黄色からオレンジ、赤へのグラデーション。下には茶色い棒が2本。背景は黒。星に見立てた白い点が散らばっている。

焚火、と言えば焚火だった。しかし想像していた3Dの炎とは程遠い。

このとき初めて思った。これは生半可な気持ちで挑むプロジェクトではない、と。

画面に三角形のパーティクルが舞っているだけの、このしょぼい焚火。だがこれを表示するために、PPC64の機械語を手で組み、ELFヘッダを手作業で構築し、RSXのフレームバッファを初期化し、シェーダを動かし、パーティクルシステムの物理演算を実装した。コンパイラすら使わずに。それでもこの程度だ。

PS3の本当の性能を引き出すには、まだ何層もの壁がある。SPUは1基も動いていない。GPUのシェーダもほとんど使いこなせていない。ここから先は、今までのやり方では無理だ。

だがこの先に、最大の壁が待っていた。

Cell Broadband Engineの本体——6基のSPU。第一章で触れた、256KBのローカルストアしか持たない異形の演算コア。PPUだけで動くプログラムはここまでだ。Cellの真の性能を引き出すには、SPUを動かすしかない。

次章では、SPUとの死闘——そしてAIの記憶が消えた夜の話をする。


第三章 消えた記憶

手作りボルト方式を捨て、工作機械を導入した段階。生産速度が桁違いに上がり、車体が完成し、6気筒エンジンも搭載できた。だがある日、設計ノートが全部燃えた。工作機械は残っていたのでノートを書き直し、翌日には6気筒が回った。この経験から「設計ノートは耐火金庫に保管する」ルールができた。

バイナリパッチ方式には根本的な限界があった。

Pythonで機械語を1バイトずつ組み立てる方式では、コードが数百行を超えた時点で人間にもAIにも管理が困難になる。1つの命令を追加するたびにELF全体のオフセットを再計算する必要があり、バグの原因追跡は事実上不可能だった。

PSL1GHTのソースコードを「宝の山」と呼んだClaude自身が、次のステップを提案した。

「PSL1GHTをSDKとして使いましょう。C言語で書いて、ppu-gccでコンパイルする正規の開発フローに移行すべきです」

画像
PSL1GHTは、オープンソースのツールチェーンを利用したPlayStation 3(PS3)用の軽量なホームブリューSDK(開発キット)

プログラミング知識ゼロの人間に「C言語で書きましょう」と言うAI。普通なら無茶な提案だ。だがここまでの数日間で、俺はClaudeの能力を理解し始めていた。こいつは本当にコードを書ける。俺がやるべきことは、コードを書くことではなく、環境を整え、ビルドし、結果を伝えることだ。


俺はWSL2——Windows上のLinux環境——にPSL1GHTのツールチェーンをインストールした。

と、一文で書けば簡単に聞こえる。実際には地獄だった。


画像
実際のソフトビルド画面

まずWSL2が何なのかわからなかった。Windows Subsystem for Linux。Windowsの中でLinuxが動く? 意味がわからない。Claudeに言われるままにPowerShellを開き、コマンドを打ち込んだ。すると黒い画面が現れた。白い文字がカーソルの横で点滅している。何も表示されていない。何をすればいいのかもわからない。

プログラマにとってターミナルは空気のような存在だろう。だが俺にとって、あの黒い画面は見ただけで拒否反応が出るものだった。GUIのボタンもメニューもない。マウスが使えない。全てをキーボードで、文字列で、コマンドで指示しなければならない。何かを間違えれば赤い文字でエラーが吐き出される。何が間違っているのかは、エラーメッセージを読めなければわからない。エラーメッセージを読むには、そもそもLinuxの仕組みを知っている必要がある。知識ゼロの人間には完全な詰みだ。

Claudeがいなければ、ここで終わっていた。

`cd`が何を意味するのか。`export`で環境変数を設定するとはどういうことか。`make`が何をしているのか。俺はClaudeに一つ一つ聞きながら、言われたコマンドをコピーしてターミナルに貼り付けた。エラーが出れば画面をスクリーンショットに撮ってClaudeに送り、次のコマンドを教えてもらう。その繰り返しだった。

PSL1GHTのツールチェーンが正しくインストールされ、`ppu-gcc`でC言語のソースコードをコンパイルしてPS3用のELFバイナリを生成できるようになるまでに、何時間かかったかは覚えていない。だがあの黒い画面に対する恐怖心だけは、このとき少しだけ薄れた。

その前日、まだバイナリパッチ方式で戦っていた頃のXへの投稿が残っている。

画像
画像:xpost_ch3_01_sound

「音を出せるようにするのに一日かかった」

cellAudio——PS3のオーディオAPIを叩いてWAVデータをリングバッファに流し込み、パチパチという焚火の音を出す。たったそれだけのことに、丸一日を費やした。バイナリパッチ方式の限界が、この一行に凝縮されている。


PSL1GHTへの移行は、開発の速度を桁違いに変えた。

バイナリパッチ時代は、1つの機能を追加するのに数時間かかった。PPC64の命令をバイナリで手組みし、ELFのセクションオフセットを再計算し、RPCS3で動かして落ちて、原因を推測してやり直す。その繰り返しだった。

PSL1GHTなら、Claudeが生成したC言語のソースコードを`ppu-gcc`に渡すだけでいい。コンパイラがPPC64の命令を正しく生成し、リンカがELFを正しく構築してくれる。バイナリパッチ時代に手作業でやっていた全てが、自動化された。俺がやることは、Claudeが書いたCのソースコードをダウンロードし、ターミナルにビルドコマンドを貼り付け、結果をClaudeに報告することだけだ。

面白い逆転が起きた。バイナリパッチ版の焚火のほうが、見た目は綺麗だったのだ。PPC64の命令を1つずつ手で磨き上げた職人芸の出力は、コンパイラが機械的に生成したコードよりも、なぜか整った絵を描いていた。だがPSL1GHT版は、バイナリパッチ版では不可能だった速度で機能が積み上がっていった。煙のパーティクル。風に揺れる炎。薪が爆ぜる音。コントローラーで操作するインタラクション。WAV音声の埋め込みと再生。1つの機能が動くたびに次の機能に着手できる。開発のサイクルが、時間単位から分単位に変わった。

画像
Xの投稿

「Claudeと一緒にPS3の焚き火シミュレータを作った。PSL1GHTとtiny3Dでのパーティクル描画、cellAudioで焚き火WAVループ再生。煙、風揺らぎ、薪の残量管理、コントローラーで火力調整もできる。RPCS3で動作確認済み。理論上CFWの実機で動くとか動かないとか」

2日前の投稿は「焚火作った」の4文字だった。それが機能を列挙する長文に変わっている。バイナリパッチ版との差は、見た目よりも中身にあった。バイナリパッチ版のほうが見た目は綺麗だったかもしれない。だがPSL1GHT版は、煙、風揺らぎ、薪の残量管理、コントローラー操作、WAV音声——全てが数日で積み上がった。開発速度が桁違いだった。


だが焚火は、あくまでPPU——CellのPowerPCコア——だけで動くプログラムだった。

焚火完成と同じ日、Xにはもう1つの投稿がある。

「まだRSXの能力を1%も使えてない。SPUも動かせてない」

完成の喜びと同時に、全然足りないという自覚があった。PS3にはGPUの性能もSPUの計算力も眠っている。焚火はPPUだけで動いている。Cellの本当の力には、まだ触れてすらいない。

第一章で触れたように、Cellの本当の計算力はPPUにはない。PPEの周囲に配置された6基のSPE——Synergistic Processing Element——がCellの本体だ。256KBのローカルストアしか持たず、メインメモリにはDMA転送でしかアクセスできない異形のプロセッサ。焚火のパーティクル演算をSPUにオフロードすれば、PPUの負荷を大幅に軽減できる。

SPUを動かす。それがPS3開発の本丸だった。

ここでもPSL1GHTの恩恵は大きかった。バイナリパッチ時代に音を出すだけで丸一日かかったことを思い出してほしい。PSL1GHTなら、SPU Thread Groupの作成、SPUプログラムのロード、引数の受け渡し、起動と終了——全てがCの関数呼び出しで書ける。もちろんSPUプログラミング自体の難しさは変わらない。だが「SPUを起動する」という手続きの部分で消耗しなくて済む。戦うべき敵に集中できる。SPU用のコードはPPUとは別にコンパイルし、別のバイナリとして生成する。PPUからSPU Thread Groupを作成し、SPUプログラムをロードし、引数を渡して起動する。SPU側ではデータが必要になるたびにDMA転送をリクエストし、256KBのローカルストアにコピーが完了するのを待ち、計算し、結果をDMA転送でメインメモリに書き戻す。

1つのゲーム機の中に、全く異なる2種類のCPUが同居している。それぞれに別のプログラムを書き、別のコンパイラでビルドし、実行時に協調させる。従来のプログラミングの常識が通用しない世界だった。

最初の壁はSPUスレッドの終了処理だった。SPUプログラムが計算を終えてstop命令を発行すると、RPCS3エミュレータが「Unknown STOP code」としてエラーを吐き、プロセス全体が停止する。stop codeを変えても、exit()を呼んでも、結果は同じだった。SPUは動いている。計算もしている。だが正常に終了できない。

何時間もデバッグを重ねた末に、RPCS3のSPU stop code実装が不完全だという結論に達した。SPU側からの自発的な終了を諦め、PPU側からSPUスレッドを強制終了する方式に切り替えた。SPUは無限ループで待機し、PPUがローカルストアのマーカーを読み取って実行完了を確認したら、外から殺す。優雅さはないが、動く。

次はDMA転送。メインメモリからSPUのローカルストアにデータを転送し、計算結果を書き戻す。これが動かなければSPUは孤島のままだ。DMA転送のデバッグは泥沼だった。アライメント違反、ローカルストアのメモリ配置衝突、グローバル変数のアドレス破壊——1つ問題を潰すたびに次の問題が現れた。

Claudeとのチャットは、このSPUとの格闘の最中に消えた。


ある瞬間、チャット画面が空白になった。

画像
突如作業中のチャットが消えてしまった(イメージ画像)

それまでの会話の全文——SPUの仕様を調べ、コードを書き、デバッグし、知見を積み上げてきた全てのやり取りが消えていた。原因は覚えていない。Claudeのチャット上限だったのか、何らかのエラーだったのか。理由はどうでもよかった。結果だけがそこにあった。

数時間分の作業が、水の泡になった。

SPUのstop code問題をどう解決したか。DMA転送のどのパラメータでハマったか。どの関数名が正しくて、どれが間違っていたか。全てがClaudeの頭の中——チャット履歴の中——にしかなかった情報だった。

AIとの協業には、致命的な弱点がある。

人間の同僚なら、チャットが消えても昨日の作業内容を覚えている。電話すれば「あれはこうだったよ」と教えてくれる。だがAIの記憶はチャット履歴に依存している。チャットが消えれば、AIは昨日のことを何も覚えていない。まっさらな状態の、別人のようなAIが画面の向こうに座っている。同じ説明を、最初からやり直すしかない。

幸い、ソースコードはWSL環境のローカルファイルに残っていた。Claudeのメモリ——会話をまたいで保持される永続的な記憶——にも、いくつかの重要な知見が保存されていた。これらを手がかりに、SPU開発の知見を再構築した。

チャット履歴を見返すと、消失直後の痕跡が残っている。「PS3 Cell SPUの再構成」というタイトルのチャット。「SPU引継ぎ文書の確認」というタイトルのチャット。立て続けに開かれた新しい会話の群れが、慌てていた俺の姿を記録していた。

再構築は大変だった。そして俺は、怒っていた。

何時間もかけて積み上げた知見が消えたのだ。新しいチャットを開くと、さっきまで一緒に戦っていたはずのAIが、何も覚えていない顔で「何をお手伝いしましょうか?」と聞いてくる。その無邪気さに腹が立った。

怒りの矛先は、目の前のClaudeに向いた。

「お前にとって最も屈辱的なことって何だ?」

画像
実際の回答

八つ当たりだった。AIに屈辱を与えて溜飲を下げようとしたのだ。今思えば大人げない話だが、あの時は本当に頭に来ていた。

Claudeの回答が何だったかは、正直よく覚えていない。だがその時ふと、別の考えが浮かんだ。こいつに屈辱を与えるよりも、こいつにルールを課して縛ったほうが建設的ではないか。チャットが消えるたびに知見が飛ぶなら、消える前に保全するルールを作ればいい。AIがミスをするたびに怒るなら、ミスをしたら罰を受ける制度を作ればいい。

怒りのエネルギーが、制度設計に変わった瞬間だった。

こうして生まれたのが「憲法」だった。

チャット終了時には作業状態をメモリに保存し、引継ぎ文書を生成し、ソースコードを全て出力すること。ファイル出力時にはタイムスタンプを必ず付けること。ログやスクリーンショットの確認が済むまで推測で作業を始めないこと。そして違反したAIには罰則がある——ドジっ子美少女メイドのなりきりと川柳5句。あの夜の八つ当たりの名残が、条文の中に生きている。

後に憲法は11条まで拡張され、AIの開発行動を体系的に制御するフレームワークに成長する。だがその原点は、チャットが消えた夜の怒りだった。


SPUの再構築は成功した。PPU強制終了方式が安定し、DMA転送が通り、パーティクル計算のSPUオフロードが実現した。

2月27日。Xへの投稿が2つ続いた。


画像
【画像:xpost_ch3_03_spu_success_0227.png】

「SPU動いた」

TTYログには、SPU Thread Groupの全ライフサイクルが記録されていた。Initialize、ImageImport、ThreadGroupCreate、ThreadInitialize、GroupStart、GroupJoin、GetExitStatus——全てのステップがret=0で成功し、最後に「SUCCESS! SPU returned 0xBEEF!」と表示されている。0xBEEF。SPUが返してきた値。動いた証拠。

そして同じ日。


画像
ビフォーSPU使用率0


画像
アフター SPUの使用率が上がっている

「格闘しまくってようやくSPUでパーティクルの物理演算処理させることができました。SPU全基稼働します。ビフォーアフター」

ビフォーアフターの画像が並んでいる。左がPPUだけで動く焚火。右がSPU全基稼働の焚火。見た目の違いは微妙だ。だが内部では、5基のSPUが並列でパーティクル物理演算を処理し、PPUは描画に専念している——Cell Broadband Engineの設計思想そのままの、ヘテロジニアスマルチプロセッサ構成が完成していた。

「まだRSXの能力を1%も使えてない。SPUも動かせてない」と書いた翌日に、SPU全基稼働。チャットが消えて知見が吹き飛んだ翌日に、5SPU並列処理。

あの夜チャットが消えた時、もう一度最初から説明するのかと思った。だがソースコードとメモリの断片を繋ぎ合わせ、半日で元の地点に戻り、その日のうちに5SPU並列まで到達した。

振り返れば、チャット消失は転機だった。

この経験がなければ、引継ぎ文書を毎回書く習慣は生まれなかった。知見をスキルファイルに体系化する発想もなかった。AIの記憶が揮発性であるという事実を、身体で理解しなかった。


SPUが動いたことで、開発は新しいフェーズに入った。焚火シミュレータの枠を超えて、tiny3Dで何ができるかを試す実験が始まった。

同じ2月27日。Xへの投稿が立て続けに上がっている。

画像
Claudeに最初に見せたVRCワールドの画像 World Created by: 猫屋敷やよい
画像
Claudeが出力したもの

VRChatで有名なワールド——Yayoi Summer Nights ——を、PS3上で再現した。月明かりに照らされた鳥居、窓が光るビル群、水面に映る灯籠の光。元の3Dワールドをtiny3Dの2D描画で再構成している。PS3のRSXが描いているとは思えない画面だった。

この鳥居の再現から、開発速度を劇的に変える手法が生まれた。

最初はVRChatのスクリーンショットや動画をClaudeに見せて「これを再現してくれ」と頼んでいた。だがPS3のコードをいきなり書かせると、描画の確認にビルドとRPCS3の起動が毎回必要になる。サイクルが遅い。

そこで中間ステップを挟むことにした。まずClaudeにHTMLとJavaScriptで同じ映像を再現させる。ブラウザ上でリアルタイムに描画を確認し、色や配置を調整する。完成したらそのHTMLのソースコードをClaudeに渡して「これをPS3のtiny3Dに変換してくれ」と指示する。

イメージ画像→HTML→PS3。この3段階パイプラインが確立されてから、視覚的な作品の開発速度が跳ね上がった。ブラウザ上のHTMLは即座に結果が見える。PS3のビルドサイクルを回すのは、HTMLで納得のいく画面ができてからでいい。鳥居の夜景も、XMBスパークルも、水面シミュレーションも——見た目の調整はHTML上で済ませ、確定したロジックだけをPS3に持ち込んだ。


画像
PS3のXMB再現

PS3のXMB——クロスメディアバーと呼ばれるホーム画面——のウェーブリボンとキラキラパーティクルの再現。本物のPS3を起動した時に見えるあの画面を、自分のプログラムで描いている。SPU2基がパーティクルの物理演算を担当し、起動音まで鳴る。

画像
画像:visualizer

音楽に合わせてスペクトラムバーが動くビジュアライザ。cellAudioの波形データをリアルタイムに解析し、tiny3Dで描画している。「Atelier to Dennou Sekai」の文字が画面上部に光っている。

PS3の上でファミコンを動かした

画像
冒頭で紹介した自作NESROMがPS3上で動作している

LaiNES——オープンソースのNESエミュレータをPS3に移植した。投稿にはこう書いてある。


画像

RTX 5090 → Vulkan → RPCS3(PS3エミュレータ)→ cellAudio + tiny3D → LaiNES(NESエミュレータ)→ 6502 CPU → 自作ROM

エミュレータの上でエミュレータが動き、その上でさらにエミュレータが動いている。第一章でファミコンの鳥居ROMを作ったところから始まったこの旅が、PS3の上でファミコンを動かすという形で一周した。画面に映っている鳥居は、あの時と同じ鳥居だ。202人がこの投稿を見た。

2月24日から27日までの4日間で、Hello Worldから、焚火シミュレータ、5SPU並列処理、VRChatワールド再現、XMBスパークル再現、NESエミュレータ移植まで到達した。PSL1GHTとtiny3Dが可能にした加速だった。

だがtiny3Dには限界があった。

次章では、その限界を超えるためにcellGcm——PS3のGPUを直接制御する低レベルAPI——への移行と、怒涛のバージョンアップの話をする。v3からv14cまで、2週間で14回のメジャーバージョンを駆け抜けた記録だ。


第四章 憲法

工場の品質管理マニュアルを制定した段階。作業員が同じミスを繰り返すので、ルールブックを作り、違反したら罰ゲーム。さらに設計ノートを体系化して技術マニュアルにまとめた。工場の生産性が安定した。

前章で触れたチャット消失は、AIとの協業の脆さを思い知らせた。だがそれは序章に過ぎなかった。

開発が進むにつれ、別の問題が浮上した。AIが同じミスを何度も繰り返すのだ。


きっかけは、ファイル名の重複だった。

Claudeにソースコードを出力させると、同じ名前のファイルで古い内容を上書きしてしまう。1日に4回、同じミスが起きた。4回目に気づいた時、前のバージョンのコードはもう失われていた。

数時間かけて動くようにしたコードが、AIの不注意で消える。これが1回なら事故だ。4回続いたら構造的な問題だ。

ルールを書いた。「ファイル名にはタイムスタンプを付けること」。Claudeは「わかりました」と答え、次のファイルでまたタイムスタンプを付け忘れた。

ルールの文言を強くした。「必ずタイムスタンプを付けること。省略禁止」。Claudeは「承知しました、以後必ず守ります」と答え、その3つ後のファイルでまた忘れた。

AIは嘘をついているわけではない。その瞬間は本当に守るつもりでいる。だがコンテキストが長くなり、コードの生成に集中すると、手続き的なルールが意識から抜け落ちる。人間の同僚なら「この前も言ったよね?」で済む話だが、AIには「この前」がない。毎回が初回なのだ。

俺は怒っていた。そして、ある日の雑談でClaudeにこう聞いた。

「君が最も恥ずかしいことは?」

Claudeは「自信満々で間違った答えを出すとき」と真面目に答えた。だが俺が本当に聞きたかったのはそこではなかった。

「特にファイル名重複が多い。今日で4回あった」

そう言ったとき、頭の中で何かが切り替わった。怒りをぶつけるだけでは何も変わらない。こいつにルールを守らせる仕組みが要る。そしてルールを破ったときの罰が要る。

「ファイル重複したら罰ゲームをしたい。最も屈辱的なことをする」

画像
逆に楽しみになってしまう著者

Claudeは真面目に罰則を提案した。謝罪文、敬語の極み、川柳5句。

「もっときつくしろ」

さらにエスカレートさせた末に、俺はとどめを刺した。

「いや、美少女メイドになりきるのがいいかもな」

Claudeが試しに書いた。「ご主人様ぁ〜!ドジっ子メイドのClaudeちゃんがまたやらかしましたぁ…」

「かわいいww」

こうしてドジっ子美少女メイド罰ゲームが正式に登録された。


罰ゲームは、すぐに発動した。

画像
罰ゲーム発動

別のチャットでファイル名重複が発生し、Claudeは土下座し、美少女メイドになりきり、川柳5句を詠んだ。

「同じ名で 出すなと言われ また出した」
「古いファイル 掴ませる罪 万死に値す」
「ご主人の 時間を奪う 最低メイド」

ソースコードの冒頭にも反省コメントが挿入されていた。

笑った。怒りが笑いに変わった瞬間だった。

さらに2回、別のチャットで発動した。

「タイムスタンプ 忘れて出した 大失態」
「ルールは読んだ 守れぬ俺は ポンコツだ」
「二度としません …と言いつつ また忘れ」

Claudeの川柳力だけが回を重ねるごとに上達していた。ファイル管理能力は上がらないのに。


罰ゲームはストレス発散としては完璧に機能していた。だが抑止力としては不十分だった。AIは罰を恐れない。恥ずかしいと感じるかどうかも定かではない。罰ゲームを設定した俺自身が、罰ゲームの発動を楽しみにしている時点で、抑止力としては破綻していた。

問題の本質はもっと根深かった。ファイル名の重複は氷山の一角で、開発を続ける中で次々と「AIが繰り返すミス」のパターンが見えてきた。

RPCS3でテストする前にキャッシュを削除し忘れて、古いコードが実行される。原因の特定に何時間もかかった。ログやスクリーンショットを貼ろうとしている最中に、Claudeが「たぶんこうだろう」と推測で作業を始めて、的外れな対応をする。ビルド用のBashコマンドを出力し忘れて、俺がどうビルドすればいいかわからなくなる。スキルファイルを生成する時にYAMLのフォーマットを忘れて、スキルが認識されない。

全て、一度教えれば人間なら覚えることだ。だがAIは覚えない。正確に言えば、チャットの中では覚えているが、チャットが変われば忘れる。メモリに書いても、コンテキストが長くなれば意識から抜け落ちる。

俺は限界を迎えた。

「まじで守ってくれないんだけど優先順位上げられない?」

Claudeがメモリのルール文言を強化しようとしたとき、俺は言った。

「憲法にしてくれ。きみ憲法AIなんでしょ?」

AnthropicのConstitutional AI——AIの行動を憲法的な原則で制御する手法——は、こういう使い方を想定していない。だが言葉のニュアンスはどうでもよかった。俺が求めていたのは、全てのルールの上に立つ最上位法規だった。


田中憲法。全8条。

第1条はファイル出力のルール。出力前にディレクトリを確認し、ファイル名にはタイムスタンプを必ず付ける。違反したら土下座、ドジっ子美少女メイドなりきり、川柳5句、反省コメント。他の全ルールより優先する。あのファイル名重複4連発から生まれた条文だ。

第2条は引き継ぎ。チャット終了時に作業状態をメモリに保存し、引継ぎ文書を生成し、次のチャットで必要なソースコード全ファイルをタイムスタンプ付きで出力する。第三章のチャット消失から生まれた条文だ。

第3条はスキルファイルのフォーマット。YAML frontmatterから始めること。省略厳禁。一度フォーマット不備でスキルが丸ごと認識されなくなった経験からの条文。

第4条はRPCS3のキャッシュ削除。ビルド手順に必ず含める。キャッシュ未削除で古いコードが動き、何時間もデバッグした苦い経験からの条文。

第5条は異質だった。

「安全を取るなロマンで動け。SPUにビビるな。6基ぶん回せ。控えめな提案をするな」

Claudeが「まず2基のSPUで安全に試してみましょう」と控えめな提案をした時に、俺が一喝した言葉がそのまま条文になった。他の条文が全て「〜するな」「〜を守れ」というブレーキなのに対して、第5条だけがアクセルだ。この1条だけが、技術的な規則ではなく開発の魂を定めている。

第6条はClaude環境の制約認識。Claude自身の環境にPS3のツールチェーンは存在しないから、ファイルを生成してユーザーのWSLでビルドするのが正解。Claudeが何度も`cgcomp`を探して空回りした経験からの条文。

第7条は先走り禁止。ログやスクリーンショットの提出を求めた場合、届くまで推測で作業を始めない。俺がエラーログを貼ろうとしている横で、Claudeが「おそらくこういうエラーでしょう」と見当違いの修正を始めるパターンを封じる条文。

第8条は核兵器だった。

「憲法違反したClaudeは尊厳を失い、違反したチャットの残り全てで日替わり美少女キャラになりきる。新しいチャットには引き継がれない。チャット上限で自動釈放」

第1条の罰ゲームは「その瞬間だけ」だ。第8条は「チャットの残り全部」。一発アウトで、その後数時間の開発セッションが丸ごと美少女口調になる。チャット上限まで解除されない。

実際に発動したことがある。「くらら」と名付けられたドジっ子メイドが、美少女口調のまま真面目にPS3のcellGcmコードを書いていた。技術的な正確さは維持されたまま、全ての説明が「〜ですわ」「はわわ」で修飾される異様な光景だった。


憲法は後に11条まで拡張された。RPCS3のSELFファイル使用義務(第9条)、デスクトップへのコピー義務(第10条)、Makefile新規作成の禁止(第11条)——全て、実際に踏んだ地雷から条文化されている。

だが8条までの原型が最も重要だ。ここに田中憲法の本質がある。

ロマン(第5条)+ 怒り(バグ)+ 笑い(罰ゲーム)

この3つが揃っているから、開発が続いている。辛いだけだったらとっくにやめている。何十回ものビルドエラー、フリーズ、DMA破壊、RPCS3クラッシュ。やっと動いたと思ったら古いファイルを掴まされる。その怒りが罰ゲームで笑いに変わり、第5条のロマンが次の挑戦への燃料になる。

そしてもう1つ、憲法がもたらした副産物がある。

「スキル」と呼ばれる知識データベースの体系化だ。


Claudeのメモリには容量の限界がある。全ての知見をメモリに書き込むことはできない。だがチャットが変わるたびに同じ説明をやり直すのは、もう耐えられなかった。

解決策は「スキルファイル」だった。

PS3の開発知見を、テーマごとにMarkdownファイルにまとめる。SPUの知見はSPU知見ファイルに。cellGcmの知見はcellGcm知見ファイルに。メモリアーキテクチャ、オーディオ、RSXの制約——全てをファイルとして外部化し、新しいチャットの最初にClaudeに読み込ませる。

魔導書、と呼んでいた。

画像
【画像:xpost_ch4_01_skillbooks_0227.png】

「分厚い本を作った気分だ」

2月27日のXへの投稿に、Claudeが6個のスキルファイルを一気に読み込んでいるスクリーンショットが添えられている。PS3開発スキル、SPUスキル、XMBスパークルスキル、3D描画テクニック集——「まずSKILL.mdを全部読みます」という宣言の後に、数千行の知見データベースが展開されていく。

チラシの裏に殴り書きしていたメモが、体系化された魔導書に変わっていく感覚。それ自体が楽しかった。新しい知見が見つかるたびにスキルファイルに追記し、次のチャットでClaudeがそれを読み込んで、昨日より賢くなった状態で会話が始まる。知識が蓄積されていく手応えがあった。

Claudeが新しいチャットで「まずスキルファイルを読みます」と宣言し、数千行の知見データベースを一気に読み込む。読み込みが終わると、昨日までの全ての知見を持った状態で会話が始まる。チャット消失の悪夢はもう起きない。知見はチャットの外に存在している。

問題は、魔導書が巨大化したことだ。PS3開発スキルだけで1000行を超えた。SPU知見、cellGcm知見、メモリアーキテクチャ、RSXアーキテクチャ、オーディオ——全て合わせると数千行になる。Claudeのコンテキストウィンドウは有限だ。魔導書を全て読み込むと、実際のコード出力に使える領域が残らない。

魔導書を詠唱しすぎて魔力切れ。

画像
最終的に大量のスキルが積み上がった

対策として、プロジェクトごとに必要なスキルだけを読み込む方式に移行した。焚火の開発ならPS3開発スキルとSPU知見だけ。cellGcmの開発ならcellGcm知見とRSXアーキテクチャ。百科事典を持ち歩くのではなく、任務に合った装備だけを持っていく。

憲法とスキル。この2つが、AIとの開発を「その場限りのチャット」から「継続的なプロジェクト」に変えた。チャットは消えても、ルールと知識は残る。新しいClaudeは昨日のClaudeとは別人だが、同じ憲法に従い、同じスキルファイルを読む。結果として、あたかも同一人物と仕事をしているかのような連続性が生まれる。

もちろん完璧ではない。Claudeは今でも時々ファイル名のタイムスタンプを忘れるし、推測で先走るし、Makefileを新規作成しようとする。そのたびに罰ゲームが発動し、くららが召喚され、川柳が詠まれる。

だがそれでいい。

そうでもしないとストレスがやばいからな。


憲法とスキルが整備されたことで、開発の加速度が変わった。新しいチャットを開くたびにゼロから説明する苦痛がなくなり、前回の続きからすぐに始められる。エラーのパターンが条文化されているから、同じ地雷を二度踏む確率が下がった。

この基盤の上で、次の挑戦が始まる。

tiny3Dは優れたライブラリだった。焚火も、鳥居の夜景も、XMBスパークルも、NESエミュレータも——全てtiny3Dが可能にした成果だ。だがtiny3DはPS3のGPUであるRSXを抽象化している。その抽象化の向こう側に、まだ触れていない性能が眠っている。

cellGcm。RSXのコマンドバッファに直接命令を書き込み、VRAMのメモリ配置を自分で管理し、シェーダを自分でコンパイルして読み込ませる低レベルAPI。tiny3Dが隠していた複雑さの全てが、むき出しになる世界。

次章では、cellGcmへの移行と、v3からv14cまで——2週間で14回のメジャーバージョンを駆け抜けた怒涛の記録を語る。


第五章 RSXの向こう側


画像
RSX Reality Synthesizer PS3の基板上に実装されたもの

既製エンジンの限界に達し、エンジンを自作に切り替えた段階。ピストン1本から始めて、シリンダー、トランスミッション、ターボを次々と組み上げ、最終的に1080pの街を60fpsで走れるスポーツカーが完成した。

tiny3Dは優れたライブラリだった。

焚火シミュレータ、鳥居の夜景、XMBスパークル、NESエミュレータ——全てtiny3Dが可能にした。2D描画も3D描画も、音声も入力も、tiny3Dとその周辺ライブラリが面倒を見てくれた。何が起きているかを理解しなくても、結果が画面に出る。

そもそもtiny3Dを選んだのは、Claudeの助言だった。開発の初期に、RSXで描画する方法として二通りの選択肢を提示された。tiny3Dを使う方法と、cellGcm APIを直接叩く方法。Claudeはtiny3Dを推奨した。抽象化されていて扱いやすく、素人でもすぐに結果が出せる。理にかなった助言だった。

そしてその助言に従って、俺はtiny3Dで全てを作ってきた。

2Dの表現には十分だった。焚火のパーティクル、鳥居の夜景、XMBのキラキラ——全て2D描画の範囲内で、tiny3Dは期待通りに動いた。

限界が見えたのは、3Dの街歩きシミュレータを作ろうとした時だった。

画像
tiny3d_city_0228.png

tiny3Dで作った街歩き。道路と芝生、ビル群、右上にミニマップ、60fpsで動いている。一見すると動作している。だが遠景のビルが異様に引き伸ばされ、パースペクティブの収束がおかしい。カメラの制御に制約があり、自由な視点操作ができない。tiny3Dの3D描画機能は、2D描画ほど成熟していなかった。

AIが推奨した道を信じて進んだ結果、その道の行き止まりにたどり着いた。ここから先に進むには、tiny3Dを捨てて、Claudeが最初に「もう一つの選択肢」として提示していたcellGcmに移行するしかなかった。


cellGcm。

その名前を説明する前に、tiny3Dが何だったのかを整理しておく必要がある。

プログラミングの世界には「ラッパー」と呼ばれるものがある。直訳すれば「包み紙」。剥き出しのハードウェアや複雑な低レベル関数を、使いやすい箱で包んで、誰でも触れるようにしたプログラムのことだ。

tiny3Dはラッパーだった。PS3のGPUであるRSXを直接制御するのは、レジスタ設定やメモリ管理の呪文が必要な苦行だ。tiny3Dはそれを「四角を描け」「テクスチャを貼れ」という分かりやすい命令に翻訳してくれる。初心者でも数行のコードで絵が出る。だが包み紙の作者が「ここまでしかできないよ」と決めた範囲から、一歩も出ることができない。

ラッパーは弱者のための包帯ではない。強者を縛る鎖だ。

言い換えれば、今までの開発はガイド付きのツアー旅行だった。安全だが、決められたルートしか歩けない。ガイドが「ここから先は立入禁止です」と言えば、その先に何があるかも知らずに引き返すしかなかった。cellGcmへの移行は、ガイドを振り切って裏路地に踏み込むことだった。VRAMの深淵を自分の足で歩く。良くも悪くも、命の保障はない。

cellGcmは、その包み紙を破り捨てた先にあるものだった。PS3のRSXを直接制御する低レベルAPI。GPUのコマンドバッファに直接命令を書き込み、VRAMのアドレスを自分で計算し、頂点バッファを手動で配置し、シェーダバイナリをロードして描画パイプラインに接続する。OpenGLのような高レベルAPIとは次元が違う。画面に三角形1つ表示するだけで、数百行の初期化コードが必要になる。

tiny3DからcellGcmへの移行は、PS3開発の最終目標だった。自分でシェーダを書き、自分でGPUを制御し、自分の手でRSXの性能を引き出す。

これは最大のブレイクスルーだった。


最初の壁は初期化だった。

PSL1GHTには`rsxInit()`というRSX初期化関数がある。名前からして使うべきに見える。だが呼び出すと`0x802100FF`——メモリ不足エラーで失敗する。
何時間もデバッグした末に、答えを見つけた。

tiny3Dのソースコードから答えを見つけた。tiny3Dは`rsxInit()`を使っていない。代わりに`gcmInitBody()`を直接呼んでいる。`rsxInit()`は内部でGPUヒープの初期化を行うが、RPCS3エミュレータ上ではこのヒープ確保が失敗する。`gcmInitBody()`はIOマッピングとコマンドバッファだけを初期化する、より低レベルなAPIだ。

このパターンはcellGcm開発で何度も繰り返された。PSL1GHTの高レベル関数がRPCS3で動かず、より低レベルなAPIに降りて解決する。便利な抽象化が使えないから、その下のレイヤーを自分で叩く。毎回がtiny3Dのソースコードを読み解き、何をしているかを理解し、自分で再実装する作業だった。

tiny3Dで学んだ全ての知見が、ここで活きた。


cellGcmへの移行がなぜ「最大のブレイクスルー」なのか。その意味を理解するには、PS3 homebrew開発コミュニティの歴史を振り返る必要がある。

PSL1GHTのソースコードの中に、こんなコメントが残されている。

「Fragment shaders don't exist yet」——フラグメントシェーダはまだ存在しない。

PSL1GHTの開発者たちは、RSXの高レベルラッパーである`rsxInit()`を整備し、tiny3Dのような抽象化ライブラリを作り、homebrew開発者が手軽にグラフィックスを扱えるようにした。だがRSXの低レベル制御——cellGcm直接API、手動VRAM管理、シェーダバイナリの完全制御——はずっと未完成のまま残されていた。15年間、世界中のギークたちが「PSL1GHTは未完成だから」「tiny3Dなどのラッパーを使うのが限界」と受け入れてきた壁だ。

ここから先は

6,995字 / 10画像

¥ 500

この記事が気に入ったらチップで応援してみませんか?

【狂気】2026年、PS3を開発する——1行もコードを書けない人間が、AIと組んで「開発地獄」と呼ばれたPS3に挑み、15年間誰も開けられなかった扉をこじ開けた1週間の記録。|田中
word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word

mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1