|
11 |
GameFSMの改良 (23) |
対応するコードを示します。まず、前景は各色1bitカラー$(g, r, b)$で元と変わりません。
Bit#(1) fg_g1 = !in_exp ? (in_data[2] & pack(fg_dt)) : 1'b0;
Bit#(1) fg_r1 = !in_exp ? (in_data[1] & pack(fg_dt))
: ((in_data[2] | in_data[1] | in_data[0]) & pack(fg_dt));
Bit#(1) fg_b1 = !in_exp ? (in_data[0] & pack(fg_dt)) : 1'b0;
これに4bitの背景を重ね合わせます。背景は$(g_3, g_2, g_1, g_0, r_3, r_2, r_1, r_0, b_3, b_2, b_1, b_0)$の各色4bitカラーです。ただし前稿のとおり、$g_3=r_3=b_3=0$であることからデータは省略でき、3bitずつROMに格納します。
// 背景 GRB333(9bit)
Bit#(3) bg_g3 = bg_data[8:6];
Bit#(3) bg_r3 = bg_data[5:3];
Bit#(3) bg_b3 = bg_data[2:0];
そこからスキャンのタイミングでこのように各色3bitずつ9bitを取り出します。
// 3bit → 4bit (MSB=0 を付加)
Bit#(4) bg_g4 = { 1'b0, bg_g3 };
Bit#(4) bg_r4 = { 1'b0, bg_r3 };
Bit#(4) bg_b4 = { 1'b0, bg_b3 };
次にこのようにMSBに0を詰めて各色4bitとします。
// 背景無効領域は完全黒
Bit#(4) pix_g4 = bg_active ? mixPx(bg_g4, fg_g1) : 4'b0000;
Bit#(4) pix_r4 = bg_active ? mixPx(bg_r4, fg_r1) : 4'b0000;
Bit#(4) pix_b4 = bg_active ? mixPx(bg_b4, fg_b1) : 4'b0000;
前景と背景をブレンドしてdisplay timingでレターボックス化します。以下は前景と背景の合成関数です。
// 背景4bit bg4 と 1bit 前景 fg1 を合成
// 前景の足し込み量は 4'hC 固定(強すぎれば 8〜F で調整)
function Bit#(4) mixPx(Bit#(4) bg4, Bit#(1) fg1);
UInt#(4) ubg = unpack(bg4);
// fg1 が 0 のとき 0000, 1 のとき 1111
Bit#(4) add_b = 4'hC & { fg1, fg1, fg1, fg1 };
UInt#(4) uadd = unpack(add_b);
UInt#(5) sum = zeroExtend(ubg) + zeroExtend(uadd);
UInt#(4) out4 = (sum > 15) ? 15 : truncate(sum);
return pack(out4);
endfunction
図1048.1に完成結果を示します。実際には動画で見るより背景画像は暗くなっており、ゲームの邪魔になることはありません。

記事タイトルはGameFSMの改良ですが、実際に背景画像や星の点滅はGraphicsFSMというグラフィックコントローラに実装しました。背景画像が結構ROMを食うため、Arty 7-35Tでは入らず、Arty 7-100Tでなければ入りませんでした。