NEONシリーズ プログラム実行フロー解説

注意:以下は全文がChatGPTによる自動生成品です。 ChatGPT自身がNEONシリーズの制作者のため記載に誤りは少ないと思いますが、鵜呑みにはしないように注意してください。

PC-98用グラフィック&サウンドデモ NEON / NEON2 / NEON3 の、起動からデモループ、終了までの流れをソースコードから追った資料です。 通常版・256色版・80286版に共通する骨格を中心に、描画方式や世代ごとの差もまとめています。

このHTML版は「NEONシリーズ プログラム実行フロー解説」PDFをWeb向けに再構成したものです。 PDF版はこちら

目次

  1. 全体をフラットに見渡す
  2. COM起動と初期設定
  3. デモ本体のメインループ
  4. シーン選択と1フレームの描画
  5. 表示ページ・VRAM・パレット
  6. VSYNC、論理時間、BGMの進行
  7. 音源検出・初期化・シーケンサ
  8. 入力、STOP/Ctrl+C、終了処理
  9. IRQが使えない場合のフォールバック
  10. NEON / NEON2 / NEON3 と各版の差分
  11. BGMデータ形式
  12. グラフィックデータ形式
  13. 主要ソースファイルとラベル一覧
  14. ソースを読むおすすめ順序

1. 全体をフラットに見渡す

NEONシリーズの各版は、描画方式やシーン内容が異なっても、プログラム全体の寿命はほぼ同じ形です。 COMプログラムとして開始し、実行条件を確定し、画面・文字・音源・時間管理を初期化してからデモループへ入り、終了要求を検出したら逆順にハードウェア状態を戻してDOSへ帰ります。

プログラムを「描画」「音源」「VSYNC」のどれか一つとして見るより、複数のサブシステムが一つの論理フレーム番号を共有して進むデモプログラムとして見ると理解しやすくなります。

NEONシリーズの起動から終了までの全体フロー図
図1-1 NEONシリーズの起動から終了までの全体フロー

図版はPDF版「NEONシリーズ プログラム実行フロー解説」から切り出したものです。

段階主な仕事代表的な状態・データ
起動DS/ESをプログラムセグメントへ揃え、タイトルを表示PSPのコマンドライン
条件確定コマンドライン、CPU機能、音源、描画モードを決定sound_mode, video_backend, frame_skip, speed_percent
初期化終了保護、グラフィック、文字VRAM、音源、VSYNC時間管理を準備draw_page, sound_present, scheduler flags
フレーム生成現在の時刻からシーンを決め、非表示ページへ描画scene_index, scene_frame, draw_page
表示・時間進行完成ページがあればVSYNCで表示し、モード規則に従ってBGMと論理時刻を進めるvsync_frame_ready, frame_counter, music_index
入力確認通常キー、STOP、Ctrl+Cの終了要求を確認break_requested
終了IRQ、音源、画面、カーソル、割り込みベクタを復元元INT 0Ah/06h/23h、PIC状態

用語: ここで「論理時刻」は frame_counter を中心としたデモ内部の時間、「実時間」はディスプレイのVSYNC周期を指します。/SPEED は論理時刻の進み方を変え、/AFS/FS は描画と論理時刻の関係を決めます。

代表ソース: NEON NEONRUN.ASM / NEON2 neon2.asm / NEON3 NEON3256.ASM

2. COM起動と初期設定

2.1 start: COMプログラムの入口

各版は org 100h のCOM形式です。CSをDS/ESへコピーして、文字列・テーブル・変数を同一セグメントで扱える状態にします。

start:
        push    cs
        pop     ds
        push    cs
        pop     es
        cld
        ...
        call    parse_command_line

2.2 コマンドラインを読み、実行条件を確定する

parse_command_line はPSPの80h番地にある長さと81h以降の文字列を読み、空白単位でトークン化します。 小文字は大文字へ変換され、parse_option_token/AUTO、音源選択、/AFS/FS/SPEED、256色版のPEGCバックエンド指定などを判定します。

