カートリッジ
カートリッジは一つの gzip 圧縮 JSON ファイルで、ROM (バイト列、ラベル、ソース)、タイル (バイナリ形式と 0..3 の行の両方)、そしてそれが書かれたコンソールアドレスを運ぶ。
規約はバイト列の横ではなく一緒に旅をする。規約こそが外部の作者が同意しなければならない部分であり、ページがゲームを遊ぶには 8 個のアドレスが要るのに、どれについても問い合わせるハードウェアが無いからだ。別ファイルの規約は、漂うほうの写しだ。
mtime はゼロなので、同じカートリッジを二度鋳造すれば同じバイト列になり、二つを diff できる。
curl -s localhost:6502/v1/console # 規約、公開版
curl -s localhost:6502/v1/cartridge -d @cart.json \
-H 'content-type: application/json' -o mine.cart.gz
curl -s 'localhost:6502/v1/cartridge?format=json' -d @cart.json ... | jq .verify
GET /v1/console はデータとしての規約で、プログラムから読むならそちらの写しだ。このページは理由の側で、あのルートがリファレンスの側。
鋳造だけができて、アセンブルにはできない二つのこと
成立しないレイアウトを拒む。 自分の画面に重なる ROM は完璧にアセンブル できて、それから自分の上に描く。ROM の中にある規約バイトは、ホストがコードに書き込むということだ。どちらも理由付きの 422 になる。後で壊れるカートリッジにはならない。
アセンブラの end (両端含む) を one-past と読み違えたせいで、これらの検査はどれも 1 バイト足りなかった。いまは test_cartridge.py が両側から釘付けにしている。
実際に走らせる。 アセンブルできて、ブートできて、しかしティックフラグを 一度も上げない ROM は、このコンソールでは走らない ROM であり、走らせる以外にそれを言えるものは無い。報告には、完了したフレーム数、各フレームの費用、画面が変わったか、どのタイルが載っているかが入る。
フレーム費用は、カートリッジを無視する梯子の上で実測される
費用は絶対的な梯子の上で測られる。128 半サイクルから 16k までは 128 刻み、その先は 1024 刻みで、カートリッジが宣言するどんな値からも意図的に種を取らない。
宣言された費用から最初の一段を決めるのは、ホストには正しく、測定には間違いだ。同じ ROM を frame_cost 512 と 20000 で鋳造したら、実測は 6400 と
6250 になった。どちらの数字も、自分のリクエストを切り上げただけのものだ。
これは仮定の話ではない。Die Runner のページが主張していたフレーム費用は、自分のリクエストを読み返したものだった。 コンソールは frameCost 半サイクルを要求し、それから使った量を報告するので、そこに書かれた値は何であれ自己確認になる: 12,000 はファイルが打ち込んだ数字であって、チップが作った数字ではなかった。
実際に走らせて実測すると、Die Runner の定常フレームは 8,704。12 フレームにわたって微動だにせず、最初のフレームは 5,440。ページが買っていたチップ時間より、1 フレームあたりおよそ 28% 少ない。
読み込み方
コンソールページは ?cart=<url> かファイル選択からカートリッジを読み込み、読み込まれたカートリッジは、ラベルが画面上と言っているものを黙って置き換える代わりに、選択肢に加わる。タイルはシートを置き換えるので、カートリッジは自分の絵を連れてくる。
games/deploy.sh はサンプルをツリーに置く代わりに鋳造する。だから
rom/dierunner.s に対して古びることができず、デプロイのたびにエンドポイントが運動する。
# API が鋳造する。成立しないレイアウトを拒み、それから走らせる。
python3 games/tools/mint.py --api https://6502.tinymachines.ai/api
カートリッジ・ゼロ
rom/snake.rom、351 バイト。パイプを端から端まで証明するためにいる。
そのカートリッジ項目のアドレスはすべて逆アセンブル (rom/snake.lst) から読み取り、稼働中のチップで確認したもので、推測は一つも無い。以前の読みでは
2 = right になっていて、蛇が下に歩いてそうではないと言った。
| アドレス | 何か |
|---|---|
$0D | ティックフラグ: ホストがクリアし、ROM が上げる |
$02 | 要求方向、1 上 2 下 3 左 4 右 |
$03 | ゲームオーバー |
$0400-$04FF | 画面、16x16、0 空 1 蛇 2 餌 |
盤面は壁を持たず巻き付く: セル番号の両ニブルに AND #$0F。
出自: サイトオーナーのプロンプトで Grok が書き、xAI の消費者向け規約の下で オーナーが所有する。ダイデータからの派生ではなく、あのデータの義務を一切負わない。
カートリッジ・ワン
rom/dierunner.s、339 バイト。このコンソールのために書かれ、プロジェクト自身のアセンブラ (web/asm.js の上の games/tools/asm.mjs。逆アセンブラの表を反転したものなので、アセンブルできるなら同じ行に逆アセンブルできる) でアセンブルされる。
あなたはダイを降下する電荷キャリアだ。世界は上にスクロールして迎えに来る。ポリシリコンのゲートが一つだけ口を開けて道を塞ぐ。パストランジスタのゲートは二つのチャネルを持ち、導通するのは一方だけで、8 フレームごとにクロック位相が反転して二つが入れ替わる。いま閉じているチャネルはすぐに開く。それがゲームのすべてだ。電荷パケットが得点になる。ダイは巻き付く。
アートと一緒に届いた 7 枚のタイルはすべて使われていて、飾りのための飾りは一つも無い。かつてのダイは、柵と柵の間が空っぽだった。
| タイル | 何か | 何をするか |
|---|---|---|
| 9 | ポリのバス | ダイを横切る三連。背景 |
| 10 | 電源レール | 列を下に 3 から 6 行走る。背景 |
| 11 | 拡散のウェル | 時々の単発。背景 |
| 12 | ポリの T | レールが入ってくる場所 |
| 13 | メタルの L | レールが曲がって出て行く場所 |
| 14 | コンデンサ | 電荷パケット 5 個ぶん |
| 15 | ボンドパッド | 直上の柵の隙間を標識する |
理解しておく価値があるのは電源レールだ: ROM は 1 行に 1 セルしか描かないのに、世界がスクロールするからレールとして現れる。入る端をポリの T が、出る端をメタルの L が蓋するので、ROM が線を一度も描かないままレールには向きがある。
ボンドパッドが付くのは素通しの柵だけだ。スイッチ付きゲートのどちらのチャネルが開いているかは、プレイヤーが着く頃には動いてしまっている制御線次第なので、そこにある標識は推測を指すことになる。 コンソール規約を参照。