FC2カウンター FPGAの部屋 アサーション事始め

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

ISimでOVL V2.6を使用したシミュレーション(OVLライブラリのコンパイルと登録)

AXI4バスのBFMにデータ転送時にランダムなWaitを挟む機能を追加した。これをループさせてバグを検出したいのだが、シミュレーション波形を目で見ていると、とっても大変なので、OVL(Open Verification Language? Open Verification Library?)を使用して動作をチェックすることにした。なお、OVLの最新バージョンVer. 2.6 はここからダウンロードすることができる。

FPGAの部屋のOVLの資料を以下に示す。
アサーション事始め
ISimでOVLのVHDL, Verilog混在シミュレーション(OVLライブラリのコンパイルと登録)
ISimでOVLのVHDL, Verilog混在シミュレーション(ISimでシミュレーション)

ISimでOVLのシミュレーションを行うためには、OVLライブラリをコンパイルして、ライブラリに登録する必要がある。そのため、OVLの各チェッカをコンパイルするためにバッチを自作してある。そのための方法が”ISimでOVLのVHDL, Verilog混在シミュレーション(OVLライブラリのコンパイルと登録)”に書いてある。バッチファイルは、OVLチェッカの位置をフルパスで書いてあるので、それを変更してからISE13.4のコンパイラでコンパイルを行った。
下に手順を示す。

1.スタートメニュー -> アクセサリ -> コマンド プロンプトを立ち上げる。

2.ISE13.4のインストールフォルダに行って、13.4\ISE_DSフォルダの中の settings32.bat(Windows 64ビット版の場合はsettings64.bat)を実行する。
ISim_OVL_Sim_1_120309.png

3.OVL_Verilog_Lib_Comp.batとOVL_VHDL_Lib_Comp.bat の入っているフォルダに移動する。

4.OVL_Verilog_Lib_Comp.batを実行する。
ISim_OVL_Sim_2_120309.png

5.コンパイルが終了した。
ISim_OVL_Sim_3_120309.png

6.前回同様、isimフォルダに下にaccellera_ovl_vlog フォルダが出来て、Verilogのコンパイル済みのライブラリができた。
ISim_OVL_Sim_4_120309.png

7.OVL_VHDL_Lib_Comp.batを実行した。
ISim_OVL_Sim_5_120309.png

8.前回同様、isimフォルダに下にaccellera_ovl_vhdl フォルダが出来て、VHDLのコンパイル済みのライブラリができた。
ISim_OVL_Sim_6_120309.png

*コンパイルした2つのライブラリをISimに登録する。

9.Xilinx\13.4\ISE_DS\ISE\verilog\hdp\ntフォルダに、accellera_ovl_vlog フォルダをコピーする。
ISim_OVL_Sim_7_120309.png

10.Xilinx\13.4\ISE_DS\ISE\vhdl\hdp\ntフォルダに、accellera_ovl_vhdl フォルダをコピーする。
ISim_OVL_Sim_8_120309.png

11.Xilinx\13.4\ISE_DS\ISE\vhdl\hdp\ntフォルダに、xilinxsim.iniがあるので、これをエディタで開く。

12.accellera_ovl_vlog=$XILINX/verilog/hdp/nt/accellera_ovl_vlog と accellera_ovl_vhdl=$XILINX/vhdl/hdp/nt/accellera_ovl_vhdl の行を追加した。
ISim_OVL_Sim_9_120309.png

これで、accellera_ovl_vlogとaccellera_ovl_vhdlライブラリがISimで使用できるようになった。
  1. 2012年03月09日 05:12 |
  2. アサーション事始め
  3. | トラックバック:0
  4. | コメント:0

ArbiterのアサーションをOVLに変更

昨日、FPGA-CAFEでSCCBの配線をハンダ付けしてきたので、SCCBを追加するつもりなのだけれど、その前に、以前に”Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路6(シミュレーション2)”で書いたArbiterのVerilogアサーションをOVLにしてみた。

アドレスが4増加しているアサーションにovl_transitionを使おうと思ったのだが、どうもうまく行かなかった。結局、enableに条件を入れて、ovl_alwaysを使うことにした。なかなかいろいろなアサーションのうちどれを使うかが難しい。次は、DDR2 SDRAMコントローラにアサーションを入れる予定なので、その時にはいろいろなOVLアサーションを使えると期待している。
下に、ArbiterのOVLアサーションを示す。

    // アサーション
    // synthesis translate_off
    always @ (posedge clk_ddr2) begin
        if (reset_ddr2) begin
            camc_addr_1d <= 0;
            vgadc_addr_1d <= 0;
            addr_assertion_valid <= 1'b0;
        end else begin
            if (ddr2_addr_we) begin
                camc_addr_1d <= camc_addr;
            end
            if (vgadc_addr_we) begin
                vgadc_addr_1d <= vgadc_addr;
            end
            if (ddr2_addr_we || vgadc_addr_we) begin
                addr_assertion_valid <= 1'b1;
            end
        end
    end
    
    // Camera_Controller が有効の時にVGA_Display_Controller がライトしないことをチェックするOVLアサーション
    ovl_never #(`OVL_ERROR, `OVL_ASSERT, "ERROR : Camera_Controller が有効の時にVGA_Display_Controller がライトした", `OVL_COVER_DEFAULT, `OVL_POSEDGE, `OVL_ACTIVE_HIGH, `OVL_GATE_CLOCK) camc_vga_we_assertion (clk_ddr2, reset_ddr2, 1'b1, (cs_abt==CAMC_Grant || cs_abt==VGADC_Wait) && vgadc_addr_we, fire_camc_vgac);
    
    // 現在のCamera_Controller からのWrite Addressが以前のWrite Addressの+4かどうかをチェックするOVLアサーション
    ovl_always #(`OVL_ERROR, `OVL_ASSERT, "ERROR : 以前のcamc_addr から+4されていない", `OVL_COVER_ALL, `OVL_POSEDGE, `OVL_ACTIVE_HIGH, `OVL_GATE_CLOCK) camc_addr_assertion (clk_ddr2, reset_ddr2, camc_addr>=4 && (cs_abt==CAMC_Grant || cs_abt==VGADC_Wait) && ddr2_addr_we , camc_addr_1d+4==camc_addr, fire_camc_addr);
    
    // VGA_Display_Controller が有効の時にCamera_Controller がライトしないことをチェックするOVLアサーション
    ovl_never #(`OVL_ERROR, `OVL_ASSERT, "ERROR : VGA_Display_Controller が有効の時に、camc_addr_ena, camc_data_ena が1になった", `OVL_COVER_DEFAULT, `OVL_POSEDGE, `OVL_ACTIVE_HIGH, `OVL_GATE_CLOCK) vgac_camc_we_assertion (clk_ddr2, reset_ddr2, 1'b1, (cs_abt==VGADC_Grant || cs_abt==CAMC_Wait) && (ddr2_addr_we || ddr2_addr_we), fire_vgac_camc);
    
    // 現在のVGA_Display_Controller からのRead Addressが以前のRead Addressの+4かどうかをチェックするOVLアサーション
    ovl_always #(`OVL_ERROR, `OVL_ASSERT, "ERROR : 以前のvgadc_addr から+4されていない", `OVL_COVER_ALL, `OVL_POSEDGE, `OVL_ACTIVE_HIGH, `OVL_GATE_CLOCK) vgadc_addr_assertion (clk_ddr2, reset_ddr2, vgadc_addr>=4 && (cs_abt==CAMC_Grant || cs_abt==VGADC_Wait) && ddr2_addr_we , vgadc_addr_1d+4==vgadc_addr, fire_vgac_addr);
    
    // Camera_Controller がFIFOがフルの時に書き込んでいるか?をチェックするアサーション
    ovl_never #(`OVL_ERROR, `OVL_ASSERT, "ERROR : アドレスFIFOがフルの時にCamera_Controller が書き込んだ", `OVL_COVER_DEFAULT, `OVL_POSEDGE, `OVL_ACTIVE_HIGH, `OVL_GATE_CLOCK) camc_addr_full_we_assertion (clk_ddr2, reset_ddr2, 1'b1, ddr2_addr_we && ddr2_addr_fifo_full, fire_camc_addr_overflow);
    ovl_never #(`OVL_ERROR, `OVL_ASSERT, "ERROR : データFIFOがフルの時にCamera_Controller が書き込んだ", `OVL_COVER_DEFAULT, `OVL_POSEDGE, `OVL_ACTIVE_HIGH, `OVL_GATE_CLOCK) camc_data_full_we_assertion (clk_ddr2, reset_ddr2, 1'b1, ddr2_data_we && ddr2_wrdata_fifo_full, fire_camc_data_overflow);
    
    // VGA_Display_Controller がFIFOがフルの時に書き込んでいるか?をチェックするアサーション 
    ovl_never #(`OVL_ERROR, `OVL_ASSERT, "ERROR : アドレスFIFOがフルの時にVGA_Display_Controller が書き込んだ", `OVL_COVER_DEFAULT, `OVL_POSEDGE, `OVL_ACTIVE_HIGH, `OVL_GATE_CLOCK) vgadc_data_full_we_assertion (clk_ddr2, reset_ddr2, 1'b1, vgadc_addr_we && ddr2_addr_fifo_full, fire_vgadc_addr_overflow);
    // synthesis translate_on