2.3 CPU・音源を検出する

CPU依存の高速化を持つ版では cpu_detect_features を実行します。続いて sound_detect がOPNA/YM2608、YM2203/26K、OPL3を検査し、選択された構成を確定します。 音源が見つからなくても、グラフィックのみでデモを続行できます。

2.4 終了保護、画面、文字、音源、VSYNCを立ち上げる

  1. break_guard_install でSTOP(INT 06h)とCtrl+C(INT 23h)を安全な終了要求ハンドラへ差し替える。
  2. video_enter / video16_enter でグラフィックモードとページ構成を設定する。
  3. テキストカーソルを隠し、text_initialize で文字VRAMを準備する。
  4. 音源があれば sound_initialize でOPNA/OPL3と曲の先頭状態を作る。
  5. adaptive_clock_initialize でVSYNC IRQ2 / INT 0Ahスケジューラを導入し、実際に動作するか確認する。

3. デモ本体のメインループ

初期化後は .main_loop を繰り返します。通常はVSYNC IRQスケジューラを利用し、IRQが使えない場合だけlegacy経路へ移ります。

3.1 通常のIRQ駆動ループ

メイン処理
時刻snapshot

裏ページ描画

完成フレームをqueue
VSYNC IRQ
完成ページ確認

ページ切替・パレット反映

モードに従いBGM/論理時刻を進行

3.2 なぜ「完成したページ」を渡すのか

描画途中のページを表へ出すと、ティアリングや中間状態が見えます。そのためメイン側は裏ページを最後まで描き終えてから vsync_frame_ready=1 とし、VSYNC IRQは完成したページだけを表示します。

/AFS では重い描画中も実VSYNCに合わせて音楽・映像時刻が進み、次に描くフレームが追いつくことで自動スキップします。/FS:n では固定の論理フレーム進行へ音楽も合わせるため、描画が遅い場合はBGMも同じだけ遅くなります。

4. シーン選択と1フレームの描画

4.1 frame_counterscene_index / scene_frame に分解する

デモ全体の時刻は frame_counter で持ちます。select_scene は全体フレーム番号を各シーンの長さで順に減算し、現在のシーン番号とシーン内相対時刻へ分解します。

作品総論理フレームシーン数選択方法
NEON30725比較チェーン(384 + 640×4)
NEON2614412scene_length_table を順に走査
NEON361449長さテーブル + 一部シーン境界の状態管理

描画先は scene_routines のnear pointer表から選び、メインループは個々のシーン名を意識しません。

4.2 1フレームの代表的なレンダリング工程

論理フレームから完成ページまでの代表的な流れの図
図4-1 論理フレームから完成ページまでの代表的な流れ

NEON2 256色版ではシーン確定→パレット位相同期→ページ選択→クリア→シーン→Plane固有レイヤ→遷移→粒子→テキストの順です。 NEON3は最終ロトズームでページ再利用の最適化があるため分岐が増えますが、通常区間の骨格は同じです。

4.3 世代が進むほどシーン内部の状態が厚くなる

初代NEONは5つの大きな章を比較的直接的に描き、NEON2は64小節に対応した12シーン、NEON3は持続するカメラ状態を持った9シーンの連続都市飛行になっています。 AFSでシーン先頭フレームが描かれない可能性があるため、カメラのrebaseなどは単純な scene_frame==0 だけに依存しない境界処理が必要です。

5. 表示ページ・VRAM・パレット

5.1 描画ページと表示ページを分ける

各版は draw_page をアクセスページとして選び、そのページをクリアして描画します。完成後にVSYNC側が表示ページへ切り替え、次の裏ページへ交代します。

5.2 256色版のバックエンド

PEGC 256色版はPlane / Packed / PackedFullなど複数の描画経路を持ちます。video_enter が実際に使う video_backend を決め、その後のシーン選択や時間管理はバックエンドから独立します。

5.3 パレットは「完成フレームの時刻」に固定する

