Posts Tagged with "Vivado HLx"

既に発行済みのブログであっても適宜修正・追加することがあります。
We may make changes and additions to blogs already published.

オープニングアニメーション

posted by sakurai on June 9, 2021 #416

Youtube

この動画を観察すると、オープニングアニメーションの際に文字が一文字ずつ表示されているので、これを実装します。文字列は3つの部分から構成されています。

  • "PLAY SPACE INVADERS" --- 一文字ずつゆっくりと表示
  • "*SCORE ADVANCE TABLE *..." --- 一瞬で表示
  • "=? MYSTERY..." --- 一文字ずつゆっくりと表示

これを3つのカタマリとして、3つの表示ルーチンで表示します。最初と最後のルーチンは1文字表示するたびに8/60 sec(=133.3 msec)のウエイトを入れています。文字表示の間にsbuttonを見ているのは、スタートボタンにより、いつでもゲームを開始できるように割り込みを入れるためです。

function Stmt stringS1; // PLAY SPACE INVADERS
   return (seq
      for (str_idx <= 0; str_idx < 19; str_idx <=  str_idx + 1) seq
         copyArea(s1sx[str_idx], s1sy[str_idx], s1dx[str_idx], s1dy[str_idx], s1w[str_idx], s1h[str_idx]);
         wait_timer(`TICK_WAIT8);
         if (sbutton) break;
      endseq
   endseq);
endfunction

 function Stmt stringS2; // *SCORE ADVANCE TABLE* ...
    return (seq
      for (str_idx <= 0; str_idx < 23; str_idx <=  str_idx + 1) seq
         copyArea(s2sx[str_idx], s2sy[str_idx], s2dx[str_idx], s2dy[str_idx], s2w[str_idx], s2h[str_idx]);
      endseq
   endseq);
endfunction

function Stmt stringS3; // =? MYSTERY ...
   return (seq
      for (str_idx <= 0; str_idx < 40; str_idx <=  str_idx + 1) seq
         copyArea(s3sx[str_idx], s3sy[str_idx], s3dx[str_idx], s3dy[str_idx], s3w[str_idx], s3h[str_idx]);
         wait_timer(`TICK_WAIT8);
         if (sbutton) break;
      endseq
   endseq);
endfunction

左矢前のブログ 次のブログ右矢

ソフトブロック解説 (5)

posted by sakurai on June 8, 2021 #415

sound階層

サウンド階層には4つの独立したサウンドステートマシンの他、サウンドミキサーやパラシリモジュールが存在します。4つの独立したサウンドステートマシンにより、同時に4音の発声が可能となっています。

図%%.1
図415.1 sound階層

サウンドステートマシンサブ階層

図415.2にサウンドステートマシンサブ階層を示します。このステートマシンが4チャネルあります。

  • mkSoundFSMモジュール --- サウンドROMを読み出すステートマシンであり、それをミキサーに出力する (BSV⇒Verilog)
  • サウンドROM --- Waveフォーマットデータを格納するROM (Xilinx IP)

図%%.2
図415.2 soundFSM階層

ミキサー&パラシリモジュール

  • ミキサーモジュール --- 4個の独立したサウンドFSMからの音データを加算し重畳する (Verilog)
  • パラシリモジュール --- ミックス後のパラレルデータをシリアルに変換し、シリアルDACに出力する (Verilog)

図%%.3
図415.3 ミキサー&パラシリ階層

コマンドバッファサブ階層

最後にコマンドバッファサブ階層を示します。

  • コマンドバッファ(OneStage) --- GameFSMとSoundFSMの間でコマンドを受け渡す (Verilog)

図%%.4
図415.4 コマンドバッファ階層

左矢前のブログ 次のブログ右矢

ソフトブロック解説 (4)

posted by sakurai on June 7, 2021 #414

graphics階層

基本的にはgraphic_controlモジュールが中心となる階層です。次の3つのモジュールから構成されています。

  • graphic_controlモジュール --- クロックとリセットを入力し、HS, VS, DT等のグラフィックディスプレイタイミングやVRAMアドレスを生成するモジュール (Verilog)
  • xslice --- VRAMデータ中のRGB成分のみを抜き出す (Xilinx IP)。VRAMはRGBの他にもう一面持っており、その面にはシールドデータのみが描画されています。しかしながら、その面は表示はされません。この情報は、自弾及び敵弾の衝突判定に用います。これによりシールドをピクセル毎に破壊することができます。

    図%%.1
    図414.1 ピクセル毎の衝突判定
  • display_outモジュール --- ディスプレイタイミング時に表示データを出力し、さらに爆発信号EXPにより全面赤表示にするモジュール (Verilog)

図%%.2
図414.2 graphics階層

