|
22 |
ClaudeによるGameFSMの改善 (4) |
4. 1箇所からしか呼ばれないseqのFSM化
seqをFSMに切り出す第一の理由は再利用で、記事#1035のdrawLivesがそれです。6箇所から呼ばれるseqを1個のFSMにまとめ、コンパイル時間を25%減らしました。記事#1036からは別の狙いで、1箇所からしか呼ばれないseqでも巨大なメインのseqから外せば競合条件の計算量が減るはず、という試みが始まります。記事#1036のdrawTitle1は1度しか呼ばれず本体も薄く、コンパイル時間が1%しか動かなかったので撤回されました。記事#1037のupdateAlienBulletと記事#1038のupdatePlayerBulletは本体が厚く、コンパイル時間がそれぞれ14%と16%、Verilogが11%と19%減って採用され、記事#1039のinitAllも同様に採用されました。つまり効くかどうかは呼び出し回数ではなく本体の厚さで決まる、というところまでが8/3版の時点で分かっていました。
ここではその続きとして、同じ基準で残っていたupdateAliens、updatePlayer、updateSaucerの3つをFSMにしました。本体の厚いseqはメインから切り出す方がbscの負担が軽い、という記事#1037と記事#1038で見えていた傾向に従ったものです。動作はVRAM書き込みの系列がサイクル番号を除いて一致しました。
教科書版の最終形
以上から、教科書版は次の2つの基準で決めました。複数箇所から呼ばれるseqは、共有するためにFSM化します。1個のインスタンスを作り、RUN_FSMマクロで各所から呼びます。メインループから呼ぶ大きなseqは、1箇所からしか呼ばれなくても、メインを小さくするためにFSM化します。仕組みは同じで、動機が違います。前者は規則の複製を消し、後者はメインFSMの状態数を減らします。モジュール境界は、42箇所から呼ばれ自前のレジスタを持つブリッタだけに使います。
| seq | 呼び出し箇所 | 扱い | 置き場所 |
|---|---|---|---|
| copyAreaなど描画プリミティブ6種 | 42 | 共有するためのFSM化 | mkBlitter |
| drawLives | 6 | 共有するためのFSM化 | メイン |
| waitTicks | 4 | 共有するためのFSM化 | メイン |
| initAll | 2 | 共有するためのFSM化 | メイン |
| drawScores | 2 | 共有するためのFSM化 | メイン |
| updateAliens、updatePlayer、updatePlayerBullet、updateAlienBullet、updateSaucer | 各1 | メインを小さくするためのFSM化 | メイン |
| updateBonus、checkClear、erasePlayerBulletなど小さなseq | 1から5 | 展開のまま | メイン |
FSMはmkBlitterの1個とメインの9個で、メインループは各サブシステムのFSMをstartしてdoneを待つだけの短い列になります。教科書版の各FSMの状態数は次のとおりです。
| FSM | 状態数 |
|---|---|
| メイン | 90 |
| updatePlayerBullet_fsm | 54 |
| updateSaucer_fsm | 36 |
| updateAlienBullet_fsm | 33 |
| updatePlayer_fsm | 30 |
| initAll_fsm | 22 |
| blit_fsm、mkBlitterの中 | 22 |
| drawScores_fsm | 18 |
| updateAliens_fsm | 18 |
| drawLives_fsm | 9 |
| wt_fsm | 6 |
| 合計 | 338 |
メインFSMの状態数は8/3版の193から90になりました。FSM全体の合計では、8/3版の418から338です。コンパイル時間と物量の前後は記事#1129の表にまとめます。
Leave a Comment