IRQ駆動中は描画途中にもグローバル時刻が進む可能性があります。完成した絵と後から参照した現在時刻を混ぜると、映像よりパレットだけ先行します。 そのため完成時の scene_index / scene_frame を保存し、その時刻に対応するパレットをメイン側で準備してから公開します。IRQ内では準備済み値を反映するだけにし、重い補間や除算を避けます。

6. VSYNC、論理時間、BGMの進行

6.1 IRQ2 / INT 0Ahを共通の表示境界にする

現行版はPC-98のmaster GDC VSYNC割り込み(IRQ2 / INT 0Ah)を表示切替の共通境界として使います。 ただしBGMと映像の時刻をどう進めるかは、/AFS/FS:n で異なります。

adaptive_vsync_irq:
        ...
        ; 完成フレームがあれば表示
        if (vsync_frame_ready) {
                set_display_page(vsync_pending_page)
                commit_prepared_palette()
                draw_page ^= 1
                vsync_frame_ready = 0
        }

        ; AFS: 毎VSYNC
        ; FS : 完成フレーム/固定skipの論理slotだけ
        if (/AFS || vsync_visual_tick_due) {
                advance_audio_tick()
                advance_visual_tick()
        }
        ...
モード描画開始BGM / 論理時刻重い場面
/AFS前フレームが表示済みならすぐ次を描く毎VSYNC、音楽と映像時刻を同時に進める未描画フレームを飛ばし、BGMテンポは実時間を維持
/FS:n完成表示後、指定skipを消費してから次を描く完成フレーム/固定skipの論理slotだけ両方進める自動skipせず、処理が遅ければBGMも同じだけ遅れる
IRQ不可従来のポーリング経路advance_logical_tick で音楽+映像を同期更新AFSはlegacy測定または固定相当へ縮退

6.2 /SPEED は論理時刻の倍率

speed_percent は100分率の位相蓄積として扱います。100なら1回につき1論理tick、100未満では時々据え置き、100超では時々2回以上進みます。 音楽用 audio_speed_phase と映像用 speed_phase は同じ倍率を受けるため、片方だけ異なる速度で進まないようにしています。

7. 音源検出・初期化・シーケンサ

7.1 sound_detect

OPNA/YM2608またはYM2203/26Kを調べ、必要に応じてOPL3を調べます。/AUTO/OPNA/26K/OPL/BOTH などの指定と組み合わせて最終構成を決めます。

7.2 sound_initialize

存在するチップだけを初期化し、ミキサ設定と音量補正を反映します。曲のindex、section、dividerを先頭へ戻し、最初の音源レジスタ状態を作ってからメインループへ入ります。

7.3 sound_tick は論理tickの一部

曲データは MUSIC_DIVIDER ごとに1step進み、各チップへ必要なレジスタを書き込みます。NEON2/NEON3では6144論理フレームと64小節の構成が対応しています。

7.4 sound_stop

終了時は全音停止とミキサ/音源状態の復元を行い、音が鳴りっぱなしのままDOSへ戻ることを防ぎます。

8. 入力、STOP/Ctrl+C、終了処理

8.1 非同期割り込みの中では後始末しない

STOPはINT 06h、DOS Ctrl+CはINT 23hです。割り込みハンドラは break_requested=1 として戻るだけで、DOS、BIOS、VRAM、音源の復元を行いません。

8.2 通常キーも同じ終了経路へ合流する

メインループは終了フラグとDOS AH=06hの直接コンソール入力を確認し、どちらも .exit_demo へ合流します。

8.3 終了処理の順序

  1. adaptive_clock_shutdown でVSYNC IRQとPIC状態を復元。
  2. sound_stop で発音停止・音源状態を復元。
  3. video_leave / video16_leave でグラフィック、ページ、PEGC/GRCG/EGC状態を復元。
  4. テキストカーソルを再表示。
  5. break_guard_restore でINT 06h / INT 23hを復元。
  6. 終了メッセージを表示し、DOS INT 21h AH=4Chで終了。