左矢前のブログ 次のブログ右矢

ソフトブロック解説 (3)

posted by sakurai on June 4, 2021 #413

VRAM階層

VRAM階層は、図413.1で示すように以下の2モジュールから構成されます。

  • VRAM --- 256×256×4bitのデュアルポートメモリ (Xilinx IP)
  • Muxモジュール --- メモリダンプモジュールからのアドレスをマルチプレクスする (BSV⇒Verilog, 過去記事で設計)

図%%.1
図413.1 VRAM階層

左矢前のブログ 次のブログ右矢

ソフトブロック解説 (2)

posted by sakurai on June 3, 2021 #412

invader階層

引き続きinvader階層です。これはインベーダゲームの中心となる、GameFSM(invader_move)を含む階層です。基本的には、

  • GameFSMモジュール --- ゲームのシナリオを実行するFSM (BSV⇒Verilog)
  • パターンROM --- インベーダその他のビットマップを格納するROM (Xilinx IP)

の2つのモジュールにより、VRAMをR/Wすることにより絵を動かしています。この階層には、さらに以下のモジュールが存在します。

  • buttonsモジュール --- FPGAボード上のプッシュボタンと、PMODのジョイスティックインタフェースのOR取り (Verilog)

図%%.1
図412.1 invader階層

左矢前のブログ 次のブログ右矢

ソフトブロック解説

posted by sakurai on June 2, 2021 #411

ソフトブロック解説

ここから、簡単に各ソフトブロック階層の解説をします。全体ブロック図は過去記事に挙げてあります。全体ブロック図において、左から順に、clock階層、メモリダンプモジュール(ソフトブロック階層無し)、invader階層、VRAM階層、graphics階層、sound階層となっています。

clock階層

図411.1にclock階層の構造を示します。使用されているモジュールは全てXilinx IPです。

図%%.1
図411.1 clock階層
入力は
  • sys_clock --- 100MHzクロック
  • reset --- 負論理リセット

の2本です。出力は、

  • C921_6KHz --- 921.6KHzクロックであり、UARTのボーレートクロック
  • C60Hz --- 60Hzクロックであり、動画の1フレーム(tick)を決める基準クロック
  • C2MHz_FSMCLK --- 文字通り2MHzのFSMクロック
  • MCLK --- 11.289MHzクロックであり、サウンド用のマスタークロック
  • C40MHz --- 40MHzクロックであり、グラフィックのドットクロック
  • locked --- 負論理のリセット信号

バイナリカウンタ説明

  • c_counter_binary_0 --- clk_wizからの8MHzクロックを入力し、bit0(4MHz)、bit1(2MHz)、bit2(1MHz)と分周する。xslice_0はそのbit1(2MHz)を取り出し、C2MHz_FSMCLKとして出力する。
  • c_counter_binary_1 --- c_counter_binary_0からxslice_2はそのbit2(1MHz)を取り出し、c_counter_binary_1で0x411a(=16666)を計数したらリセットする。xslice_1ではその14bit(16.667msec=59.9988Hz)を取り出し、C60Hzとして出力する。これはデューティは50%ではないが、エッジを見るため問題ない。
  • c_counter_binary_2 --- clk_wizからの7.3728MHzクロックを入力し、bit0(3.6864MHz)、bit1(1.8432MHz), bit2(921.6KHz)と分周する。xslice_3はそのbit2(921.6KHz)を取り出しC921_6KHzとして出力する。

左矢前のブログ 次のブログ右矢

QSPI Flashへの書き込み

posted by sakurai on June 1, 2021 #410

QSPIへの再書き込み

Artyボードにおいて、基本的には過去記事で示した手順でFlashに書き込みます。ところが、一度Flashに書き込むと、Add Configuration Memory Deviceがグレーアウトされていることがあります。その場合は、

図%%.1
図410.1

このように、JTAGのデバイスを右クリックすると、メニューが現れるので、Program Configuration Memory Deviceをクリックします。すると次の画面が出るので、デバイスを選択し、プログラミングします。

図%%.2
図410.2

左矢前のブログ 次のブログ右矢

Space Invadersの構成と物量

posted by sakurai on May 31, 2021 #409

ブロック図

ブロック図をIP Integratorで示します。

図%%.1
図409.1 ブロック図

リソース使用量

各階層(ソフトブロック)のリソース使用量を図409.2に示します。

図%%.2
図409.2 リソース使用量

表409.1に示すように、BRAMの割合がかなり大きいです。全部で50個中、39.5個を使用しています。

表409.1
リソース 割合[%]
MMCM 20
BUFG 25
I/O 16
BRAM 79
FF 6
LUT 36

モジュール配置

