15 |
GameFSMの改良 (13) |
他にもcall順位の上位では出てこなかった関数にdrawLives()がありました。これは自機の残り数を表示するもので、staticには6回呼ばれているため、これもFSM化して最適化します。
まず、オリジナルのコードは、
// 残機表示
function Stmt drawLives();
return (seq
// 残機数字の表示
copyArea(gun_no*8, 161, 23, 241, 8, 8);
if (gun_no == 1) seq
eraseArea(42, 241, 16, 8);
endseq else if (gun_no > 1) seq
eraseArea(16*gun_no + 26, 241, 16, 8);
copyArea(0, 16, 16*gun_no+10, 241, 16, 8);
endseq // if
endseq);
endfunction
ここでgnu_noが自機の数を示します。これを例によってFSM化してメインでは起動し、終了待ちをするだけに変更します。以下が変更後のコードです。
// 残機表示
function Stmt drawLives_org();
return (seq
// 残機数字の表示
copyArea(gun_no*8, 161, 23, 241, 8, 8);
if (gun_no == 1) seq
eraseArea(42, 241, 16, 8);
endseq else if (gun_no > 1) seq
eraseArea(16*gun_no + 26, 241, 16, 8);
copyArea(0, 16, 16*gun_no+10, 241, 16, 8);
endseq // if
endseq);
endfunction
// 単一インスタンスのFSMを生成(モジュールスコープ)
FSM drawLives_fsm <- mkFSM(drawLives_org());
// “起動ラッパ”を元の名前に
function Stmt drawLives();
return (seq
`RUN_FSM(drawLives_fsm)
endseq);
endfunction
本体の関数名に_orgを付けるだけでロジックは変えません。元の関数名は起動マクロで本体を起動し終了待ちする関数に付け替えます。
以前作成したマクロは以下のとおりです。呼ぶ側で必ずseq/endseqで挟む必要があります。
`define RUN_FSM(F) action F.start(); endaction await(F.done);
以下に結果の表を示します。bsvソース量はほとんど変わらないので表示していません。bscの見る場合の数が減るためコンパイル時間がかなり減少し、物量も若干減少しています。
自機表示(drawLives())の最適化前後 | 前 | 後 | 比較 | |
---|---|---|---|---|
BSV合成 | コンパイル時間 | 1'54'' | 1'25'' | ▲25.4% |
Verilog合成 | ファイルサイズ[KB] | 7,509 | 5,924 | ▲21.1% |
合成時間 | 1'00'' | 0'51'' | ▲15% | |
Vivado LUT数 | 5,700 | 5,551 | ▲2.6% | |
Vivado FF数 | 1,794 | 1,790 | ▲0.2% |