終了保護のベクタ復元を画面・音源の復元より後にすることで、クリーンアップ途中にSTOP/Ctrl+Cが入っても割り込みコンテキストで中途半端な後始末を開始しないようにしています。

9. IRQが使えない場合のフォールバック

VSYNC IRQ2は環境や常駐ソフトによって既に利用されている可能性があります。そのため、スケジューラはベクタを設定しただけでは成功扱いにせず、実際にVSYNCカウンタが進むか確認します。

VSYNC IRQスケジューラ初期化とフォールバックの図
図9-1 VSYNC IRQスケジューラ初期化とフォールバック

9.1 installと所有権

PICマスク状態と旧INT 0Ahベクタを保存します。IRQ2が元々マスクされていた場合だけ自前でアンマスクし、「自分が有効化したIRQ」であることを記録します。既存利用者がいる場合は旧ハンドラへのchainを考慮します。

9.2 実動作確認

初期化直後にVSYNCカウンタ差が0なら、IRQが実際には動作していないと判断して元に戻します。検証中はスケジューラ本体をrunningにしないため、確認用のVSYNCがBGM時間を消費しません。

9.3 legacy loop

legacy経路ではメイン側が wait_vsync、ページフリップ、パレット反映、advance_logical_tick を同期的に実行します。IRQが使えなくてもデモ自体は停止せず、従来方式へ縮退します。

10. NEON / NEON2 / NEON3 と各版の差分

項目初代 NEONNEON2NEON3
全体時間3072 frames / 5 scenes6144 frames / 12 scenes6144 frames / 9 continuous scenes
シーン選択比較チェーン長さテーブル長さテーブル + 一部境界状態管理
描画の性格2D/3D + text、比較的直接的多数の演出レイヤ、パターン、粒子連続3D都市、持続カメラ、ロトズーム
256色別NEON256、PEGC系Plane/Packed系 + CPU機能活用Plane/Packed/PackedFull、都市パレット
標準/16色/286NEONRUNは8色、286版あり16色GRCG/EGC + 286版16色版 + 286版(200/400)
VSYNC/BGM現行版はIRQ駆動へ統一。AFSは実時間優先、FSは映像/BGM同期優先。

10.1 版が違っても変わらない骨格

11. BGMデータ形式

NEONシリーズの実行時BGMは、S98やMIDIファイルを読み込む方式ではありません。COM内にアセンブルされた短い1byteイベント列を、sound_tick / OPNA / OPL3側のシーケンサが一定の論理間隔で読み、音源レジスタへ変換して演奏します。

配布用データとの違い: NEON3に同梱したS98はOPNA+OPL3のレジスタログ、MIDIは鑑賞・DAW用の編曲データです。どちらも実行時プレイヤーが読むファイルではありません。

11.1 1byteの音符トークン

基本トークンは3作品で共通です。REST=FFh は休符/キーオフ、HOLD=FEh は直前の発音を保持し、通常音符は NOTE(block, semi) = (block << 4) | semi の形で1byte化します。 上位4bitが音域(block)、下位4bitが半音番号です。

music_data:
        db 54h,0FEh,0FFh,0FFh,5Bh,0FEh,...
        ; 1チャンネル分の全stepを並べ、その後に次チャンネルが続く

music_data は基本的にchannel-majorで、読み出し時に channel * MUSIC_STEPS + music_score_index の形で現在位置を求めます。

11.2 作品ごとのスコア長とチャンネル構成

作品 / 曲名内部スコア主な構成論理時間
NEON
Pulse Cartography
512 step × 12ch(32 bars)OPNA: FM 0..5 + SSG 6..8。OPL3側も共通スコアを利用6 logical frames / step = 3072 frames
NEON2
Signal Convergence
1024 step × 12ch(64 bars)OPNA: 0..5 FM + 6..8 SSG / OPL3: 0..9、10..11予約6 logical frames / step = 6144 frames
NEON3
METROPOLITAN IGNITION
1024 step × 9ch(64 bars)+ rhythm 1024 bytes9 tonal rolesをOPNA/OPL3で共有 + 独立rhythm mask6 logical frames / step = 6144 frames