各階層の配置状況を図409.3に示します。おもしろいことに、サウンドが4つのまとまりに分かれていますが、図409.4のように4つのステートマシン毎に固まっていました。

図%%.3
図409.3 モジュール配置図

図%%.4
図409.4 サウンド関係配置図

左矢前のブログ 次のブログ右矢

BSVによる歩行音の改善

posted by sakurai on May 28, 2021 #408

インベーダの歩行音

インベーダの歩行音は、現在は隊列に同期して出力されます。インベーダ一匹の歩行処理は60Hzで実施されるため、初期状態では55/60secに一度、最後の一匹では1/60secに一度歩行音が出力されます。

最後の一匹の時に、どうも歩行音が速すぎると思っていたら、過去記事のとおり、インベーダの数に応じた間隔で歩行音が出力され、必ずしも隊列の動作とは同期していないことが判明しました。アニメーションは、インベーダーの数に比例して徐々に速くなるのに比べ、サウンドは段階的に速くなるのは、どのような意図があるのでしょうか?

なるべくオリジナルに近づけるという方針から、今回はこれを実装します。

歩行音間隔タイマの実装

まず、過去記事の表を実装します。タイマ初期値の最大値は52なので6bitのレジスタが55個必要です。1から55までを使用しており、0を含めた56個を定義しています。

UInt#(6) inv_init_stimer[56] = {5, 5, 7, 9,11,12,13,14,16,16,19,19,19,21,21,21,21,24,24,24,
                         24,24,28,28,28,28,28,28,34,34,34,34,34,34,34,34,39,39,39,39,
                         39,39,39,46,46,46,46,46,46,46,52,52,52,52,52,52};

過去記事の歩行音間隔タイマの仕様に示すように、これはタイムアウトした際に、インベーダ数に応じた値でタイマを初期化するための表です。次に、歩行音間隔タイマ本体を実装します。

Reg#(UInt#(6)) inv_stimer <- mkRegU;

次に、サウンドパターンは4から7を繰り返すため、2bitのパターンレジスタを用意します。

Reg#(UInt#(2)) inv_spattern <- mkRegU;

初期化部分です。タイマの初期値は52とします。パターンの初期値は0とします。

        inv_stimer <= 52;
        inv_spattern <= 0;

隊の先頭で実施していた次のサウンド出力処理を削除します。

//          if (inv_ido != END_STATE) seq
//                sound(extend(inv_pattern) + 4); // from 4 to 7
//          endseq

その代わり、 全てのインベーダについて次の処理を追加します。

     // 全てのインベーダについて処理
     if (inv_stimer == 0) seq
           sound(extend(inv_spattern) + 4); // from 4 to 7
           inv_spattern <= inv_spattern + 1;
           inv_stimer <= inv_init_stimer[inv_no];
     endseq else seq
           inv_stimer <= inv_stimer - 1;
     endseq

これにより過去記事のような動作を行うはずです。⇒実施したところ、正しく動作したようです。


左矢前のブログ 次のブログ右矢

posted by sakurai on May 27, 2021 #407

受信したデータは以下の図に示すように、一文字4bitのデータが連続する、VRAM内容を示すログデータです(右側を一部省略)。

図%%.1
図407.1 受信データ(部分)

VRAMデータ4bitの意味は以下のとおりです。

  • bit3: バリケード(シールド)=非画像情報
  • bit2: R=画像情報
  • bit1: G=画像情報
  • bit0: B=画像情報

従って、非画像情報を無視し、次のコードにより画像フォーマットであるPPMに変換します。

log2ppm.c

#include <stdio.h>
void main() {
      char line[4096];
      char ch;
      printf("P3\n256 256\n255\n");
      for(int y = 0; y <= 255; y++) {
            fgets(line, sizeof(line), stdin);
            for(int x = 0; x <= 255; x++) {
                  ch = line[x] - 0x30;
                  if ((ch & 0x4) != 0) printf("255 ");    // R
                  else printf("0 ");
                  if ((ch & 0x2) != 0) printf("255 ");    // G
                  else printf("0 ");
                  if ((ch & 0x1) != 0) printf("255 ");    // B
                  else printf("0 ");
            }
            printf("\n");
      }
}

以下のコマンドによりフィルタを作成します。

$ gcc -O log2ppm.c -o log2ppm

上記のようにフィルターとして実行し、ログデータを画像ファイルに変換します。

$ ./log2ppm <putty.log >putty.ppm

生成されたファイルを画像処理ツールであるgimp2で開くと以下のように正常に受信されています。

図%%.2
図407.2 受信画像

以上で、ゲームのメモリダンプ機能がひとおおり完成しました。ゲームの状態を吸い出したのは、これをオートエンコーダによりCNNに認識させるのを目的としています。


左矢前のブログ 次のブログ右矢


ページ: