Vivado上でシミュレーション(simulation)をしたい


目的(purpose)

今回、久々にzynqで遊んでみようと思います。
前に二つほど記事を書いているので良ければそちらも見てください。

久々にやるということで結構忘れていることが多かったので復習としてまとめてみました。
今回やるのはVivadoで作成したものをシミュレーションしてみるという内容です。
シミュレーションをうまく扱えるようになれば作成するたびにzynqで試すよりも効率良く開発できるようになります。


開発環境(Development environment)

OS:

  • Windows10 Home

ツール:

  • Vivado 2019.2
  • ZYBO Z7 (Zynq 7010)


まずはzynqについているledを1秒間隔で点滅させます。
点滅させるコードは前回と同様こちらの記事を参考に作成させていただきました。
※ 多少簡略化のためにコードを書き換えています


blink.v

`timescale 1ns / 1ps
module blink(
    input CLOCK,     
    output OUTPUT
);

parameter CNT_MAX = 27'd124999999;  // 1
// parameter CNT_MAX = 27'd125;    // 2
reg [26:0] cnt = 27'd0;  // 3
reg led = 1'd1;  // 4

always @(posedge CLOCK) begin
    if (cnt == CNT_MAX) begin
        cnt <= 27'd0;
        led <= ~led;
    end
    else begin
        cnt <= cnt + 27'd1;
    end
end

assign OUTPUT = led;  // 5

endmodule

  • 1, 2 :二つともledを点滅させるタイミングの基準となる定数です。
    1は実際にzynqで点滅させるときに1秒間隔で点けたり、消したりしたいため クロック数が125MHzということから125×10^6カウント(実際はカウントが0から始まるので1減らしています)で一区切りつけるようにしています。
    2はシミュレーション用で説明用の図を見やすくするために用いる数値です。
    1μ秒ごとに点けたり消したりさせます。(実際にledを点滅させても肉眼では認識できませんが……)
  • 3 : 点滅を任意の時間間隔で点滅させるためのカウンターです。
    always @(posedge CLOCK)の部分でクロックの波が立ち上がった時に毎回処理をするのでそのままledを点滅させると高速で点滅するので意味がありません。
  • 4 : 代入している数値が
    1'd1ですが、左の1はビット数を表しています。
    ledは今回一つだけ扱うため点く、消えるの2パターンのみです。1ビットで事足りるので1としています。dのアルファベットはdecimalつまり、10進数を表しています。
    右に書かれている1の数字が10進数表示です。
    その他2進数や16進数で表すこともできますが、とりあえず見慣れている10進数で書いています。
  • 5 : 最後、ledの状態を出力するために出力用のOUTPUTに繋げています。


テストベンチを作成する(Test bench)

シミュレーションをする前にテストベンチを作成します。
これは外部から入力される信号を模擬的に作り出し、blink.vに使用することでblink.vが狙い通りの動作をしているかを確認するためのコードです。

Flow NavigatorAdd Sourcesを選択

f:id:fetchkun:20200518183624p:plain

Add or create simulation sourcesを選択

f:id:fetchkun:20200518183640p:plain

Create File(下図の赤丸)をクリックすると、ソースファイルを作成するポップアップ画面が出る。
File nameに任意のファイル名を打ち込みOKを押す。
その後、Finish(緑丸)の部分を押す。

f:id:fetchkun:20200518183657p:plain

その後、下二つの画面が出ると思いますがそのままOK, Yesを押して完了してください

f:id:fetchkun:20200518183723p:plain

f:id:fetchkun:20200518183740p:plain


blink_tb.v

`timescale 1ns / 1ps  // 1
module blink_tb;

reg clk;
wire led;

blink test (
  .CLOCK(clk),  // 2
  .OUTPUT(led)  // 3
);

initial begin
  clk = 0;
  repeat(250000000) begin
    #4;  // 4
    clk = 1;
    #4;
    clk = 0;
  end
  $stop;
end

endmodule

  • 1, 4 : 1の設定により#4と書くことで、4ns(4×10^-9秒)経過するごとにclkに信号を流したり流さなかったりすることができる。
  • 2, 3 : ここの、CLOCKOUTPUTblink.v内で定義した変数です。それぞれclk, ledを割り振ることでblink_tb内での信号を送ることができます。


実際にシミュレーションをしてみる(Simulation)

f:id:fetchkun:20200518185146p:plain
上図の赤丸部分をクリックするとsimulationの画面に映ります。
その後、青丸の部分をクリックするとSIMULATION画面のObjectsにいくつか追加されます。

f:id:fetchkun:20200518185203p:plain
上図の赤丸部分を右の矢印部分にドラッグアンドドロップをすると表示することができます。

f:id:fetchkun:20200518185222p:plain
上図の赤丸を押すとシミュレーション画面がリロードされ追加したNameも反映されます。
緑の枠で囲まれた部分が今は2000nsまで表示されていますが、さらに続きが見たい場合は青丸の部分を操作し、▶(T)ボタンを押すことで続きがさらに表示されます。


f:id:fetchkun:20200518185259p:plain
上図の赤丸をクリックするとELABORATED DESIGNの画面が開きます。
青丸の部分をクリックするとFIND Resultsタブが追加され、緑の部分を設定します。
ピンの番号はボートに記載されていたり、digilentが出しているリファレンスマニュアルにも書いてあります。
reference.digilentinc.com

f:id:fetchkun:20200518185319p:plain
設定を保存するとxdcファイルが作成されます。

f:id:fetchkun:20200518185334p:plain
また上図のAdd Sourcesからでも作成できます。

f:id:fetchkun:20200518185349p:plain
上図のように選択し、Nextする。

f:id:fetchkun:20200518185404p:plain
create fileを押してファイル名を決めて進めると作成されます。

後は、Generate Bitstreamをして、Open Hardware Manager -> open target -> program deviceしていくと実行できますが、詳しくは下のURLを参考にしてください。
qiita.com


最後に(Finally)

今回、Vivadoでシミュレーションをしてみました。テストベンチを作成するときは最初どうしたら良いか分からなかったですが、さまざまな記事を参考にしたらできるようになりました。
この記事が少しでも役にたてれば幸いです。