残念ながら、全部OVLアサーションではできなくて、camc_addr_1dとvgadc_addr_1dをVerilogで作っている。
OVL_assertion_1_100906.png

fire...信号がすべて0でアサーションが発火していないことを示す。
ここで、2番目のovl_alwaysアサーションの camc_addr_1d+4==camc_addr を camc_addr_1d+3==camc_addr に変更して、もう一度シミュレーションを行った。シミュレーション結果を下に示す。
OVL_assertion_2_100906.png

fire_camc_addr が途中で1になったのがわかる。その部分を拡大してみる。
OVL_assertion_3_100906.png

camc_addrが0から4になる時が、アサーションエラーだ。わざとアサーションエラーを出した。うまく動いているようだ。
  1. 2010年09月06日 04:56 |
  2. アサーション事始め
  3. | トラックバック:0
  4. | コメント:0

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路でのOVLアサーション1

Spartan-3A Starter KitでCMOSカメラ・ディスプレイ回路6(シミュレーション2)”でVerilogで書いたアサーションをOVLに書きなおしてみたいという希望を書いたが、実際にOVLアサーションに書きなおしてみることにした。
OVLについては、私のブログのまとめサイトアサーション事始めを参照のこと。
AccelleraのOVL(Open Verification Library)のダウンロードサイトに行くと、Ver.2.5が出ていたので、これをダンロードしてから始めると良いと思う。

まずはVGA_Display_Controllerから、VerilogアサーションをOVLに変更してみる。ここでのアサーションは下のように非同期FIFOのoverflowとunderflowを検出するアサーションだ。

    // アサーション
    // synthesis translate_off
    always @ (posedge clk_ddr2) begin
        if (reset_ddr2)
            ;
        else begin
            if (afifo_overflow) begin 
                $display("%m: at time %t ERROR : FIFOがフルなのにライトした",$time);
                $stop;
            end
        end
    end
    always @(posedge clk_cam) begin
        if (reset_cam)
            ;
        else begin
            if (afifo_underflow) begin
                $display("%m: at time %t ERROR : FIFOが空なのにリードした",$time);
                $stop;
            end
        end
    end
    // synthesis translate_on


これを、OVLに変更するために、ovl_never を使用し、以下のように変更した。

// synthesis translate_off
`include "std_ovl_defines.h" // std_ovl_defines.hをインクルード
// synthesis translate_on

...............

    // synthesis translate_off
    wire [`OVL_FIRE_WIDTH-1:0] fire_overflow, fire_underflow; // fire用の信号を定義
    // synthesis translate_on

    ...............
    
    // synthesis translate_off
    ovl_never #(
        `OVL_ERROR,            // severity_level
        `OVL_ASSERT,        // property_type
        "ERROR : FIFOがフルなのにライトした", // msg
        `OVL_COVER_DEFAULT,    // coverage_level
        `OVL_POSEDGE,        // clock_edge
        `OVL_ACTIVE_HIGH,    // reset_polarity
        `OVL_GATE_CLOCK    // gating_type
    ) afifo_overflow_assertion (
        clk_ddr2,
        reset_ddr2,
        1'b1,
        afifo_overflow,
        fire_overflow
    );
        
    ovl_never #(
        `OVL_ERROR,            // severity_level
        `OVL_ASSERT,        // property_type
        "ERROR : FIFOが空なのにリードした", // msg
        `OVL_COVER_DEFAULT,    // coverage_level
        `OVL_POSEDGE,        // clock_edge
        `OVL_ACTIVE_HIGH,    // reset_polarity
        `OVL_GATE_CLOCK    // gating_type
    ) afifo_underflow_assertion (
        clk_cam,
        reset_cam,
        1'b1,
        afifo_underflow,
        fire_underflow
    );
    // synthesis translate_on


最初にstd_ovl_defines.hをインクルードする。次にfire用の信号を宣言する。その次にovl_neverを書いた。”OVL(Open Verification Library)を試してみる7(OVLチェッカの概要)”を引用する。

ovl_never : test_exprが決して真にならないことをチェックする。例えば、サイコロの値をdice_cntとすると、test_exprはdice_cnt>6と表される。dice_cntが7以上になればアサーション・エラーとなる


詳しくは(OVLの使い方や値の意味は)、OVLをダウンロードして、解凍したファイルのstd_ovl\docs\pdfdocsの下のovl_lrm.pdf(Accellera Standard OVL V2 Library Reference Manual)を見てもらうとわかると思う。

最初のパラメータ (severity_level) の`OVL_ERRORは、重要性のレベルでアサーションエラーだとERRORを出力する。“severity level”には、OVL_FATAL、OVL_ERROR、OVL_WARNING、OVL_INFOがあるそうだ(Accellera Standard OVL V2 Library Reference Manual参照、以下略)。

2番目 (property_type) の`OVL_ASSERTは、assertやassumeのプロパティだ。OVL_ASSERTはX/Zのチェックを含んだassert。OVL_ASSERT_2STATEは、X/Zのチェックを無視したassert。後は、OVL_ASSUME、OVL_ASSUME_2STATE がある。

3番目 (msg) は、アサーションエラーの時のメッセージ。

