|
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にし、あわせて逆方向としてupdatePlayerBulletとupdateAlienBulletを展開に戻した場合も測りました。3つを同じ環境で続けてコンパイルしています。
| 構成 | bsc時間 | Verilog[KB] | メイン状態数 | LUT | FF |
|---|---|---|---|---|---|
| 小FSM 7個の現状 | 0:44 | 1,965 | 168 | 5,812 | 2,125 |
| 1箇所呼びの2個を展開に戻す | 0:55 | 2,597 | 249 | 5,770 | 2,099 |
| 1箇所呼びの3個を追加でFSM化 | 0:45 | 1,660 | 94 | 5,879 | 2,187 |
LUTとFFはYosysの概算、時間は2コアの仮想マシンでの値です。展開に戻すとメインFSMの状態数が168から249に増え、コンパイル時間が24%増、Verilogが32%増になりました。逆に3個を追加でFSMにすると状態数は94に減り、時間は同じままVerilogが16%減りました。LUTとFFは逆方向に1%ほど動きます。記事#1037と記事#1038で見えていた、本体の厚いseqはメインから切り出す方がbscの負担が軽い、という傾向を逆方向からも確かめた形です。動作はVRAM書き込みの系列がサイクル番号を除いて一致しました。
教科書版の最終形
以上から、教科書版は次の2つの基準で決めました。複数箇所から呼ばれるseqは1個の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の状態数は8/3版の194から94になります。
Leave a Comment