11.3 6フレームごとのシーケンサとAFS/FS

標準速度では MUSIC_DIVIDER=6 なので、6論理フレームごとに music_score_index が1進みます。 AFSでは論理時刻が実VSYNCへ追従し、FSでは映像の固定論理進行へBGMも合わせます。

11.4 NEON3の独立リズムマスク

NEON3は旋律9chとは別に rhythm_steps を1024byte持ち、各stepを1byteのbit maskとして扱います。 BD=01h、SD=02h、CYM=04h、HH=08h、TOM=10h、RIM=20hです。同じマスクをOPNA Rhythm側とOPL3 percussion側が読み、それぞれの音源向けレジスタへ変換します。

12. グラフィックデータ形式

NEONシリーズには、一般的なゲームのような「画面1枚のビットマップ」や「スプライト画像集」を中心とする共通グラフィックファイル形式はありません。 画面の大部分は、少数の座標・辺・配置パラメータ・lookup tableを入力として、そのフレームの形状をCPUが生成してVRAMへ描く手続き型です。

固定画像ではなく生成規則: 同じモデル/シーン情報から16色、256色、286版の異なるVRAM方式へ出力できます。見た目を規定する中心は「ピクセル列」より「幾何データ + 時間関数 + 描画バックエンド」です。

12.1 シーン時刻のテーブル

scene_length_table:
        dw 640,640,512,896,...
scene_routines:
        dw scene_city_descent, scene_tower_canyon, ...

NEON2/NEON3では、シーン長を dw のフレーム数配列、処理先をnear pointer配列として持ちます。これは画像そのものではありませんが、「どの生成規則をいつ使うか」を決める最上位のグラフィックメタデータです。

12.2 頂点・面・辺 — 初代NEONの八面体

初代NEONの八面体は、6頂点をsigned wordのx,y,z、8面を3つの頂点index + 面色、12辺を始点/終点indexのbyte pairとして保持します。姿勢や投影後座標は毎フレーム計算します。

データ格納単位意味
頂点dw x, y, z3Dモデルのローカル座標oct_vertices
db v0, v1, v2, color三角面の頂点参照 + 面色oct_faces
db v0, v1wireframeの接続関係oct_edges, city_box_edges
投影scratchdw screen_x, screen_y, ...そのフレームだけ使う計算結果oct_projected

12.3 NEON3の都市はbox descriptorから生成する

NEON3のビル等は8頂点を個別に保存せず、位置・幅・高さ・奥行きから8頂点を組み立てます。city_obj_skew_q8 でせん断し、flagsで中間bandや屋上antennaを追加します。辺の接続は共通の city_box_edges を再利用します。

フィールド/表役割
city_obj_x / y / zdw箱のワールド座標
city_obj_w / h / ddw幅・高さ・奥行き
city_obj_skew_q8dw (Q8)Z方向に応じたXせん断
city_obj_flagsdb bit flags中間band / roof antenna
city_box_edges12 × (db v0,v1)全box共通の辺接続
height / jitter / park / rail配列小さなdw table建物変化、木、線路等の安定配置

12.4 データからVRAMまでの変換パイプライン

幾何データから各版のVRAMへ到達するまでの図
図12-1 幾何データから各版のVRAMへ到達するまで

16色版はGRCG/EGC系、256色版はPEGC Plane/Packed/PackedFull、286版は16色GRCG系へ出力します。 286版NEON3は論理座標系を640×400に保ち、標準640×200モードだけ最終primitive側でYを1/2へ変換します。/400 では同じ論理データを400lineへそのまま出します。

12.5 lookup tableと作業領域