4番目 (coverage_level) は、coverage_level。`OVL_COVER_DEFAULTは、std_ovl_defines.hで OVL_COVER_BASICと定義されている。これをOVL_COVER_CORNERにすると、ovl_rangeで、min値とmax値になったときに”OVL_COVER_POINT : OVL_RANGE ”が表示される。
OVL_COVER_SANITY はチェックしている値が変化したときに、”OVL_COVER_POINT : OVL_RANGE ”が表示される。
後は、OVL_COVER_STATISTIC、OVL_COVER_NONE、OVL_COVER_ALL がある。

5番目 (clock_edge) は、クロックエッジで立ち上がりでチェックするか(OVL_POSEDGE)、立ち上がりでチェックするか(OVL_NEGEDGE)。

6番目 (reset_polarity) は、リセットの極性。アクティブハイ(OVL_ACTIVE_HIGH)か、アクテイブロー(OVL_ACTIVE_LOW)

7番目 (gating_type) は、enableに対してどう振舞うかを表す。OVL_GATE_CLOCKの場合はenableがFALSEの場合はチェックを停止し、なにもしない。カウンタや初期値は変更されない。
OVL_GATE_NONEの場合はenableを無視する。OVL_GATE_RESETの場合はenableがFALSEの場合はリセットする。

今度は信号の方で、最初の clk_cam は、アサーションのためのクロック。

2番目の reset_cam は同期リセット。

3番目の 1'b1 は、enableで、パラメータの7番目のgating_typeに関連する。

4番目の afifo_overflow は、チェックの条件だ。ここがTUREになると、パラメータの3番目のメッセージが出力される。

5番目の fire_overflow は、3ビット幅のfireで、ビット0はアサーションが失敗した時に1になる。ビット1はX/Zチェックが失敗した時に1になる。ビット2はCoverイベントがあったときに1になる。

さて、OVLをシミュレーションしてみよう。”OVL(Open Verification Library)を試してみる2(Veritakを使用する)”で行ったように、Defineが必要になる。

-Define OVL_VERILOG
-Define OVL_INIT_MSG
-Define OVL_COVER_ON
-Define OVL_ASSERT_ON
-Define OVL_MAX_REPORT_ERROR=1


上に示すDefineを行った。このうち必須なのは、OVL_ASSERT_ONとOVL_COVER_ONかな?
次に、std_ovl フォルダをincludeフォルダとして登録した。ライブラリフォルダとしても登録した。

-include_dir ../../../../OVL/std_ovl
-lib_dir ../../../../OVL/std_ovl


OVL Ver.2であれば、

-lib_ext vlib

は必要ない。
これで準備OKなので、Veritak-Basic Ver.3.80Dで、コンパイルしてシミュレーションしてみた。下がその結果だ。
OVL_1_100822.png

2つのfireは、ずっと発火しないまま、つまりエラーがでない状況だ。これは良いことなのだが、fireが発火するシミュレーションが、”OVL(Open Verification Library)を試してみる4(OVL_range)”にあるので参照のこと。
  1. 2010年08月21日 05:54 |
  2. アサーション事始め
  3. | トラックバック:0
  4. | コメント:0

VHDLでOVLアサーションを使用する3(VHDLからVerilog OVLを使用する)

VHDLでOVLアサーションを使用する2(VHDLライブラリを使用)”でVHDL OVLを使用したが、今度はVerilogのOVLを使用して、VHDLソースにOVLアサーションを挿入しようと思う。前回のOVLアサーションはovl_nextだけだったが、Verilog OVLにしかないovl_frameを使用する。

proj_pkg.vhd, req_sm.vhd, ack_sm は”VHDLでOVLアサーションを使用する2(VHDLライブラリを使用)”と同じだ。
テストベンチのtb_req_ack.vhd を示す。

-- tb_req_ack.vhd
-- OVL_Verilogアサーションを使用する

-- tb_req_ack.vhd本体
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
library accellera_ovl_vhdl;
use accellera_ovl_vhdl.std_ovl.all;
use accellera_ovl_vhdl.std_ovl_procs.all;
-- use accellera_ovl_vhdl.std_ovl_components.all;
library accellera_ovl_vlog;
use accellera_ovl_vlog.all; -- ovl_frameをuse
library work;
use work.proj_pkg.all;

entity tb_req_ack is
end tb_req_ack;

architecture testbench_arch of tb_req_ack is
component ack_sm
    port(
        clk : in std_logic;
        reset : in std_logic;
        req0 : in std_logic;
        req1 : in std_logic;
        ta0 : in std_logic; -- Transfer Acknowledge
        ta1 : in std_logic; -- Transfer Acknowledge
        ack0 : out std_logic;
        ack1 : out std_logic
    );
end component;
component req_sm
    port(
        clk : in std_logic;
        reset : in std_logic;
        req_start : in std_logic;
        ack : in std_logic;
        req : out std_logic
    );
end component;
  component ovl_next
    generic (
      severity_level      : ovl_severity_level := OVL_SEVERITY_LEVEL_NOT_SET;
      num_cks             : positive           := 1;
      check_overlapping   : ovl_chk_overlap    := OVL_CHK_OVERLAP_OFF;
      check_missing_start : ovl_ctrl           := OVL_OFF;
      property_type       : ovl_property_type  := OVL_PROPERTY_TYPE_NOT_SET;
      msg                 : string             := OVL_MSG_NOT_SET;
      coverage_level      : ovl_coverage_level := OVL_COVERAGE_LEVEL_NOT_SET;
      clock_edge          : ovl_active_edges   := OVL_ACTIVE_EDGES_NOT_SET;
      reset_polarity      : ovl_reset_polarity := OVL_RESET_POLARITY_NOT_SET;
      gating_type         : ovl_gating_type    := OVL_GATING_TYPE_NOT_SET;    
      controls            : ovl_ctrl_record    := OVL_CTRL_DEFAULTS
    );
    port (
      clock               : in  std_logic;
      reset               : in  std_logic;
      enable              : in  std_logic;
      start_event         : in  std_logic;
      test_expr           : in  std_logic;
      fire                : out std_logic_vector(OVL_FIRE_WIDTH - 1 downto 0)
    );
  end component ovl_next;
  component ovl_frame
    generic (
      severity_level       : ovl_severity_level      := OVL_SEVERITY_DEFAULT;
      min_cks              : natural                 := 0;
      max_cks              : natural                 := 0;
      action_on_new_start  : natural                 := OVL_ACTION_ON_NEW_START_DEFAULT;
      property_type        : ovl_property_type       := OVL_PROPERTY_DEFAULT;
      msg                  : string                  := OVL_MSG_DEFAULT;
      coverage_level       : ovl_coverage_level      := OVL_COVER_DEFAULT;
      clock_edge           : ovl_active_edges        := OVL_CLOCK_EDGE_DEFAULT;
      reset_polarity       : ovl_reset_polarity      := OVL_RESET_POLARITY_DEFAULT;
      gating_type          : ovl_gating_type         := OVL_GATING_TYPE_DEFAULT;
      controls             : ovl_ctrl_record         := OVL_CTRL_DEFAULTS
    );
    port (
      clock                : in  std_logic;
      reset                : in  std_logic;
      enable               : in  std_logic;
      start_event          : in  std_logic;
      test_expr            : in  std_logic;
      fire                 : out std_logic_vector(OVL_FIRE_WIDTH - 1 downto 0)
    );
  end component ovl_frame;

signal clk : std_logic := '1';
signal reset : std_logic := '1';
signal req_start0 : std_logic := '0';
signal req_start1 : std_logic := '0';
signal req0 : std_logic := '0';
signal req1 : std_logic := '0';
signal ta0 : std_logic := '0';
signal ta1 : std_logic := '0';
signal ack0 : std_logic := '0';
signal ack1 : std_logic := '0';
signal fire_ta0_ack0_as, fire_ta1_ack1_as : std_logic_vector(OVL_FIRE_WIDTH - 1 downto 0);
signal fire_req0_ack0_as, fire_req1_ack1_as : std_logic_vector(OVL_FIRE_WIDTH - 1 downto 0);

constant PERIOD : time := 20 ns;
constant DUTY_CYCLE : real := 0.5;

-- req_startとtaを出力するprocedure
procedure REQ_START_TA(
    signal clk : in std_logic;
    loop_count : in integer;
    signal req_start : out std_logic;
    signal ta : out std_logic
) is
begin
    wait until clk'event and clk='1'; -- clkの立ち上がりまでwait
    wait for 1 ns; -- 遅延を挟んで
    req_start <= '1';
    wait until clk'event and clk='1'; -- clkの立ち上がりまでwait
    wait for 1 ns; -- 遅延を挟んで
    req_start <= '0';
     
    for n in loop_count to 1 loop
        wait until clk'event and clk='1'; -- clkの立ち上がりまでwait
        wait for 1 ns; -- 遅延を挟んで
    end loop;
    ta <= '1';
    wait until clk'event and clk='1'; -- clkの立ち上がりまでwait
    wait for 1 ns; -- 遅延を挟んで
    ta <= '0';
end REQ_START_TA;

begin
    -- clkの生成(50MHz)
    clk_generate : process begin
        clock_loop : loop
            clk <= '1';
            wait for (PERIOD * DUTY_CYCLE);
            clk <= '0';
            wait for (PERIOD - (PERIOD * DUTY_CYCLE));
        end loop clock_loop;
    end process clk_generate;
    
    -- シミュレーション時にOVLチェッカの初期化数を表示
    ovl_print_init_count_p : process begin
        wait for 0 ns;
        ovl_print_init_count_proc(ovl_proj_controls);
        wait; -- forever
    end process ovl_print_init_count_p;
    
    -- resetの生成
    reset_generate : process begin
        reset <= '1';
        wait for 100 ns;
        reset <= '0';
        wait; -- forever
    end process reset_generate;
    
    ack_sm_inst : ack_sm port map(
        clk => clk,
        reset => reset,
        req0 => req0,
        req1 => req1,
        ta0 => ta0, 
        ta1 => ta1,
        ack0 => ack0,
        ack1 => ack1
    );
    req_am_inst0 : req_sm port map(
        clk => clk,
        reset => reset,
        req_start => req_start0,
        ack => ack0,
        req => req0
    );
    req_am_inst1 : req_sm port map(
        clk => clk,
        reset => reset,
        req_start => req_start1,
        ack => ack1,
        req => req1
    );
        
    -- req_start0 とta0 の関係を生成する
    process begin
        req_start0 <= '0';
        ta0 <= '0';
        wait until reset'event and reset='0'; -- resetの立ち下がりまでwait
        wait for 100 ns;
        REQ_START_TA(clk, 1, req_start0, ta0);
        REQ_START_TA(clk, 2, req_start0, ta0);
        REQ_START_TA(clk, 3, req_start0, ta0);
        REQ_START_TA(clk, 2, req_start0, ta0);
        REQ_START_TA(clk, 1, req_start0, ta0);
        REQ_START_TA(clk, 3, req_start0, ta0);
        REQ_START_TA(clk, 2, req_start0, ta0);
        wait for 200 ns;
        assert (false) report "Simulation End!" severity failure;
    end process;
    
    -- req_start1 とta1 の関係を生成する
    process begin
        req_start1 <= '0';
        ta1 <= '0';
        wait until reset'event and reset='0'; -- resetの立ち下がりまでwait
        wait for 100 ns;
        REQ_START_TA(clk, 2, req_start1, ta1);
        REQ_START_TA(clk, 1, req_start1, ta1);
        REQ_START_TA(clk, 2, req_start1, ta1);
        REQ_START_TA(clk, 3, req_start1, ta1);
        REQ_START_TA(clk, 3, req_start1, ta1);
        REQ_START_TA(clk, 1, req_start1, ta1);
        REQ_START_TA(clk, 2, req_start1, ta1);
        wait; -- forever
    end process;
    
    -- OVLアサーション
    ovl_gen : if (ovl_proj_controls.assert_ctrl = OVL_ON) generate
        ta0_ack0_assertion : ovl_next generic map (
            severity_level        => OVL_ERROR,
            num_cks             => 1,
            check_overlapping   => OVL_CHK_OVERLAP_OFF,
            check_missing_start => OVL_ON,
            property_type        => OVL_ASSERT,
            msg                 =>"ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted.",
            coverage_level      => OVL_COVER_BASIC,
            clock_edge            => OVL_POSEDGE,
            reset_polarity        => OVL_ACTIVE_HIGH,
            gating_type            => OVL_GATE_CLOCK,
            controls            => OVL_CTRL_DEFAULTS
        )port map (
            clock               => clk,
            reset               => reset,
            enable              => '1',
            start_event         => ta0,
            test_expr           => ack0,
            fire                => fire_ta0_ack0_as
        );
        ta1_ack1_assertion : ovl_next generic map (
            severity_level        => OVL_ERROR,
            num_cks             => 1,
            check_overlapping   => OVL_CHK_OVERLAP_OFF,
            check_missing_start => OVL_ON,
            property_type        => OVL_ASSERT,
            msg                 =>"ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted.",
            coverage_level      => OVL_COVER_BASIC,
            clock_edge            => OVL_POSEDGE,
            reset_polarity        => OVL_ACTIVE_HIGH,
            gating_type            => OVL_GATE_CLOCK,
            controls            => OVL_CTRL_DEFAULTS
        )port map (
            clock               => clk,
            reset               => reset,
            enable              => '1',
            start_event         => ta1,
            test_expr           => ack1,
            fire                => fire_ta1_ack1_as
        );
        req0_ack0_assertion : ovl_frame generic map(
            severity_level        => OVL_ERROR,
            min_cks                => 2,
            max_cks                => 4,
            action_on_new_start    => OVL_IGNORE_NEW_START,
            property_type        => OVL_ASSERT,
            msg => "ERROR: ack0 isn't asserted after 2-4 clocks after req0 was asserted.",
            coverage_level        => OVL_COVER_BASIC,
            clock_edge            => OVL_POSEDGE,
            reset_polarity        => OVL_ACTIVE_HIGH,
            gating_type            => OVL_GATE_CLOCK,
            controls            => OVL_CTRL_DEFAULTS
        ) port map(
            clock                 => clk,
            reset                => reset,
            enable                => '1',
            start_event            => req0,
            test_expr            => ack0,
            fire                => fire_req0_ack0_as
        );
        req1_ack1_assertion : ovl_frame generic map(
            severity_level        => OVL_ERROR,
            min_cks                => 2,
            max_cks                => 4,
            action_on_new_start    => OVL_IGNORE_NEW_START,
            property_type        => OVL_ASSERT,
            msg => "ERROR: ack1 isn't asserted after 2-4 clocks after req1 was asserted.",
            coverage_level        => OVL_COVER_BASIC,
            clock_edge            => OVL_POSEDGE,
            reset_polarity        => OVL_ACTIVE_HIGH,
            gating_type            => OVL_GATE_CLOCK,
            controls            => OVL_CTRL_DEFAULTS
        ) port map(
            clock                 => clk,
            reset                => reset,
            enable                => '1',
            start_event            => req1,
            test_expr            => ack1,
            fire                => fire_req1_ack1_as
        );
    end generate ovl_gen;
end testbench_arch;


std_ovlフォルダのstd_ovl_components.vhdとstd_ovl_components_vlog.vhdのパッケージ名がstd_ovl_componentsで同じなので、これらのパッケージはuseしないで、component文をソース上に書くことにした。ModelSim Altera Starter Editon 6.5b では、VHDLとVerilogの混在シミュレーションが出来ないため、ModelSim SE 6.1eでシミュレーションを行った。
前と同様に、accellera_ovl_vhdlとaccellera_ovl_vlogライブラリをリンクして、VHDLファイルをコンパイルし、シミュレーションをスタートする。run -allコマンドでシミュレーションを行った。そのModelSimの図を下に示す。
OVL_VHDL_7_100329.png

ログを下に示す。

# OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 260000 : tb_req_ack.ovl_gen.ta1_ack1_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 280000 : tb_req_ack.ovl_gen.ta0_ack0_assertion.ovl_error_t
# OVL_ERROR : OVL_FRAME : ERROR: ack0 isn't asserted after 2-4 clocks after req0 was asserted. : Test expression is not TRUE within specified maximum max_cks cycles from start event : severity 1 : time 300000 : tb_req_ack.ovl_gen.req0_ack0_assertion.ovl_error_t
# OVL_ERROR : OVL_FRAME : ERROR: ack1 isn't asserted after 2-4 clocks after req1 was asserted. : Test expression is not TRUE within specified maximum max_cks cycles from start event : severity 1 : time 300000 : tb_req_ack.ovl_gen.req1_ack1_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expresson is asserted without a corresponding start_event : severity 1 : time 320000 :
tb_req_ack.ovl_gen.ta0_ack0_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expresson is asserted without a corresponding start_event : severity 1 : time 320000 :
tb_req_ack.ovl_gen.ta1_ack1_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 340000 : tb_req_ack.ovl_gen.ta0_ack0_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 340000 : tb_req_ack.ovl_gen.ta1_ack1_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 400000 : tb_req_ack.ovl_gen.ta0_ack0_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 400000 : tb_req_ack.ovl_gen.ta1_ack1_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expresson is asserted without a corresponding start_event : severity 1 : time 440000 :
tb_req_ack.ovl_gen.ta0_ack0_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expresson is asserted without a corresponding start_event : severity 1 : time 440000 :
tb_req_ack.ovl_gen.ta1_ack1_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 460000 : tb_req_ack.ovl_gen.ta0_ack0_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 460000 : tb_req_ack.ovl_gen.ta1_ack1_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 520000 : tb_req_ack.ovl_gen.ta1_ack1_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 540000 : tb_req_ack.ovl_gen.ta0_ack0_assertion.ovl_error_t
# OVL_ERROR : OVL_FRAME : ERROR: ack0 isn't asserted after 2-4 clocks after req0 was asserted. : Test expression is not TRUE within specified maximum max_cks cycles from start event : severity 1 : time 560000 : tb_req_ack.ovl_gen.req0_ack0_assertion.ovl_error_t
# OVL_ERROR : OVL_FRAME : ERROR: ack1 isn't asserted after 2-4 clocks after req1 was asserted. : Test expression is not TRUE within specified maximum max_cks cycles from start event : severity 1 : time 560000 : tb_req_ack.ovl_gen.req1_ack1_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expresson is asserted without a corresponding start_event : severity 1 : time 580000 :
tb_req_ack.ovl_gen.ta0_ack0_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expresson is asserted without a corresponding start_event : severity 1 : time 580000 :
tb_req_ack.ovl_gen.ta1_ack1_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 600000 : tb_req_ack.ovl_gen.ta0_ack0_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 600000 : tb_req_ack.ovl_gen.ta1_ack1_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 660000 : tb_req_ack.ovl_gen.ta0_ack0_assertion.ovl_error_t
# OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 660000 : tb_req_ack.ovl_gen.ta1_ack1_assertion.ovl_error_t
# OVL_ERROR : OVL_FRAME : ERROR: ack0 isn't asserted after 2-4 clocks after req0 was asserted. : Test expression is not TRUE within specified maximum max_cks cycles from start event : severity 1 : time 700000 : tb_req_ack.ovl_gen.req0_ack0_assertion.ovl_error_t
# OVL_ERROR : OVL_FRAME : ERROR: ack1 isn't asserted after 2-4 clocks after req1 was asserted. : Test expression is not TRUE within specified maximum max_cks cycles from start event : severity 1 : time 700000 : tb_req_ack.ovl_gen.req1_ack1_assertion.ovl_error_t
# ** Failure: Simulation End!
# Time: 841 ns Iteration: 0 Process: /tb_req_ack/line__183 File: C:/HDL/OVL/examples/req_ack_test_vhdl_vlog/tb_req_ack.vhd
# Break at C:/HDL/OVL/examples/req_ack_test_vhdl_vlog/tb_req_ack.vhd line 196


これで、混在シミュレーションができるシミュレーターがあれば、VHDLでも種類の豊富なVerilog OVLを使うことができた。
  1. 2010年03月29日 19:53 |
  2. アサーション事始め
  3. | トラックバック:0
  4. | コメント:0

VHDLでOVLアサーションを使用する2(VHDLライブラリを使用)

VHDLでOVLアサーションを使用する1(ライブラリのコンパイル)”でライブラリをコンパイルした。今回は、req_sm.vhd, ack_sm.vhd, tb_req_ack.vhd, ついでにパッケージのproj_pkg.vhd(これは、マニュアルを引用した)を作って、ModelSim Altera Starter Editon 6.5b のプロジェクトを作り、”VHDLでOVLアサーションを使用する1(ライブラリのコンパイル)”で作ったライブラリをModelSimのプロジェクトにインポートする。そうしてからVHDLファイルをコンパイルし、シミュレーションを行う。
さて、まずは、ModelSimのプロジェクトを作成し、ファイルをプロジェクトに加える。
ovl_vhdl_5_100327.png

次に、accellera_ovl_vhdlとaccellera_ovl_vlogライブラリをリンクしよう。
ModelSimのfileメニューからNew -> Library... を選択する。
ovl_vhdl_2_100327.png

Create a New Libraryダイアログが開くので、Library Name:にaccellera_ovl_vhdl を入力し、Library Maps to:はBrowse...ボタンをクリックして、accellera_ovl_vhdlを選択して、Next>ボタンをクリックする。
ovl_vhdl_3_100327.png

ModelSimのLibraryペインにaccellera_ovl_vhdlライブラリが入る。
ovl_vhdl_4_100327.png

同様に、accellera_ovl_vlogライブラリをプロジェクトにインクルードする。

ここで、各VHDLファイルを示す。まずは、グローバルなライブラリの設定を行うproj_pkg.vhdから。

-- proj_pkg.vhd

library accellera_ovl_vhdl;
use accellera_ovl_vhdl.std_ovl.all;
use accellera_ovl_vhdl.std_ovl_procs.all;

package proj_pkg is
    -- OVL configuration
    constant ovl_proj_controls : ovl_ctrl_record := (
        -- generate statement controls
        xcheck_ctrl                 => OVL_ON,
        implicit_xcheck_ctrl        => OVL_ON,
        init_msg_ctrl               => OVL_ON,
        init_count_ctrl             => OVL_OFF,
        assert_ctrl                 => OVL_ON,
        cover_ctrl                  => OVL_ON,
        global_reset_ctrl           => OVL_OFF,
        finish_ctrl                 => OVL_ON,
        gating_ctrl                 => OVL_ON,
        -- user configurable library constants
        max_report_error            => 4,
        max_report_cover_point      => 15,
        runtime_after_fatal         => "150 ns    ",
        -- default values for common generics
        severity_level_default      => OVL_SEVERITY_DEFAULT,
        property_type_default       => OVL_PROPERTY_DEFAULT,
        --msg_default => OVL_MSG_DEFAULT,
        msg_default                 => ovl_set_msg("Assertion Error"),
        coverage_level_default      => OVL_COVER_DEFAULT,
        clock_edge_default          => OVL_CLOCK_EDGE_DEFAULT,
        reset_polarity_default      => OVL_RESET_POLARITY_DEFAULT,
        gating_type_default         => OVL_GATING_TYPE_DEFAULT
    );
end package proj_pkg;


req_sm.vhdを下に示す。

-- OVLテスト用 req_sm.vhd
-- req_start 信号を受けると、reqを1にアサートする。ackを受け取るとreqを0にディアサートする

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

entity req_sm is
    port(
        clk : in std_logic;
        reset : in std_logic;
        req_start : in std_logic;
        ack : in std_logic;
        req : out std_logic
    );
end req_sm;

architecture RTL of req_sm is
type cs_req_state is (idle_req, assert_req);
signal cs_req : cs_req_state;
begin
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                cs_req <= idle_req;
                req <= '0';
            else
                case cs_req is
                    when idle_req =>
                        if req_start='1' then
                            cs_req <= assert_req;
                            req <= '1';
                        end if;
                    when assert_req =>
                        if ack='1' then
                            cs_req <= idle_req;
                            req <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
end RTL;


ack_smを下に示す。

-- OVLテスト用 ack_sm.vhd
-- 2つのreqを管理して、reqがアサートされている状態で、taがアサートされるとackを返す

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

entity ack_sm is
    port(
        clk : in std_logic;
        reset : in std_logic;
        req0 : in std_logic;
        req1 : in std_logic;
        ta0 : in std_logic; -- Transfer Acknowledge
        ta1 : in std_logic; -- Transfer Acknowledge
        ack0 : out std_logic;
        ack1 : out std_logic
    );
end ack_sm;

architecture RTL of ack_sm is
type cs_main_state is (idle_req, assert_req0, assert_req1, assert_req01, req0_ack, req1_ack, req01_ack);
signal cs_main : cs_main_state;
begin
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                cs_main <= idle_req;
                ack0 <= '0'; ack1 <= '0';
            else
                case cs_main is
                    when idle_req =>
                        if req0='1' then
                            cs_main <= assert_req0;
                            ack0 <= '0'; ack1 <= '0';
                        elsif req1='1' then
                            cs_main <= assert_req1;
                            ack0 <= '0'; ack1 <= '0';
                        end if;
                    when assert_req0 =>
                        if req1='1' then
                            cs_main <= assert_req01;
                            ack0 <= '0'; ack1 <= '0';
                        elsif ta0='1' then
                            cs_main <= req0_ack;
                            ack0 <= '1'; ack1 <= '0';
                        end if;
                    when assert_req1 =>
                        if req0='1' then
                            cs_main <= assert_req01;
                            ack0 <= '0'; ack1 <= '0';
                        elsif ta1='1' then
                            cs_main <= req1_ack;
                            ack0 <= '0'; ack1 <= '1';
                        end if;
                    when assert_req01 =>
                        if ta0='1' and ta1='0' then
                            cs_main <= req0_ack;
                            ack0 <= '1'; ack1 <= '0';
                        elsif ta0='0' and ta1='1' then
                            cs_main <= req1_ack;
                            ack0 <= '0'; ack1 <= '1';
                        elsif ta0='1' and ta1='1' then
                            cs_main <= req01_ack;
                            ack0 <= '1'; ack1 <= '1';
                        end if;
                    when req0_ack =>
                        if req1='1' then
                            cs_main <= assert_req1;
                            ack0 <= '0'; ack1 <= '0';
                        else
                            cs_main <= idle_req;
                            ack0 <= '0'; ack1 <= '0';
                        end if;
                    when req1_ack =>
                        if req0='1' then
                            cs_main <= assert_req0;
                            ack0 <= '0'; ack1 <= '0';
                        else
                            cs_main <= idle_req;
                            ack0 <= '0'; ack1 <= '0';
                        end if;
                    when req01_ack =>
                        cs_main <= idle_req;
                        ack0 <= '0'; ack1 <= '0';
                end case;
            end if;
        end if;
    end process;
end RTL;


最後に、テストベンチのtb_req_ack.vhd を示す。

-- tb_req_ack.vhd

-- tb_req_ack.vhd本体
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
library accellera_ovl_vhdl;
use accellera_ovl_vhdl.std_ovl.all;
use accellera_ovl_vhdl.std_ovl_components.all;
use accellera_ovl_vhdl.std_ovl_procs.all;
library work;
use work.proj_pkg.all;

entity tb_req_ack is
end tb_req_ack;

architecture testbench_arch of tb_req_ack is
component ack_sm
    port(
        clk : in std_logic;
        reset : in std_logic;
        req0 : in std_logic;
        req1 : in std_logic;
        ta0 : in std_logic; -- Transfer Acknowledge
        ta1 : in std_logic; -- Transfer Acknowledge
        ack0 : out std_logic;
        ack1 : out std_logic
    );
end component;
component req_sm
    port(
        clk : in std_logic;
        reset : in std_logic;
        req_start : in std_logic;
        ack : in std_logic;
        req : out std_logic
    );
end component;
signal clk : std_logic := '1';
signal reset : std_logic := '1';
signal req_start0 : std_logic := '0';
signal req_start1 : std_logic := '0';
signal req0 : std_logic := '0';
signal req1 : std_logic := '0';
signal ta0 : std_logic := '0';
signal ta1 : std_logic := '0';
signal ack0 : std_logic := '0';
signal ack1 : std_logic := '0';
signal fire_ta0_ack0_as, fire_ta1_ack1_as : std_logic_vector(OVL_FIRE_WIDTH - 1 downto 0);
signal fire_req0_ack0_as, fire_req1_ack1_as : std_logic_vector(OVL_FIRE_WIDTH - 1 downto 0);

constant PERIOD : time := 20 ns;
constant DUTY_CYCLE : real := 0.5;

-- req_startとtaを出力するprocedure
procedure REQ_START_TA(
    signal clk : in std_logic;
    loop_count : in integer;
    signal req_start : out std_logic;
    signal ta : out std_logic
) is
begin
    wait until clk'event and clk='1'; -- clkの立ち上がりまでwait
    wait for 1 ns; -- 遅延を挟んで
    req_start <= '1';
    wait until clk'event and clk='1'; -- clkの立ち上がりまでwait
    wait for 1 ns; -- 遅延を挟んで
    req_start <= '0';
     
    for n in loop_count to 1 loop
        wait until clk'event and clk='1'; -- clkの立ち上がりまでwait
        wait for 1 ns; -- 遅延を挟んで
    end loop;
    ta <= '1';
    wait until clk'event and clk='1'; -- clkの立ち上がりまでwait
    wait for 1 ns; -- 遅延を挟んで
    ta <= '0';
end REQ_START_TA;

begin
    -- clkの生成(50MHz)
    clk_generate : process begin
        clock_loop : loop
            clk <= '1';
            wait for (PERIOD * DUTY_CYCLE);
            clk <= '0';
            wait for (PERIOD - (PERIOD * DUTY_CYCLE));
        end loop clock_loop;
    end process clk_generate;
    
    -- シミュレーション時にOVLチェッカの初期化数を表示
    ovl_print_init_count_p : process begin
        wait for 0 ns;
        ovl_print_init_count_proc(ovl_proj_controls);
        wait; -- forever
    end process ovl_print_init_count_p;
    
    -- resetの生成
    reset_generate : process begin
        reset <= '1';
        wait for 100 ns;
        reset <= '0';
        wait; -- forever
    end process reset_generate;
    
    ack_sm_inst : ack_sm port map(
        clk => clk,
        reset => reset,
        req0 => req0,
        req1 => req1,
        ta0 => ta0, 
        ta1 => ta1,
        ack0 => ack0,
        ack1 => ack1
    );
    req_am_inst0 : req_sm port map(
        clk => clk,
        reset => reset,
        req_start => req_start0,
        ack => ack0,
        req => req0
    );
    req_am_inst1 : req_sm port map(
        clk => clk,
        reset => reset,
        req_start => req_start1,
        ack => ack1,
        req => req1
    );
        
    -- req_start0 とta0 の関係を生成する
    process begin
        req_start0 <= '0';
        ta0 <= '0';
        wait until reset'event and reset='0'; -- resetの立ち下がりまでwait
        wait for 100 ns;
        REQ_START_TA(clk, 1, req_start0, ta0);
        REQ_START_TA(clk, 2, req_start0, ta0);
        REQ_START_TA(clk, 3, req_start0, ta0);
        REQ_START_TA(clk, 2, req_start0, ta0);
        REQ_START_TA(clk, 1, req_start0, ta0);
        REQ_START_TA(clk, 3, req_start0, ta0);
        REQ_START_TA(clk, 2, req_start0, ta0);
        wait for 200 ns;
        assert (false) report "Simulation End!" severity failure;
    end process;
    
    -- req_start1 とta1 の関係を生成する
    process begin
        req_start1 <= '0';
        ta1 <= '0';
        wait until reset'event and reset='0'; -- resetの立ち下がりまでwait
        wait for 100 ns;
        REQ_START_TA(clk, 2, req_start1, ta1);
        REQ_START_TA(clk, 1, req_start1, ta1);
        REQ_START_TA(clk, 2, req_start1, ta1);
        REQ_START_TA(clk, 3, req_start1, ta1);
        REQ_START_TA(clk, 3, req_start1, ta1);
        REQ_START_TA(clk, 1, req_start1, ta1);
        REQ_START_TA(clk, 2, req_start1, ta1);
        wait; -- forever
    end process;
    
    -- OVLアサーション
    ovl_gen : if (ovl_proj_controls.assert_ctrl = OVL_ON) generate
        ta0_ack0_assertion : ovl_next generic map (
            severity_level        => OVL_ERROR,
            num_cks             => 1,
            check_overlapping   => OVL_CHK_OVERLAP_OFF,
            check_missing_start => OVL_ON,
            property_type        => OVL_ASSERT,
            msg                 =>"ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted.",
            coverage_level      => OVL_COVER_BASIC,
            clock_edge            => OVL_POSEDGE,
            reset_polarity        => OVL_ACTIVE_HIGH,
            gating_type            => OVL_GATE_CLOCK,
            controls            => OVL_CTRL_DEFAULTS
        )port map (
            clock               => clk,
            reset               => reset,
            enable              => '1',
            start_event         => ta0,
            test_expr           => ack0,
            fire                => fire_ta0_ack0_as
        );
        ta1_ack1_assertion : ovl_next generic map (
            severity_level        => OVL_ERROR,
            num_cks             => 1,
            check_overlapping   => OVL_CHK_OVERLAP_OFF,
            check_missing_start => OVL_ON,
            property_type        => OVL_ASSERT,
            msg                 =>"ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted.",
            coverage_level      => OVL_COVER_BASIC,
            clock_edge            => OVL_POSEDGE,
            reset_polarity        => OVL_ACTIVE_HIGH,
            gating_type            => OVL_GATE_CLOCK,
            controls            => OVL_CTRL_DEFAULTS
        )port map (
            clock               => clk,
            reset               => reset,
            enable              => '1',
            start_event         => ta1,
            test_expr           => ack1,
            fire                => fire_ta1_ack1_as
        );
    end generate ovl_gen;
end testbench_arch;


これでModelSimでシミュレーションをしてみた。結果の図を下に示す。
ovl_vhdl_6_100327.png

出力されたOVLアサーションのログを下に示す。

#        OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 260000 ps :tb_req_ack:ovl_gen:ta1_ack1_assertion:
#        OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 280000 ps :tb_req_ack:ovl_gen:ta0_ack0_assertion:
#        OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 400000 ps :tb_req_ack:ovl_gen:ta0_ack0_assertion:
#        OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 400000 ps :tb_req_ack:ovl_gen:ta1_ack1_assertion:
#        OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 520000 ps :tb_req_ack:ovl_gen:ta1_ack1_assertion:
#        OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 540000 ps :tb_req_ack:ovl_gen:ta0_ack0_assertion:
#        OVL_ERROR : OVL_NEXT : ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 660000 ps :tb_req_ack:ovl_gen:ta0_ack0_assertion:
#        OVL_ERROR : OVL_NEXT : ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted. : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 660000 ps :tb_req_ack:ovl_gen:ta1_ack1_assertion:
# ** Failure: Simulation End!
#    Time: 841 ns  Iteration: 0  Process: /tb_req_ack/line__133 File: H:/HDL/OVL/example/req_ack_test_vhdl/tb_req_ack.vhd
# Break in Process line__133 at H:/HDL/OVL/example/req_ack_test_vhdl/tb_req_ack.vhd line 146

  1. 2010年03月28日 06:09 |
  2. アサーション事始め
  3. | トラックバック:0
  4. | コメント:0

VHDLでOVLアサーションを使用する1(ライブラリのコンパイル)

今までのVerilogのOVLアサーションでは、OVL_V2をコンパイルしていたが、ライブラリ化するとコンパイルは必要無くなる。VHDLのOVLアサーションでは、VHDLのOVLアサーション(ovl_***.vhd)やVerilogのOVLアサーション(ovl_***.v)をコンパイルしてライブラリ化する。このあたりの手順は、Accellera Standard OVL V2 Library Reference Manual Software Version 2.4 March 2009の43ページ、"VHDL OVL Compile Order with Verilog OVL"を参考にしている。

1. ModelSim AE 6.5bを立ち上げて、cdコマンドでstd_ovlフォルダに移動する(Transcriptウインドウにコマンドを入力する)。
ovl_vhdl_1_100325.png

cd H:/HDL/OVL/std_ovl


2. vlibコマンドでaccellera_ovl_vlogライブラリを作成する。

vlib accellera_ovl_vlog


3. Verilog OVLをaccellera_ovl_vlogライブラリにコンパイルする。

vlog -work accellera_ovl_vlog +define+OVL_VERILOG +define+OVL_ASSERT_ON +define+OVL_FINISH_OFF +incdir+H:/HDL/OVL/std_ovl ovl_*.v


4. vlibコマンドでaccellera_ovl_vhdlライブラリを作成する。

vlib accellera_ovl_vhdl


5. VHDL OVLをaccellera_ovl_vhdlライブラリにコンパイルする。

vcom -93 -work accellera_ovl_vhdl std_ovl.vhd
vcom -93 -work accellera_ovl_vhdl std_ovl_procs.vhd
vcom -93 -work accellera_ovl_vhdl std_ovl_components_vlog.vhd
vcom -93 -work accellera_ovl_vhdl std_ovl_clock_gating.vhd
vcom -93 -work accellera_ovl_vhdl std_ovl_reset_gating.vhd
vcom -93 -work accellera_ovl_vhdl ovl_*.vhd
vcom -93 -work accellera_ovl_vhdl vhdl93/ovl_*_rtl.vhd


これでライブラリの準備は終了。
  1. 2010年03月25日 06:05 |
  2. アサーション事始め
  3. | トラックバック:0
  4. | コメント:0

OVL(Open Verification Library)を試してみる7(OVLチェッカの概要)

前回は、ovl_next, ovl_frameの機能を見てみた

今回は、各OVLチェッカの概要を下に示す。以下の項目は、Verilog-95やVHDLで使用可能なOVLを示している。VHDL用のOVLが無い場合は、(VHDLは無し)と表示されている。

ovl_always : 常に式が成り立つかを見ている(val1 < val2)
ovl_always_on_edge : サンプリングイベントの時に式が成り立つかを見ている(サンプリングイベント=ack, 式=(MAIN_STATE==ACK_STATE))(VHDLは無し)
ovl_change : start_eventが起こった時から、num_cksで示されたクロック以内に出力値が変化すことを保証する(VHDLは無し)
ovl_cycle_sequence : ステートマシンの遷移条件をテストできる。WR→WAIT→(WRまたはDONE)
ovl_decrement : ある値で減算するカウンタ等をテストできる(VHDLは無し)
ovl_delta : 信号がある一定の範囲で変化することをテストできる(VHDLは無し)
ovl_even_parity : 偶数パリティをチェックする(VHDLは無し)
ovl_fifo_index : FIFOのオーバーフローとアンダーフローをチェックする。push,pop条件を監視しdepthを設定することでチェックすることができる(VHDLは無し)
ovl_frame : start_eventとあるtest_exprの関係をテストできる。start_eventが変化してからtest_exprが変化するまでのクロック数を最小値、最大値で表する(VHDLは無し)
ovl_handshake : requestとacknowledgeの関係をovl_frame等よりも詳細にチェックすることができる。req, ackの厳密な関係を記述したい場合はこれを使うべきだと思う(VHDLは無し)
ovl_implication : 原因と結果の関係をテストする。antecedent_exprがアサートされている時に、consequent_exprもアサートされているかをチェックする
ovl_increment:ある値で加算するカウンタ等をテストできる(VHDLは無し)
ovl_never : test_exprが決して真にならないことをチェックする。例えば、サイコロの値をdice_cntとすると、test_exprはdice_cnt>6と表される。dice_cntが7以上になればアサーション・エラーとなる
ovl_never_unkown : qualifierがTRUEの時に、test_exprに不定値を含むかどうかをチェックする
ovl_never_unkown_async : 非同期(クロックイベントがない)のovl_never_unkown
ovl_next : start_eventとtest_expr間のアサートのクロックのタイミングをチェックする。ovl_frameと異なるのは、クロックのタイミングが固定されていること
ovl_no_overflow : test_exprがminとmaxの間にあるかどうかをチェックする(VHDLは無し)
ovl_no_transition : start_stateを指定して、次のステートがnext_stateに遷移しないことをチェックする(VHDLは無し)
ovl_no_underflow : test_exprがminとmaxの間にあるかどうかをチェックする(VHDLは無し)
ovl_odd_parity : test_exprが奇数パリティであることをチェックする(VHDLは無し)
ovl_one_cold : test_exprのステート値などのどれか1ビットが0であることをチェックする(VHDLは無し)
ovl_one_hot : test_exprのどれか1ビットだけが1であることをチェックする
ovl_proposition : test_exprが成立することをチェックする。組み合わせ回路(VHDLは無し)
ovl_quiescent_state : sample_eventがTRUEの時に、state_exprがcheck_valueと同一になっているかをチェックする(VHDLは無し)
ovl_range : test_exprの値がmin値とmax値の間にあることをチェックする
ovl_time : start_eventがTRUEになった次のクロックからnum_cksクロック間、test_exprの条件が成り立つことをチェックする(VHDLは無し)
ovl_transition : test_exprの信号がstart_stateの次のステートがnext_stateであることをチェックする(VHDLは無し)(注:必ずしもステートマシンのステートチェックだけではなく、1つ前の状態と次の状態のチェックをする。enableを使うとクロックが離れていても使える)
ovl_unchange : start_eventがTRUEになってから、test_exprの信号がnum_cksクロック間、変化しないことをチェックする(VHDLは無し)
ovl_width : パルス幅をチェックする。test_exprがTRUEの幅が、min_cksとmax_cksのクロックの間に入っていることをチェックする(VHDLは無し)
ovl_win_change : start_eventがTRUEになってから、end_eventがTRUEになるまでの間(event window)に、test_exprが変化することをチェックする(VHDLは無し)
ovl_win_unchange : start_eventがTRUEになってから、end_eventがTRUEになるまでの間(event window)に、test_exprが変化しないことをチェックする(VHDLは無し)
ovl_window : start_eventがTRUEになってから、end_eventがTRUEになるまでの間(event window)に、test_exprが常にTRUEであることをチェックする(VHDLは無し)
ovl_zero_one_hot : test_exprのどれか1ビットだけが1かまたは、オール0であることをチェックする


参考文献:Accellera Standard OVL V2 Library Reference Manual Software Version 2.4 March 2009

次に、fireのポートへの出力を実装しているのは以下の通りである。

ovl_always, ovl_cycle_sequence, ovl_implication, ovl_never, ovl_never_unkown, ovl_next, ovl_one_hot, ovl_range, ovl_win_unchange, ovl_zero_one_hot


上に示した参考文献を見ると例が示されていて、わかりやすく書いてある。各OVLチェッカの概要を読んで、使えそうなのを探して、参考文献で確認してからOVLを書こうと思っている。

(2010/03/23:修正)
(2012/03/10:修正)OVL Ver. 2.6ではすべてのチェッカでfire ポートへの出力が実装されている。
  1. 2010年03月22日 20:43 |
  2. アサーション事始め
  3. | トラックバック:0
  4. | コメント:2
»