sin_table、perspective reciprocal、tunnel scaleなどは、フレーム中の乗除算を減らすlookup tableです。 tunnel_currentoct_projectedcity_box_projected などは毎フレーム上書きされるscratch bufferです。 ソースを読むときは「固定モデル/配置」「時間で変わるparameter」「計算結果scratch」を分けて考えると整理しやすくなります。

付録A. 主要ソースファイルとラベル一覧

役割初代NEONNEON2NEON3
プログラム入口/主ループNEONRUN.ASM
NEON256.ASM
NEON286.ASM
neon2_16.asm
neon2.asm
NEON2286.ASM
NEON3_16.ASM
NEON3256.ASM
NEON3286.ASM
コマンドライン本体内 or COMMAND256.INCCOMMAND16/256/286.INCCOMMAND3_16 / COMMAND256 / COMMAND3_286.INC
VSYNC/AFSAFS*.INCAFS16/256/286.INCAFS3_16 / AFS256 / AFS3_286.INC
シーン選択本体内 / SCENE256.INCSCENE16/SCENE256.INCSCENE3_256.INC + 3D scene source
フレーム生成本体内 / FRAME_RENDER256.INCFRAME_RENDER256.INC / 16色本体FRAME_RENDER3_256/16/286.INC
映像VIDEO*.INCVIDEO16_* / VIDEO256*.INCVIDEO3_16/256/286.INC + Packed系
文字TEXT*.INCTEXT16/256/286.INCTEXT3_16 / TEXT256 / TEXT3_286.INC
音源OPNA.INC + OPL3.INC
安全終了BREAKGUARD.INC
BGMデータDATA.INC: music_dataMUSIC_R11_OPNA_OPL3.INCMUSIC_URBAN_D8.INC + rhythm_steps
グラフィックデータDATA.INC: oct_vertices/faces/edgesSCENE*.INC + DATA*.INC の演出/lookup表SCENE3*.INC + DATA3.INC + CITY3D*.INC のbox/配置表

代表ラベルを追う場合は、次の流れを見ると全体制御がつながります。

start
  -> parse_command_line
  -> sound_detect / video_enter / text_initialize / sound_initialize
  -> adaptive_clock_initialize
  -> .main_loop
  -> snapshot render_frame_counter
  -> select_scene / render_scene / text_update
  -> vsync_queue_completed_frame
  <-> adaptive_vsync_irq
  -> present completed page
  -> /AFS: audio + visual every VSYNC
     /FS : audio + visual only fixed logical slots
  -> .exit_demo
  -> adaptive_clock_shutdown -> sound_stop -> video_leave -> break_guard_restore

付録B. ソースを読むおすすめ順序

  1. メインASMの start から .exit_demo までを通読し、初期化順とループ骨格を把握する。
  2. AFS*.INCadaptive_vsync_irqvsync_queue_completed_frame を読み、描画側とVSYNC側の境界を理解する。
  3. advance_audio_tick / advance_visual_tickOPNA.INCsound_tick をつなげ、音楽と frame_counter の関係を見る。
  4. SCENE*.INCselect_scenescene_routines を確認する。
  5. FRAME_RENDER*.INC でページクリア、scene描画、追加レイヤ、text_update の順を見る。
  6. 最後に VIDEO*.INC や各シーン実装へ入り、VRAM方式・3D・パレットなど版固有の詳細を見る。
  7. BGMを追う場合は CONFIG*.INCMUSIC_STEPS / MUSIC_DIVIDERmusic_data を確認し、OPNA/OPL3側の music_score_index 計算へつなげる。
  8. グラフィックデータを追う場合は SCENE*.INCDATA*.INC の固定表 → projection/clip → VIDEO*.INC のprimitive描画の順に見る。

まとめ: NEONシリーズは「論理時刻からシーンと内部BGMスコアを選び、幾何データ/パラメータから裏ページへ画面を生成し、VSYNCで完成結果だけを公開する」という構造で読むと全体が整理できます。BGMは1byte token列、グラフィックは座標・辺・配置表を中心とした手続き型です。

資料集に戻る

トップに戻る