FC2カウンター FPGAの部屋 2010年03月

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

FPGAの部屋

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

DDR3 SDRAMの新機能のまとめ

さて、Spartan-6 FPGA SP605 評価キットを試してみたいのだが、その前にDDR3 SDRAMの新機能について勉強してみることにした。参照する資料はエルピーダ社のDDR3 SDRAMの新機能の使い方 - ユーザーズマニュアルを使用した。日本語でうまくまとまっていて、このシリーズにはDDR SDRAMの時代からお世話になっている。ありがとうございます。

1. 電源電圧が1.5V
2. バンク数が8、前のDDR2は4バンクだったのだが、DDR2でも8バンクもあるとのこと。
3. バースト数は当然8だが、4もあるとのこと。4の場合は、残りの4バーストを出さないで待っているようだ(Burst Chop4(BC4))。
4. ZQ Calibration:PVT (プロセス、電圧、温度)による Ron と ODT 値の変動の補正を行うそうだ。DDR2のOCDはオプション機能で肩透かしをくらったが、これは標準機能なのか?なお、Calib.コマンド(ZQCL,ZQCSを発行すると DRAM が自動で調整を行うセルフキャリブレーションだそうだ。DDR3 が正常動作するために必須の機能だそうだ。
5. RL,WLの扱いが変更になっている。この辺の機能はDDR2コントローラでも使っていない。(Posted CAS, Additive Latency)は使っていない。
6. DDR3ではディファレンシャルDQSのみ対応とのこと(DQS, DQS#)
7. /RESETピンが追加された。リセットすることができる。
8. Dynamic ODT:MRSコマンド発行なしにWrite時のODT抵抗値を動的に切り替えることが出来る機能。Write 時の信号品質向上に寄与。だそうです。Asynchoronous ODTも追加されたようだ。
9. DDR3 SDRAMのメモリモジュールでは、CMD/ADDRESS/CLK配線は各DDR3モジュールを一筆書き配線で結ぶとのこと。一筆書きの最初と最後では到達時間差が発生する。DQとDQSはそれぞれのDR3モジュールにつながっているため、CMD/ADDRESS/CLKとの間に時間差が発生する。そこで、 Write levelingモードで、DQ/DQSとCMD/ADDRESS/CLKの到達時間を合わせる。これはDQ/DQSの出力遅延を操作する必要があるので、Virtex-5以上でないと実装出来ないわけだ。
10. Read leveling:DDR3 SDRAM があらかじめ決められたデータパターンを出力してくれるようだ。これで、READデータの取り込みタイミングを最適な位置に調整しやすくなる。


DDR3は1ピン当たり、1Gbit/sec以上の転送レートを持っているので、かなりシビアになっていた。CMD/ADDRESS/CLK配線の時間差も考慮に入れて、DQ/DQSを遅延させるなど、コントローラの実装面でも厳しい。Xilinx社のFPGAでは、Virtex-5以上でないと厳しいだろう。DLLをイネーブルすると、最低動作周波数もかなり高いことが予想される。自作は厳しいだろう?
とりあえずMIGでSpartan-6のDDR3 SDRAMコントローラのハードIPを試してみたい。

ここまでやるとすると、次のメモリ規格が心配になってきた。次はどうなっているのだったろうか?DDR4?
  1. 2010年03月31日 05:55 |
  2. DDR SDRAMコントローラ
  3. | トラックバック:0
  4. | コメント:0

Kicadの回路図を書くときに忘れてはいけないTips

Kicadの回路図を書くときに忘れては行けないTips

1. コンポーネントのコピーは”C”キー
2. コンポーネントの連続挿入は”insert”キー
3. 回路のコピーは”SHIFT+ドラック”
4. コンポーネントの回転は”R”キー
5. 配線の変形(やってみて下さい)は”CTRL+ドラック”


  1. 2010年03月30日 17:38 |
  2. CADツール
  3. | トラックバック:0
  4. | コメント:2

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

ハート・ロッカーを見てきた(映画)

今日は奥さんが夜勤だったので、午前中に映画(ハート・ロッカー)を見てきた。アカデミー賞受賞作品ということで、どんなものか見てきた。
ひとことで言うと、戦争は悲惨だと感じてきた。あまり感想は書かないことにする。
もっと、エンターテイメント性の強い映画が見たい。

夕食はクリームシチューを奥さんが作っていってくれた。これに、パプリカとレタスのサラダを作る。パブリカは食べると甘くて、生で食べるのが好きだ。
  1. 2010年03月28日 17:59 |
  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でModelSimのシミュレーションを終了する方法

Verilogでシミュレーションを終了させる方法としてはシステム・タスクの$finish があり、また停止させるシスタム・タスクとしては$stop がある。VHDLでは、シミュレーションを停止または終了させる明確な文がないが、assert文を使用してシミュレーションを停止させることができる。つまり、ModelSim で"run 3ms"などのコマンドを実行するときは、3msで終了するが、VHDLで普通に書くと"run -all"で停止させるにはbreakする必要がある。これを、Verilogで$finish や$stop で停止するようにVHDLでもしたいということだ。

PS/2キーボードインターフェース用テストベンチ(procedure使用)”を例にとると、ps2read_tb.vhdの一番下のプロセス文は下のように書いてある。

    process begin
        wait for 80 ns; -- 1クロック分リセット
        
        reset <= '0'; -- リセット解除
        PS2_SigGen(x"1C", ps2clk, ps2data);
        PS2_SigGen(x"32", ps2clk, ps2data);
    end process;


これを下のように変更する。

    process begin
        wait for 80 ns; -- 1クロック分リセット

        reset <= '0'; -- リセット解除
        PS2_SigGen(x"1C", ps2clk, ps2data);
        PS2_SigGen(x"32", ps2clk, ps2data);
        wait for 40 us;
        assert (false) report "Simulation End!" severity failure;
    end process;


assert文は次のcondition が偽の時、report節に書いてあるメッセージを出力する。severity節は重大性を表す。ここではfailure となっている。このassert文はconditionがfalse なので、必ずfailureレベルでメッセージを出力する。これでシミュレーションが停止する。
ModelSimのSimulateメニューのRuntime Options... を選択するとRuntime Optionsダイアログが表示される。それのAssertionsタブを見ると、Immediate Assertion Break Severity がFailure にチェックされているから、failureレベルでメッセージを出力する事でシミュレーションが停止する。assert文のseverity levelをfatalにしておくとより確実にシミュレーションが停止するだろう。
VHDL_Sim_Stop_100326.png

2010/03/28:追記
assert文のseverity levelをfatalにしておくと下のようなエラーが出た。

(vcom-1136) Unknown identifier "fatal".

  1. 2010年03月26日 09:44 |
  2. シミュレーション
  3. | トラックバック:0
  4. | コメント:2

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

FPGAの部屋のまとめサイトの更新 (2010/03/24)

FPGAの部屋のまとめサイトを更新しました。今までに書いた記事を既存のカテゴリーに追加して、Core GeneraterSystemVerilogを追加しました。

そういえばOVLでもう1つやりたい事を忘れていました。VHDLのOVLアサーションを試してみたいです。それが終わったら、Spartan-6のSP605をやってみたいですね。
  1. 2010年03月24日 05:47 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

Kicad-2010-03-14

KiCad-2010-03-14-SVN2456-final-WinXP_full_with_components_doc_autoinstall.zipが出ています。この前、ご紹介したのはRC5だったので、正式版になったようです。
ダウンロードしてインストールしてみましたが、RC5との違いがわかりませんでした。
  1. 2010年03月23日 04:53 |
  2. CADツール
  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

蔵王スキー

2010年の3月20日と21日に山形県の蔵王温泉スキー場に、家族4人でスキーに行ってきました。高校生の娘は部活のため、お留守番です。
家を出発したのは、20日の午前5時。蔵王温泉スキー場に向けて出発。
やはり夜中なので、道がすいていました。スイスイと栃木県の矢板市まで到着。東北道に乗りました。東北道を北に進んで、山形道に乗り、山形蔵王出口で降りました。ETCを積んでいたので、1000円。凄い。去年は7000円近くだったのに。。。ラッキー。
10時20分頃、白銀荘に到着。天気は曇です。早速、スキーウェアに着替えて、中央ロープウェーに行きました。混雑もなく、最初のロープウェーで上に上がりました。下の写真は中央ロープウェー駅の出口あたりから、下を見た写真です。
zao_1_100322.jpg

中央ゲレンデを1本滑りましたが、春スキーの雪質ですが、ひどくはないといった雪質です。少し早めにお昼をということで、いままで家族で食べたことのない、中央ゲレンデ脇の三五郎小屋で昼食にしました。
zao_2_100322.jpg

息子はかつカレー、奥さんと下の娘はカレー、私は牛丼を食べました。カレーは微妙な味だったそうです。牛丼は普通でした。昔、蔵王に行っていたときはヨーデルがゲレンデに流れていた三五郎小屋にはよく入りましたが、奥さんたちの評判は芳しくなかったです。内部は、山小屋の様でもあるし、かなり、豪華な作りだと思っています。
zao_3_100322.jpg

そういえば、水のサーバーがあったのですが、天井から透明のホースで水を入れている様な感じでした。大丈夫なのかな?
さて昼食が終わったら、頂上を目指します。パラダイスゲレンデを目指して行きます。パラダイスゲレンデのリフトに乗るには登らないといけないので、コタンゲレンデのリフトにのり、パラダイスのリフトに乗りました。連絡コースを滑って、ユートピアゲレンデへ、そこを滑り降りると頂上に行くゴンドラがあります。ゴンドラはすいていました。すぐに乗って頂上へ。
zao_4_100322.jpg

その頃、どうも胃の具合が良くなかったので、私は気持ち悪くなってしまいました。頂上についたときに下痢をしてしまいました。どうも体調が優れません。やはり、今週の発表2回、宴会2回が効いたんでしょうか?
お地蔵さんに会う元気もなく、滑り降りました。その後、パラダイスゲレンデを滑って、片貝リフトに乗り、中央ゲレンデに降りてきました。中央ゲレンデで滑っていると限界に。。。また、下痢です。(お食事中の方すみません。。。)どうも気持ちも悪いので、レストランで休んでいました。奥さんと子どもたちは滑っていました。もうこのころは、平らなところは、雪の色が変わっていて、急に抵抗が大きくなって、危なくなってきました。体調も悪いし、宿に戻ることにしました。地面の出ているところもあります。
さて、中央ゲレンデのリフトに乗って、大平コースに、そこからサンシャインゲレンデを通って、中森ゲレンデへ。このころは雪もベチャベチャで、下の娘が2回ほど転びました。もう足も限界のようです。
白銀荘に3時過ぎ頃戻ってきました。本当に春スキーでした。午前中だけはマアマアの雪質でしたが、午後はひどいです。
白銀荘に帰ると、温泉へ。ここの温泉が硫黄の匂いが強くて良い温泉です。まったりしていると、夕食になりました。具合が悪くて食べられないかと思ってましたが、回復してきて、美味しい夕食を完食できました。よかったです。

次の朝は、大荒れの天気ということで、朝食を食べて、おみやげを買ったらスキーを滑らないで帰ってきました。
下の写真は白銀荘の朝食です。夕食は取るのを忘れてしまいました。
zao_5_100322.jpg

風の強いなか、高速はほとんど50Km/h制限でしたが、みんな飛ばしてましたね。どうも、山間部の高い橋の上を走っている時にスピードを出していると怖いです。風でハンドル取られるし、慎重に走っていました。
安達太良SAで昼食をとりました。最近のサービスエリアのレストランは侮れません。発酵牛のステーキ丼を食べました。柔らかくて美味しかったです。当たりでした。
zao_6_100322.jpg

その後は、時間も早いし、奥さんの実家に直行して、おみやげをおいてきました。息子の高校進学のお祝いを戴いていましたが、まだ直接あってお礼も言ってなかったのでちょうど良かったです。行ったら、地デジテレビに変わっていました。夕食も頂いてきてしまいました。久しぶりにお話しできてよかったです。
  1. 2010年03月22日 05:36 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

ISE11.5アップデータが出ています

Xilinx ISEのバージョン11.5のアップデータが出ています。ツイッターで、すすたわりさんに教えてもらいました。2.54GBありました。大きいですね。そういえば、アップデートはVirtex-6とSpartan-6だけのように書いてありました。あと、ISE12.1は2010年の5月に出るそうです。

職場のVistaにインストールしたら、立ち上がらなかった。互換性のチェックダイアログが出てきたので、もう一度インストールしてみることにした。家のWindows XPでISE11.5アップデータをかけたときのダイアルログを下に示す。
ISE115_100318.png

21:27で、今のところ15%終了。

インストールが終了した。Release Version: 11.5, Application Version: L.70 になった他は、あまり変化が分からない。
新機能は、Spartan-6 および Virtex-6 製品デバイスのサポートや、ロジック デザイン ツールの新機能、IP の新機能だそうだ。すべて、Spartan-6 および Virtex-6のアップデートの模様。

今日は、CMOSカメラでとった画像をディスプレイに出力する回路の発表終了した。これで、2日連続の発表が終了した。これでイベントは終了でもない。週末に蔵王スキーに行くんだった。。。
  1. 2010年03月18日 21:27 |
  2. Xilinx ISEについて
  3. | トラックバック:0
  4. | コメント:0

OVL(Open Verification Library)を試してみる6(ovl_next, ovl_frame その2)

OVL(Open Verification Library)を試してみる5(ovl_next, ovl_frame その1)”の続き。

さて、request とacknowledge の関係をVerilogでコーディングしてみた。req0, ta0, ack0 とreq1, ta1, ack1 の信号のグループがある。req_start0の1パルスをreq0を生成するステートマシン(req_sm.v)が受けると、req0信号をアサートする。req0は応答が帰ってくるまでアサートし続ける。ack0を出力するステートマシン(ack_sm.v)は、バックエンドの回路からのta0のアサートを確認して、ack0をアサートする。ack0がアサートされると、req0はディアサートされる、といったような制御をする。タイミングチャートを下に示す。
OVL_req_ack_1_100318.png

req_start1, req1, ta1, ack1の関係もreq0などの関係と同様とする。今回は間違いやすくするために、ack_sm.v はreq0,req1を同時に受けて、ack0, ack1を返すステートマシンとする(ta0, ta1も2つ同時に受ける)。それにわざと間違いを入れておいた(思いもよらない間違いも入っていたが。。。)。実際に作るときは、ack0, ack1のステートマシンを分けて、2つのステートマシンで処理する。しかし、仕様で同様の状態になってしまうケースもあることから、OVLを使用したアサーションの例として作成した。

req_sm.v を下に示す。

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

`default_nettype none

module req_sm (
    input wire    clk,
    input wire    reset,
    input wire    req_start,
    input wire    ack,
    output reg    req
);
    
    parameter [1:0]    idle_req        = 2'b01,
                    assert_req    = 2'b10;
    
    reg [1:0] cs_req;
    
    always @(posedge clk) begin
        if (reset) begin
            cs_req <= idle_req;
            req <= 1'b0;
        end else begin
            case (cs_req)
                idle_req : 
                    if (req_start) begin
                        cs_req <= assert_req;
                        req <= 1'b1;
                    end
                assert_req :
                    if (ack) begin
                        cs_req <= idle_req;
                        req <= 1'b0;
                    end
            endcase
        end
    end
endmodule

`default_nettype wire


次に、ack_sm.v を示す。

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

`default_nettype none

module ack_sm (
    input wire    clk,
    input wire    reset,
    input wire    req0,
    input wire    req1,
    input wire    ta0, // Transfer Acknowledge
    input wire    ta1, // Transfer Acknowledge 
    output reg    ack0,
    output reg    ack1
);
    
    parameter [6:0]    idle_req         = 7'b0000001,    // 最初のidle 状態
                    assert_req0        = 7'b0000010,    // req0だけがアサートされている
                    assert_req1        = 7'b0000100,    // req1だけがアサートされている
                    assert_req01    = 7'b0001000,
                    req0_ack        = 7'b0010000,
                    req1_ack        = 7'b0100000,
                    req01_ack        = 7'b1000000;
    reg [6:0] cs_main;
    
    always @(posedge clk) begin
        if (reset) begin
            cs_main <= idle_req;
            ack0 <= 1'b0; ack1 <= 1'b0;
        end else begin
            case (cs_main)
                idle_req : begin
                    if (req0) begin
                        cs_main <= assert_req0;
                        ack0 <= 1'b0; ack1 <= 1'b0;
                    end else if (req1) begin
                        cs_main <= assert_req1;
                        ack0 <= 1'b0; ack1 <= 1'b0;
                    end
                end
                assert_req0 : begin
                    if (req1) begin
                        cs_main <= assert_req01;
                        ack0 <= 1'b0; ack1 <= 1'b0;
                    end else if (ta0) begin
                        cs_main <= req0_ack;
                        ack0 <= 1'b1; ack1 <= 1'b0;
                    end
                end
                assert_req1 : begin
                    if (req0) begin
                        cs_main <= assert_req01;
                        ack0 <= 1'b0; ack1 <= 1'b0;
                    end else if (ta1) begin
                        cs_main <= req1_ack;
                        ack0 <= 1'b0; ack1 <= 1'b1;
                    end
                end
                assert_req01 : begin
                    if (ta0 & ~ta1) begin
                        cs_main <= req0_ack;
                        ack0 <= 1'b1; ack1 <= 1'b0;
                    end else if (~ta0 & ta1) begin
                        cs_main <= req1_ack;
                        ack0 <= 1'b0; ack1 <= 1'b1;
                    end else if (ta0 & ta1) begin
                        cs_main <= req01_ack;
                        ack0 <= 1'b1; ack1 <= 1'b1;
                    end
                end
                req0_ack : begin
                    if (req1) begin
                        cs_main <= assert_req1;
                        ack0 <= 1'b0; ack1 <= 1'b0;
                    end else begin
                        cs_main <= idle_req;
                        ack0 <= 1'b0; ack1 <= 1'b0;
                    end
                end
                req1_ack : begin
                    if (req0) begin
                        cs_main <= assert_req0;
                        ack0 <= 1'b0; ack1 <= 1'b0;
                    end else begin
                        cs_main <= idle_req;
                        ack0 <= 1'b0; ack1 <= 1'b0;
                    end
                end
                req01_ack : begin
                    cs_main <= idle_req;
                    ack0 <= 1'b0; ack1 <= 1'b0;
                end
            endcase
        end
    end
endmodule

`default_nettype wire


わざと間違いを入れてある。しかし、ack0, ack1を別々のステートマシンでやった方が、相当簡単になる。2つ一緒にやるのは難しい。
次は、OVLの入ったテストベンチを示す。req_sm.v は2つインスタンスを作っている。ack_sm.v は1つインスタンスしている。

// tb_req_ack.v

`default_nettype none
`timescale 1ns / 10ps

`include "std_ovl_defines.h"

module tb_req_ack;
    reg clk;
    reg reset;
    reg req_start0, req_start1;
    wire req0, req1;
    wire ack0, ack1;
    reg ta0, ta1;
    wire [`OVL_FIRE_WIDTH-1:0] fire_ta0_ack0_as, fire_ta1_ack1_as;
    wire [`OVL_FIRE_WIDTH-1:0] fire_req0_ack0_as, fire_req1_ack1_as;

    parameter CLK_PERIOD = 20;
    
    // 50MHzクロック
    always begin
       #(CLK_PERIOD/2)    clk = 1'b1 ;
       #(CLK_PERIOD/2)    clk = 1'b0 ;
    end
    
    // reset
    initial begin
            reset = 1'b1;
        #100    reset = 1'b0;
    end
    
    req_sm req_sm0 (
        .clk(clk),
        .reset(reset),
        .req_start(req_start0),
        .ack(ack0),
        .req(req0)
    );
    req_sm req_sm1 (
        .clk(clk),
        .reset(reset),
        .req_start(req_start1),
        .ack(ack1),
        .req(req1)
    );
    
    ack_sm ack_sm_i (
        .clk(clk),
        .reset(reset),
        .req0(req0),
        .req1(req1),
        .ta0(ta0),
        .ta1(ta1),
        .ack0(ack0),
        .ack1(ack1)
    );
    
    // req_start0とta0の関係を生成する
    initial begin
        req_start0 <= 1'b0;
        ta0 <= 1'b0;
        @(negedge reset); // リセットが0になるのを待つ
        #100;
        REQ_START_TA0(3'd1);
        REQ_START_TA0(3'd2);
        REQ_START_TA0(3'd3);
        REQ_START_TA0(3'd2);
        REQ_START_TA0(3'd1);
        REQ_START_TA0(3'd3);
        REQ_START_TA0(3'd2);
        #200    $stop;
    end
    
    // req_start1とta1の関係を生成する
    initial begin
        req_start1 <= 1'b0;
        ta1 <= 1'b0;
        @(negedge reset); // リセットが0になるのを待つ
        #100;
        REQ_START_TA1(3'd2);
        REQ_START_TA1(3'd1);
        REQ_START_TA1(3'd2);
        REQ_START_TA1(3'd3);
        REQ_START_TA1(3'd3);
        REQ_START_TA1(3'd1);
        REQ_START_TA1(3'd2);
    end
    
    // task REQ_START_TA0
    task REQ_START_TA0;
        input [2:0] loop_count;
        

        begin :REQ_START_TA0_PROCESS
            integer i;            
            
            @(posedge clk); // clkの立ち上がりまでwait
            #1 ; // 遅延を挟んで
            req_start0 = 1'b1;
            @(posedge clk); // clkの立ち上がりまでwait
            #1; // 遅延を挟んで
            req_start0 = 1'b0;
            
            for(i=loop_count; i>0; i=i-1) begin
                @(posedge clk);
                #1;
            end
            ta0 = 1'b1;
            @(posedge clk); // clkの立ち上がりまでwait
            #1 ; // 遅延を挟んで
            ta0 = 1'b0;
        end
    endtask
    
    // task REQ_START_TA1
    task REQ_START_TA1;
        input [2:0] loop_count;
        

        begin :REQ_START_TA1_PROCESS
            integer i;        
            
            @(posedge clk); // clkの立ち上がりまでwait
            #1 ; // 遅延を挟んで
            req_start1 = 1'b1;
            @(posedge clk); // clkの立ち上がりまでwait
            #1; // 遅延を挟んで
            req_start1 = 1'b0;
            
            for(i=loop_count; i>0; i=i-1) begin
                @(posedge clk);
                #1;
            end
            ta1 = 1'b1;
            @(posedge clk); // clkの立ち上がりまでwait
            #1 ; // 遅延を挟んで
            ta1 = 1'b0;
        end
    endtask
    
    // アサーション
    // ta0がアサートされた次のクロックでack0がアサートされる
    ovl_next #(
        `OVL_ERROR,            // severity_level
        1,                    // num_cks(1クロック後にアサート)
        1,                    // check_overlapping (off)
        1,                    // check_missing_start (on)
        `OVL_ASSERT,        // property_type
        // "ERROR: ta0がアサートされた次のクロックでack0がアサートされていない",
        "ERROR: ack0 isn't asserted of with the next clock that ta0 was asserted.",
        `OVL_COVER_BASIC,    // coverage_level
        `OVL_POSEDGE,        // clock_edge
        `OVL_ACTIVE_HIGH,    // reset_polarity
        `OVL_GATE_CLOCK        // gating_type
    ) ta0_ack0_assertion (
        clk,
        reset,
        1'b1,                // enable
        ta0,                // start event
        ack0,                // test_expr
        fire_ta0_ack0_as    // fire
    );
    
    // ta1がアサートされた次のクロックでack1がアサートされる
    ovl_next #(
        `OVL_ERROR,            // severity_level
        1,                    // num_cks(1クロック後にアサート)
        1,                    // check_overlapping (off)
        1,                    // check_missing_start (on)
        `OVL_ASSERT,        // property_type
        // "ERROR: ta1がアサートされた次のクロックでack1がアサートされていない",
        "ERROR: ack1 isn't asserted of with the next clock that ta1 was asserted.",
        `OVL_COVER_BASIC,    // coverage_level
        `OVL_POSEDGE,        // clock_edge
        `OVL_ACTIVE_HIGH,    // reset_polarity
        `OVL_GATE_CLOCK        // gating_type
    ) ta1_ack1_assertion (
        clk,
        reset,
        1'b1,                // enable
        ta1,                // start event
        ack1,                // test_expr
        fire_ta1_ack1_as    // fire
    );
    
    // req0アサートされた後で、ack0 が2~4クロックの間に1になる
    ovl_frame #(
        `OVL_ERROR,                // severity_level
        2,                        // min_cks
        4,                        // max_cks
        `OVL_IGNORE_NEW_START,    // action_on_new_start
        `OVL_ASSERT,            // property_type
        // "ERROR: req0がアサートされた後の2~4クロック後にack0が1にならない",
        "ERROR: ack0 isn't asserted after 2-4 clocks after req0 was asserted.",
        `OVL_COVER_BASIC,        // coverage_level
        `OVL_POSEDGE,            // clock_edge
        `OVL_ACTIVE_HIGH,    // reset_polarity
        `OVL_GATE_CLOCK        // gating_type
    ) req0_ack0_assertion (
        clk,
        reset,
        1'b1,                // enable
        req0,                // start event
        ack0,                // test_expr
        fire_req0_ack0_as    // fire
    );
        
    // req1アサートされた後で、ack1 が2~4クロックの間に1になる
    ovl_frame #(
        `OVL_ERROR,                // severity_level
        2,                        // min_cks
        4,                        // max_cks
        `OVL_IGNORE_NEW_START,    // action_on_new_start
        `OVL_ASSERT,            // property_type
        // "ERROR: req1がアサートされた後の2~4クロック後にack1が1にならない",
        "ERROR: ack1 isn't asserted after 2-4 clocks after req1 was asserted.",
        `OVL_COVER_BASIC,        // coverage_level
        `OVL_POSEDGE,            // clock_edge
        `OVL_ACTIVE_HIGH,    // reset_polarity
        `OVL_GATE_CLOCK        // gating_type
    ) req1_ack1_assertion (
        clk,
        reset,
        1'b1,                // enable
        req1,                // start event
        ack1,                // test_expr
        fire_req1_ack1_as    // fire
    );
        
endmodule

`default_nettype wire


Veritakの場合には日本語のメッセージを活かしてある。
さて、Veritakを起動して、プロジェクトを作成してシミュレーションしてみた。
下にVeritakのプロジェクトの様子を示す。define値を設定している。今回はOVL_V1のassert_... を使用してないので、.vlibは使用しない。
OVL_req_ack_2_100318.png

次にシミュレーション結果を下の図に示す。
OVL_req_ack_3_100318.png

黒い縦線のところでack0 がアサートされていないのがわかる。これに対応するovl_nextのエラーメッセージを下に示す。

OVL_ERROR : OVL_NEXT : ERROR: ta0がアサートされた次のクロックでack0がアサートされていない : Test expression is not asserted after elapse of num_cks cycles from start event : severity 1 : time 29000 : tb_req_ack.ta0_ack0_assertion.ovl_error_t


これは、fire信号、[2:0]fire_ta0_ack0_as でも確認することができる。値の4はカバーなので、1がアサーション・エラーを示す値となる。
次に、ovl_frame の方だが、330nsec の時点で、アサーション・エラーとなっている。メッセージを下に示す。

OVL_ERROR : OVL_FRAME : ERROR: req0がアサートされた後の2~4クロック後にack0が1にならない : Test expression is not TRUE within specified maximum max_cks cycles from start event : severity 1 : time 33000 : tb_req_ack.req0_ack0_assertion.ovl_error_t


こちらのfire信号、fire_req0_ack0_asは0のままだった。ドライバ記述部に飛んで、記述を見てみたが、すべて0となっていた。ovl_frame のfire はOVLのバージョン2.4ではサポートされていないようだ。

ovl_next とovl_frame アサーションを使用して、波形の自動チェックができることがわかった。エラーが出たらアサーションが止まるようにしておくと良いかもしれない(severity_levelにOVL_ERRORのかわりにOVL_FATALを記述する)。

最後に、ModelSimでもやってみたので、図を下に示す。
OVL_req_ack_4_100318.png
  1. 2010年03月18日 05:20 |
  2. アサーション事始め
  3. | トラックバック:0
  4. | コメント:0

ザイリンクス社のトレーニング、 Virtex-6 ファミリ デザインとSpartan-6 ファミリ デザイン

ザイリンクス社のトレーニング、 Virtex-6 ファミリ デザインとSpartan-6 ファミリ デザインセミナーに登録しました。5月13日と14日、5月25日と26日です。行かれる方がいらっしゃったら、よろしくお願いします。

今日は発表でした。15分発表の5分質疑応答です。明日も発表で、やはり、15分発表の5分質疑応答です。今日は少し緊張してしまったけど、明日はうまくできますように!!!

そうだ!”Spartan3A Starter Kit によるDDR2 SDRAM コントローラの実装”が載っている技術報告がアップされました。
  1. 2010年03月17日 21:39 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:0

OVL(Open Verification Library)を試してみる5(ovl_next, ovl_frame その1)

今回は、ovl_nextとovl_frameを試してみる。今回は例を作るのに時間がかかってしまった。良い例(とはなっていないかもしれないが?)を作るのは大変だと思った。
ovl_nextは、reqの次にackが来るというように、Aという信号がアサートされた後の確定したクロック後にBという信号がアサートされるというアサーションだ。例を見てみよう。下に示したのが実際に書いたovl_nextの記述。

    // ta0がアサートされた次のクロックでack0がアサートされる
    ovl_next #(
        `OVL_ERROR,            // severity_level
        1,                    // num_cks(1クロック後にアサート)
        1,                    // check_overlapping (off)
        1,                    // check_missing_start (on)
        `OVL_ASSERT,        // property_type
        "ERROR: ta0がアサートされた次のクロックでack0がアサートされていない",
        `OVL_COVER_BASIC,    // coverage_level
        `OVL_POSEDGE,        // clock_edge
        `OVL_ACTIVE_HIGH,    // reset_polarity
        `OVL_GATE_CLOCK        // gating_type
    ) ta0_ack0_assertion (
        clk,
        reset,
        1'b1,                // enable
        ta0,                // start event
        ack0,                // test_expr
        fire_ta0_ack0_as    // fire
    );


これはta0がアサートされていから1クロック後に必ずack0がアサートされるということを示したovl_nextのアサーションだ。もし、複雑なRTLコードの2つの信号間に、同じクロック期間でアサートされる関係がある時には、このようなアサーションを設計者が入れておけば、あとでRTLコードを読む人へのメッセージともなることだろう?(どっかで、聞いた?、見た?言葉)

次にovl_frameだが、これはovl_nextはA, B信号間のクロック数は確定している必要がある。ovl_frameは、Aがアサートされてから、最小何クロックから最大何クロックまでにBがアサートされれば良いというアサーションになる。下に例を示す。

    // req0アサートされた後で、ack0 が2~4クロックの間に1になる
    ovl_frame #(
        `OVL_ERROR,                // severity_level
        2,                        // min_cks
        4,                        // max_cks
        `OVL_IGNORE_NEW_START,    // action_on_new_start
        `OVL_ASSERT,            // property_type
        "ERROR: req0がアサートされた後の2~4クロック後にack0が1にならない",
        `OVL_COVER_BASIC,        // coverage_level
        `OVL_POSEDGE,            // clock_edge
        `OVL_ACTIVE_HIGH,    // reset_polarity
        `OVL_GATE_CLOCK        // gating_type
    ) req0_ack0_assertion (
        clk,
        reset,
        1'b1,                // enable
        req0,                // start event
        ack0,                // test_expr
        fire_req0_ack0_as    // fire
    );


OVL_IGNORE_NEW_STARTを定義してあるので、Aの信号req0はパルスではなくて、アサートされ続ける信号でも問題ない。
次は、実際に例を作って、結果を見てみることにする。(もう作って、やってありますが。。。)

参考文献:Accellera Standard OVL V2 Library Reference Manual Software Version 2.4 March 2009
  1. 2010年03月17日 05:25 |
  2. アサーション事始め
  3. | トラックバック:0
  4. | コメント:0

ISEのMAPのプロパティのIOBのFFを使うオプションがデフォルトでOFFになっていた

なひたふJTAG日記”さんの”ISE11でPack I/O Registersの設定オプションにご注意”を読んでびっくり!!!
なんと、ISE11のMAPのプロパティの”Pack I/O Registers/Latches into IOBs”がデフォルトでOFFになっているとのことだった。今、自分のプロジェクトを見てみたが、OFFになっていた。ショック!!!全く気がつかなかった。
今まで、動かなくて(というか、微妙に結果が違っていて)悩んでいたが、For Inputs and Outputs にしたら、あっさりうまく行った。XSTが悪いんではなかった。てっきり、Synplify Proでうまく行って、XSTでダメだからXSTが悪いのか?と思っていた。(XSTのプロジェクトはISE11.4)
Synplify Pro用のISE10.1.3でも、”Pack I/O Registers/Latches into IOBs”はOFFだったので、ISE10からデフォルト値がOFFになったのかもしれない?
ショックだったが、冷静に考えてみると、制約に足りない部分があるのかもしれない?または、ワーストケースではなく、ベストケース?のためかもしれない。
もしかして、以前のキャラクタ描画テスト回路も、もしかしたら、そういう部分が原因か?
  1. 2010年03月15日 14:54 |
  2. Xilinx ISEについて
  3. | トラックバック:0
  4. | コメント:0

2010年3月14日の日記

昨日と今日は、息子の高校への通学路をどうするかを決定するために、A駅とB駅に自転車で行ってきました。A駅は7.4Km位で昨日、自転車で行ってきたのですが、約30分でした。そこからディーゼル汽車に乗って4つ目の駅で降りて、歩いて約10分で高校に着きました。降りてみると懐かしい公園とスーパーが。。。昔々、この公園で子どもたちを遊ばせたことがありました。実は、奥さんの実家のお母さんが良く行くスーパーでした。
高校まで行ったら目的は果たしたので、また下りに乗ってA駅まで来ると、息子が具合が悪いとのこと。。。困った。しょうがないので、私だけ自転車でかえって、息子はじいちゃんに迎えに来てもらいました。後で、車で自転車を取りに来ました。
今日は、息子は大丈夫そうだったで、B駅に自転車で行ってみました。B駅はA駅の2つ手前の駅ですが、家からの距離は約5Kmです。途中は車が良く通り、歩道も狭くて、自転車の通行は危なそうでした。駅まで約22分でした。ですが、B駅からA駅まではディーゼル汽車で7分かかるので、家を出る時間は大体一緒です。よって、A駅まで自転車で行くことに決定しました。

天気が良くて風がなければ、自転車も良いですね。私も自転車で通勤しようかな?約11Kmなので、50分くらいでしょうか?風がなく、天気が良い日だけですけどね。
今日は、午後には、グランステージに行って、また2X4X10F防腐剤入の木材を10本、買ってきました。家の補修に使います。また日曜大工になりそうです。

今週は、水曜日、木曜日と発表が2回あります。頑張らないと。。。金曜日は高校の説明会(これは奥さんが行きます)で、土、日と山形蔵王にスキーに行きます。忙しい。。。
  1. 2010年03月14日 19:59 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

OVL(Open Verification Library)を試してみる4(OVL_range)

今回は、今までのassert_range をOVL V2のovl_range に書き換えてみようと思う。なお、std_ovl/docs/pdfdocs/ovl_lrm.pdf (Accellera Standard OVL V2 Library Reference Manual) を参考にしている。
まずは、OVL V1のassert_rangeは今までやってきた通り。

   assert_range #(
                  /*severity_level*/`OVL_FATAL, 
                  /*width*/ 4, 
                  /*min  */ 0, 
                  /*max  */ 9, 
                  /*property_type */`OVL_ASSERT, 
                  /*msg*/ "The counter arrived at invalid range.", 
                  /*coverage_level*/`OVL_COVER_CORNER)
     counter_checker_inst (
                           .clk(ICLK), 
                           .reset_n(~IRST), 
                           .test_expr(OCOUT));


次に、OVL V2のovl_range で書き換えた例を示す。なお、このovl_range は論理合成可能だそうだ。

   ovl_range #(
                `OVL_FATAL,         // severity_level
                4,                     // width
                0,                     // min
                9,                     // max
                `OVL_ASSERT,         // property_type
                "The counter arrived at invalid range.", 
                `OVL_COVER_CORNER,    // coverage_level
                `OVL_POSEDGE,        // clock edge
                `OVL_ACTIVE_HIGH,    // reset_polarity
                `OVL_GATE_CLOCK)    // gating type
     counter_checker_inst (
                .clock(ICLK), 
                .reset(IRST), 
                .enable(1'b1),
                .test_expr(OCOUT),
                .fire(fire)
    );


パラメータでは、clock edge、reset_polarity、gating typeが増えている。ポートではenableとfire が増えている。
fire の定義は、 wire [`OVL_FIRE_WIDTH-1:0] fire; で、OVL_FIRE_WIDTHは3だ。fire[0] は、アサーションの失敗した時に1になる。fire[1] はX/Zチェックが失敗した時に1になる(X/ZチェックはXやZになったときだろうか?)。fire[2] はカバー・イベントがあった時に1になるそうだ。つまり今は、OVL_COVER_CORNERにしているので、コーナーの時、つまりOCONTが0と9の時に1になるのだと思われる。
この修正後にシミュレーションをしてみた結果を下に示す。
OVL_sample_7_100312.png

コーナーの値0と9の次のクロックでfire[2]が1となるのがわかる。
次に、coverage_levelをOVL_COVER_BASICとしてコーナーの値でカバーを出さないようにして、max値を8として、わざとアサーションを失敗させてみよう。これでシミュレーションしてみたのが下の図。
OVL_sample_8_100312.png

235ステップ目でOCOUTが9となって、アサーションを失敗して、OVL_FATALになったので、335ステップ目でfinish している。ここで、severity_levelをOVL_ERRORにして再度シミュレーションを行うと、OCOUTが9になったときにfire[0] が1となる。
OVL_sample_9_100312.png

severity_levelがOVL_FATALの時に、アサーションが失敗した時からシミュレーションが終了するまでの時間は、グローバルのマクロ、OVL_RUNTIME_AFTER_FATALで設定することができる。デフォルト値は100だ。
  1. 2010年03月13日 13:16 |
  2. アサーション事始め
  3. | トラックバック:0
  4. | コメント:0

息子が高校に合格した

昨日は息子の高校の合格発表の日なので、半日休暇をとりました。午前9時から高校で発表で、午前9時30分にWeb上でも発表されました。うちではWeb上で見て合格を知りました。おめでとう。。。
11時に昨日卒業式だった中学校に行って、合格証書をもらってきました。親としても嬉しかったです。
思えば、息子は小学6年生の時に身体表現性障害の疼痛性障害で4ヶ月半入院して、中学校でも1,2年は保健室登校のようなもので、全く勉強していませんでした。3年になったときに高校に行きたいと思って、大変な思いをしながら、教室に戻って勉強。塾にも行かせましたが、3年生のおわりには成績は3倍以上になりました。それでも進学校は無理ですが、大学も狙える高校に合格することができました。親としてもうれしいです。残念なのは、受験による?友人との軋轢で、最後に中学に行けなくなって、卒業式にもでられなかったことです。ですが、高校生になったら新たな気持で頑張るようです。
高校も中学の人が余り行かない高校を選んだため、距離が遠いので、今度の土日には、どういうルートで高校に通えるかやってみたいと思います。
とにかくめでたいので、昨日は家族全員でお寿司に行ってきました。(#回るお寿司ですよ。。。)

そういえば、エレキジャック・フォーラム「プロの技」トーク・ショーのすべてに登録しました。講師の皆様、楽しみにしています。すごい方ばかりなので、4月24日が楽しみです。
  1. 2010年03月12日 05:05 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:8

OVL(Open Verification Library)を試してみる3(アサーションの説明)

はじめの一歩-テストベンチ-”に書かれているassert_range アサーションはある信号の値が自分の意図する範囲に入っているのかを確認するアサーションだ。アサーションとは、検証する必要のある設計意図としての動作、つまりプロパティに対する記述分だそうだ。(アサーションベース設計、原書2版、第1章はじめに、4ページより引用)つまりRTLで動作を記述するのだが、RTLではいろいろなステートマシンやその他のカウンタやロジックなどが複雑にからみ合って記述する必要がある場合がある。その信号だけを考えてみよう。その場合に、その信号は例えば4ビットのバイナリなんだけど、10進数を表していて、取りうる値の範囲は0~9までという設計だったとしよう。多分、このRTLコードには、間違いは少ないと思うが、その信号のプロパティとしての値の範囲は0~9ということを検証しようとする。そのときに使えるのがアサーションということになる。アサーション記述言語には、OVL、PSL、SystemVerilogアサーションの3つが有名らしいが、そのうちのPSL、SystemVerilogアサーションは対応するシミュレーターが必要となる。OVLはライブラリとしてコンパイルすれば、どのシミュレーターでもアサーションを記述することができる。
これまで、アサーション記述言語のことを書いてきたが、Verilogでもアサーションを書くことができる。例えば、キャラクタ描画テスト回路のFIFOのoverflow, underflowが出ているかどうかを見るために、シミュレーション限定でVerilogコードによるアサーションを書いてあった。本来、FIFOのoverflow, underflowは起こらないように制御するものであるが、制御コードのバグによって起こってしまう場合がある。アサーションによってそれを監視していれば、起こった時にすぐわかるわけだ。それが分からないと、なかなかデバックが難しくなったりする。下に示すのは、ビットマップVGAコントローラに使用した非同期FIFOのアサーションだ。この非同期FIFOには、underflow, overflow端子を生成しておいたので、それがアサートされるかどうかをチェックしている。

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


ちょっと日本語になっているのが微妙ですが、Veritak用ということで。。。
これだけだが、これでunderflowやoverflowを検出できてずいぶんと助かった。
さて、OVL V1でこれをやろうとすると、assrt_neverを使うのだろう。上のVerilogアサーションと等価に書くには、下のように書けば良いと思う。

    // アサーション
    // synthesis translate_off
    assert_never #(`OVL_FATAL, 0, "ERROR : FIFOが空なのにリードした") fifo_underflow_assertion(clk_ddr2, ~reset_ddr2, afifo_underflow);
    assert_never #(`OVL_FATAL, 0, "ERROR : FIFOがフルなのにライトした") fifo_overflow_assertion(clk_ddr2, ~reset_ddr2, afifo_overflow);
    // synthesis translate_on


上の記述は確かめていないので、動くかどうかわかりません。あくまでもイメージということでお願いします。(動かなかったら教えてください)
というわけで、数行に渡っていたVerilogのアサーションがOVL V1を使うと、1行で書くことができる。こんな簡単なアサーションだけではなく、例えば、requestとackの関係はassert_nextによって検証することができる。

次はassert_で表されるOVL V1のアサーションをovl_で始まるOVL V2のアサーションに書き換えてみる。OVL V2は、機能が拡張されていて、OVL V1を含んでいるそうだ。

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

OVL(Open Verification Library)を試してみる2(Veritakを使用する)

前回はModelSimでOVLを使用したが、今度はVeritakでもOVLを使えるかどうかを試してみた。
まずは、Veritakを起動してovl_sampleというプロジェクトを生成する。(私のブログのVeritakのチュートリアルを参照
ovl_sampleのコマンドファイルのcomplie.f を下に引用させて頂く。

ovl_example/sim/compile.f-------------------------------------
 1    +define+OVL_ASSERT_ON
 2    +define+OVL_COVER_ON
 3    +define+OVL_MAX_REPORT_ERROR=1
 4    +define+OVL_INIT_MSG
 5    +libext+.v+.vlib
 6    -y ../std_ovl
 7    +incdir+../std_ovl
 8    +incdir+../tb
 9    ../tb/top.v
10    +incdir+../rtl
11    ../rtl/decimal_counter.v
----------------------------------------------------------- 


complie.fの記述を参考に、Veritakのプロジェクトにファイルを追加する。ここでコンパイルするファイルは../tb/top.vと../rtl/decimal_counter.vだ。
Add Include Dirボタンで、インクルードするフォルダを指定する。7の+incdir+../std_ov だけで良さそうだ。
Add Lib Dirボタンで、ライブラリのあるフォルダを指定する。6番の-y ../std_ovlがライブラリを指定するフォルダで、5番の+libext+.v+.vlibで、ライブラリとして指定するファイルの拡張子を決定する。この機能はVeritakのこのマニアルによると、Add Lib Extボタンで追加出来るそうなのだけれど、Veritakのプロジェクトの設定画面にそのボタンが無い。Veritak BasicにはなくてProの機能なのだろうか?
define はどこで追加すると言うと、Def/Plus/Top のテキストボックスに書いて、Add Defineボタンをクリックするとdefineが適用されるらしい。compile.f の1,2,3,4番のdefineを入力した。
OVL_sample_3_100310.png

これでSave Projectボタンをクリックして、Exitボタンをクリックし、Load Verilogプロジェクトした。その結果、counter_checker_instモジュールが見つからないというエラーが出てしまった。counter_checker_instモジュールの実体は、assert_rangeなので、assert_range.vlibがライブラリとして定義出来ないのが、まずいようだ。
OVL_sample_4_100310.png

Veritakのサポートに聞いてみることにする。
(2010/03/11:追記)
Veritakのサポートに連絡したところ、早速、Add Lib Extボタンを追加して頂いた。たっくさんありがとうございました。Veritakのバージョンは3.77Eだ。
Add Lib Extボタンでvlibもライブラリとして解釈される。vlibを追加した。
OVL_sample_5_100310.png

タックさんに教えて頂いたのだが、このままシミュレーションをスタートすると、ずっとシミュレーションをやり続けてしまう。そこで、500nsecで終了するように設定する。シミュレーションメニューからRun Lengthを選択すると、ダイアログが出る。ダイアログで、Enter Time Integerに500ns を入力し、Enableをチェックした。これで500nsec シミュレーション後に停止するようだ。
シミュレーション後の様子を下図に示す。無事にシミュレーションすることができた。
OVL_sample_6_100311.png
  1. 2010年03月10日 05:51 |
  2. アサーション事始め
  3. | トラックバック:0
  4. | コメント:0

OVL(Open Verification Library)を試してみる1

次は、”OVL(Open Verification Library)フリーな検証ライブラリの話題”を見ながら、OVLを試してみようと思う。OVLはVerilogやVHDLでアサーションを利用できるライブラリだ。今までやってきたDPI-Cを使用するテストベンチはSystemVerilogの環境でないと動作しない。SystemVerilogのアサーションも約二年前にセミナを受けてきたが、Questaがないので使用できない。やはり、普段使っている言語でアサーションを簡単にかければ、デバック効率が格段に上がるのでは?と思う。デバックも何千という波形を見て、動作しているかどうかを人間が判定していると、自分が注目している動作は動作していても、他の注目していない部分がおかしくなっていることがある。その異常な動作が、すぐには他のところに波及せずに、大分シミュレーション時間が経過してから、他の部分に異常な動作となって現れる場合がある。そこで異常動作がわかっても、原因を追求するのが、難しい場合がある。その時に、最初に異常な動作が現れた最初の段階で、おかしいよと言ってくれるとデバックがとても助かる。アサーションにはそんな、チェッカーの役割を期待している。例えば、FIFOのオーバフーロー、アンダーフローをチェックするアサーションをVerilogで書いただけでも、相当便利だ。FIFOはオーバフーロー、アンダーフローを起こさないように、制御するはずなので、制御ロジックが不良なのが1発で分る。と言った訳でOVLをやってみたいと思った。
まずは”入手とインストール”を見ながら、OVLをダウンロードする。現在のバージョンは2.4だった。

(2013/06/27:追記)現在のOVL Ver. 2.7 の入手先は、”License and Statement of Use of Accellera System Initiative's Open Verification Library”です。そのWebページの”Accept agreement and proceed to download OVL.”をクリックするとダウンロード出来ます。

はじめの一歩”を参考に、ovl_example.zipをダウンロードして展開した。ovl_example/std_ovl にダウンロードしたOVL(std_ovl フォルダの内容)をコピーする。
OVLのアサーションは、tbフォルダのtop.vに書いてあるassert_rangeが使われている(はじめの一歩-テストベンチ-)。これは、アサーションベース設計、原書2版(たぶん、この本が唯一日本語で書かれているOVLの本だと思うんだけど?)の394~395ページに書かれている。それによると、assert_rangeアサーションは回路の中で、カウンタやステートマシンの値が適切な範囲にあることを保証するアサーションだそうだ。
さて、前回まで使ってきた。ModelSim AE 6.5bを起動する。”はじめの一歩”にはプロジェクトを作成することは書いていないが、前回のavalon_bfm_sim プロジェクトに上書きしても何なので、ovl_sampleプロジェクトを作成する。作成するフォルダは、ovl_example\sim とする。
FileメニューからNew -> Project... を選んで、ovl_sampleプロジェクトを作成する。ここでModelSimのキャプチャ図を貼ろうと思ったのだが、PrintScreenしておいたはずの図がなくなってしまったので省略。
OVL_sample_1_100309.png

Transcriptペインで、do all.do を実行する。するとシミュレーションがスタートした。
OVL_sample_2_100309.png

あっさりと出来ました。ログを下に示す。

do all.do
# ** Warning: (vlib-34) Library already exists at "work".
# Model Technology ModelSim ALTERA vlog 6.5b Compiler 2009.10 Oct 1 2009
# -- Compiling module clkgen
# -- Compiling module control
# -- Compiling module top
# -- Compiling module decimal_counter
# -- Scanning library directory '../std_ovl'
# -- Compiling module assert_range
#
# Top level modules:
# top
# vsim -do wave.do -l transcript.log -c top
# Loading work.top
# Loading work.clkgen
# Loading work.control
# Loading work.decimal_counter
# Loading work.assert_range
# do wave.do
# OVL_NOTE: V2.4: ASSERT_RANGE initialized @ top.counter_checker_inst.ovl_init_msg_t Severity: 0, Message: The counter arrived at invalid range.
# OVL_COVER_POINT : ASSERT_RANGE : test_expr_at_min covered : time 105 : top.counter_checker_inst.ovl_cover_t
# OVL_COVER_POINT : ASSERT_RANGE : test_expr_at_min covered : time 115 : top.counter_checker_inst.ovl_cover_t
# OVL_COVER_POINT : ASSERT_RANGE : test_expr_at_min covered : time 125 : top.counter_checker_inst.ovl_cover_t
# OVL_COVER_POINT : ASSERT_RANGE : test_expr_at_max covered : time 235 : top.counter_checker_inst.ovl_cover_t
# OVL_COVER_POINT : ASSERT_RANGE : test_expr_at_min covered : time 245 : top.counter_checker_inst.ovl_cover_t
# OVL_COVER_POINT : ASSERT_RANGE : test_expr_at_min covered : time 255 : top.counter_checker_inst.ovl_cover_t
# OVL_COVER_POINT : ASSERT_RANGE : test_expr_at_max covered : time 415 : top.counter_checker_inst.ovl_cover_t
# OVL_COVER_POINT : ASSERT_RANGE : test_expr_at_min covered : time 425 : top.counter_checker_inst.ovl_cover_t
# OVL_COVER_POINT : ASSERT_RANGE : test_expr_at_min covered : time 435 : top.counter_checker_inst.ovl_cover_t
# OVL_COVER_POINT : ASSERT_RANGE : test_expr_at_min covered : time 445 : top.counter_checker_inst.ovl_cover_t
# OVL_COVER_POINT : ASSERT_RANGE : test_expr_at_min covered : time 455 : top.counter_checker_inst.ovl_cover_t
# OVL_COVER_POINT : ASSERT_RANGE : test_expr_at_min covered : time 465 : top.counter_checker_inst.ovl_cover_t



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

パーシー・ジャクソンとオリンポスの神々を見てきました

今日は、イーアスで、下の娘と”パーシー・ジャクソンとオリンポスの神々”という映画を見てきました。なかなか面白かったのですが、面白いB級映画という感じでした。何で、B級映画とおもったか?と自分で考えてみたら、ストーリーが安易だと感じたからみたいです。
その後は、お寿司を食べて、お買い物して帰ってきました。ミスタードーナツを買ったのですが、まだ食べていません。おやつかな?子供は2つ、大人は1つです。私は、オールドファッション 抹茶チョコにしました。
  1. 2010年03月07日 15:23 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

無償ツールで実践する「ハード・ソフト協調検証」をやってみる7(DMAの割り込み機能)

さて、最後の”無償ツールで実践する「ハード・ソフト協調検証」(7) ―― DMAの割り込み機能を確かめられるようにする”をやってみようと思う。

avalon_cpuのポートにirq(リスト12)を追加して、割り込みタスク(リスト13)も追加した。export宣言も追加した。最終的にavalon_cpu.sv は下のようになった。

module avalon_cpu (
    input  wire        clk,
    input  wire        reset,
    output wire [31:0] avm_address,
    output wire [2:0]  avm_burstcount,
    input  wire [31:0] avm_readdata,
    output wire [31:0] avm_writedata,
    input  wire        avm_waitrequest,
    output wire        avm_write,
    output wire        avm_read,
    output wire [3:0]  avm_byteenable,
    input  wire        avm_readdatavalid,

    input  wire    [31:0] irq
);
    altera_avalon_mm_master_bfm #(
        .AV_ADDRESS_W             (32),
        .AV_SYMBOL_W              (8),
        .AV_NUMSYMBOLS            (4),
        .AV_BURSTCOUNT_W          (3),
        .USE_READ                 (1),
        .USE_WRITE                (1),
        .USE_ADDRESS              (1),
        .USE_BYTE_ENABLE          (1),
        .USE_BURSTCOUNT           (1),
        .USE_READ_DATA            (1),
        .USE_READ_DATA_VALID      (1),
        .USE_WRITE_DATA           (1),
        .USE_BEGIN_TRANSFER       (0),
        .USE_BEGIN_BURST_TRANSFER (0),
        .USE_WAIT_REQUEST         (1),
        .AV_BURST_LINEWRAP        (1),
        .AV_BURST_BNDR_ONLY       (1),
        .AV_MAX_PENDING_READS     (1),
        .AV_FIX_READ_LATENCY      (1)
    )
    cpu (
        .clk                    (clk),
        .reset                  (reset),
        .avm_address                (avm_address),
        .avm_burstcount         (avm_burstcount),
        .avm_readdata           (avm_readdata),
        .avm_writedata          (avm_writedata),
        .avm_waitrequest        (avm_waitrequest),
        .avm_write              (avm_write),
        .avm_read               (avm_read),
        .avm_byteenable         (avm_byteenable), 
        .avm_readdatavalid      (avm_readdatavalid),
        .avm_begintransfer      (),
        .avm_beginbursttransfer () 
    );
    
    `define BFM cpu

    `ifdef DPI_C
        // =========================================================================
        // DPI-C
        // =========================================================================

        `ifndef TEST_BFM
        import "DPI-C" context task dpi_main();
        `endif // TEST_BFM

        export "DPI-C" task bfm_write32;
        export "DPI-C" task bfm_read32;
        export "DPI-C" task bfm_write16;
        export "DPI-C" task bfm_read16;
        export "DPI-C" task bfm_write8;
        export "DPI-C" task bfm_read8;
        export "DPI-C" task bfm_nop;
        export "DPI-C" task wait_for_interrupt;
        
        // =========================================================================
        // Main
        // =========================================================================

        initial begin

        `BFM.init();

        `ifdef TEST_BFM
        test_bfm;
        `else
        dpi_main();
        `endif // TEST_BFM

        #100;
        $finish(2);
        end

        // =========================================================================
        // Task
        // =========================================================================

        import avalon_mm_pkg::*;

        task wait_for_interrupt( output int unsigned status );
            status = 0;
            wait( irq != 0 );
            status = irq;
        endtask : wait_for_interrupt
        
        task automatic bfm_run( Request_t request, int addr, int byte_enable, inout int data );
.......................
end module;


ポートを追加したので、SOPC Builderの設定を”無償ツールで実践する「ハード・ソフト協調検証」(7)” 図27~図31の様にやり直した
”"interrupt_receiver"のParameters部のAssociated addressable interfaceを「none」から「avalon_master」に変更します(図31).”の所は、avalon_masterではなく、avalon_master_0だった。
図31まで終了した状態のSOPC Builderの様子を下に示す。
hard_soft_25_100306.png

右側のペインにIRQが追加された。

次にDMA Controllerを追加する。同様に”無償ツールで実践する「ハード・ソフト協調検証」(7) ”の図32, 図33 の様にDMA Controller を追加中の図を下に示す。
hard_soft_26_100306.png

無償ツールで実践する「ハード・ソフト協調検証」(7)の図35のようにDMA Controllerを接続した。下図が接続後。
hard_soft_27_100306.png

ここでGenerateボタンでGenerateする。Generateは成功した。

●シミュレーションの準備を行う
ここでvlog の+defineオプションがでてきた。DPC_Cの他にDEBUGもdefineするみたいだ。私は、ライブラリ化の時に使ったsetup_sim_lib.do をsetup_sim_dma.do に名前を変更して、DEBUGのdefine を追加した。
setup_sim_dma.do の_vsim を下のように変更した。

alias _vsim {vsim -t ps +nowarnTFMPC -sv_root prog -sv_lib dpi_main_dma -L lpm_ver -L sgate_ver -L altera_mf_ver -L altgxb_ver -L stratixiigx_hssi_ver -L stratixgx_ver -L stratixgx_gxb_ver -L stratixiigx -L altera_ver -L stratixiii_ver -L stratixii_ver -L cycloneii_ver -L cycloneiii_ver -L stratixiv_hssi_ver -L arriaii_ver -L arriaii_pcie_hip_ver -L arriaii_hssi_ver -L stratixiv_pcie_hip_ver -L cycloneiv_pcie_hip_ver -L cycloneiv_hssi_ver -L hardcopyiv_pcie_hip_ver -L hardcopyiv_hssi_ver test_bench} } else {
alias _vsim {vsim -t ps +nowarnTFMPC -sv_root prog -sv_lib dpi_main_dma test_bench } }



●テスト・プログラムを用意する
リスト14に示されたテストプログラムをdpi_main_dma.c としてセーブした。たぶん、リスト14の前に #include "dpi_func.h" を付ける必要があるはずなので、それを1行目に追加した。

MSYSを立ち上げて、avalon_bfm/avalon_bfm_sim/prog にcd して、dpi_main_dma.c をコンパイルする。

gcc -c dpi_main_dma.c


そうしたら、DMA_READ_REGなどが定義されていないとしてエラー発生。当然そうなりますね?
hard_soft_28_100307.png

どうしようと思ったが、考えてみれば、図37にログがあるので、そこから推測できるはず。。。しかし、DMA Controller のマニュアルはどこにあるんだろう?HelpやAlteraのサイトを探してみたが良くわからなかったが、SOPC Builder のDMA Controller をクリックし、Editボタンをクリックすると出てくる設定ダイアログにDocumentaion ボタンが有った。これをクリックすると、データシートが出てきた。DMA Controllerのデータシートはこれ。7ページのTable 24–3. DMA Controller Register Mapを見るとレジスタのマップがわかる。それを下に転載する。
hard_soft_29_100307.png

これを元に定義値を推測して、dma_define.h を書いている。dma_define.h を下に示す。

// dma_define.h

#define    DMA_STATUS_REG    0x10000000
#define DMA_READ_REG    0x10000004
#define DMA_WRITE_REG    0x10000008
#define    DMA_LENGTH_REG    0x1000000c
#define    DMA_CONTROL_REG    0x10000018

// DMA_CONTROL_REGの値の定義
#define DMA_CONTROL_SOFTWARERESET    0x1000
#define DMA_CONTROL_QUADWORD         0x800    
#define DMA_CONTROL_DOUBLEWORD         0x400
#define DMA_CONTROL_WCON             0x200
#define DMA_CONTROL_RCON             0x100
#define    DMA_CONTROL_LEEN              0x80
#define DMA_CONTROL_WEEN              0x40
#define DMA_CONTROL_REEN              0x20
#define    DMA_CONTROL_I_EN              0x10
#define DMA_CONTROL_GO                   0x8
#define DMA_CONTROL_WORD               0x4
#define DMA_CONTROL_HW                   0x2
#define DMA_CONTROL_BYTE               0x1

// DMA_STATUS_REGの値の定義
#define DMA_STATUS_LEN    0x10
#define DMA_STATUS_WEOP     0x8
#define DMA_STATUS_REOP     0x4
#define DMA_STATUS_BUSY     0x2
#define DMA_STATUS_DONE     0x1


dpi_main_dma.c の最初に、

#include "dma_define.h"


を追加した。
gccでコンパイルすると成功した。dpi_main_dma.o が生成できた。

しまった。SystemVerilogコードをコンパイルするのを忘れてしまった。
ModelSim AE 6.5bを立ち上げて、avalon_bfm_sim.mpf をロードして、

do setup_sim_dma.do


を実行する。
hard_soft_30_100307.png

s


コマンドを実行する。

vsim -c -dpiexportobj prog/exportobj.obj test_bench


コマンドを実行する。

これでまたMSYSに戻って、

gcc -shared -o dpi_main_dma.dll dpi_mai_dma.o exportobj.obj \/c/altera/91/modelsim_ase/win32aloem/mtipli.dll


で、dpi_main_dma.dll を作る。

もう一度、ModelSim AE 6.5bに戻って、_vsim を実行する。
hard_soft_31_100307.png

シミュレーションがスタートするので、InstanceウインドウのsimタブでDUT -> avalon_cpu を選択すると、Objectウインドウに信号が表示されるので、waveウインドウのドラックアンドドロップして、RadixをHexadecimal とする。
hard_soft_32_100307.png

run -all


コマンドを実行した。うまく行ったみたいです。
hard_soft_33_100307.png

ログを下に示す。

#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: - Hello from altera_avalon_mm_master_bfm
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   $Revision: #2 $
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   $Date: 2009/08/28 $
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   AV_ADDRESS_W             = 32
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   AV_SYMBOL_W              = 8
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   AV_NUMSYMBOLS            = 4
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   AV_BURSTCOUNT_W          = 3
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   USE_READ                 = 1
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   USE_WRITE                = 1
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   USE_ADDRESS              = 1
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   USE_BYTE_ENABLE          = 1
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   USE_BURSTCOUNT           = 1
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   USE_READ_DATA            = 1
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   USE_READ_DATA_VALID      = 1
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   USE_WRITE_DATA           = 1
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   USE_BEGIN_TRANSFER       = 0
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   USE_BEGIN_BURST_TRANSFER = 0
#                    0: INFO: test_bench.DUT.the_avalon_cpu_0.avalon_cpu_0.cpu.hello: -   USE_WAIT_REQUEST         = 1
#                    0: INFO: ------------------------------------------------------------
# bfm_write32 : addr = 0x00000000, data = 0x12345678
# bfm_write32 : addr = 0x00000004, data = 0x12345678
# bfm_write32 : addr = 0x00000008, data = 0x12345678
# bfm_write32 : addr = 0x0000000c, data = 0x12345678
# bfm_write32 : addr = 0x00000010, data = 0x12345678
# bfm_write32 : addr = 0x00000014, data = 0x12345678
# bfm_write32 : addr = 0x00000018, data = 0x12345678
# bfm_write32 : addr = 0x0000001c, data = 0x12345678
# bfm_write32 : addr = 0x00000020, data = 0x12345678
# bfm_write32 : addr = 0x00000024, data = 0x12345678
# bfm_write32 : addr = 0x00000028, data = 0x12345678
# bfm_write32 : addr = 0x0000002c, data = 0x12345678
# bfm_write32 : addr = 0x00000030, data = 0x12345678
# bfm_write32 : addr = 0x00000034, data = 0x12345678
# bfm_write32 : addr = 0x00000038, data = 0x12345678
# bfm_write32 : addr = 0x0000003c, data = 0x12345678
# bfm_write32 : addr = 0x10000004, data = 0x00000000
# bfm_write32 : addr = 0x10000008, data = 0x00000800
# bfm_write32 : addr = 0x1000000c, data = 0x00000040
# bfm_write32 : addr = 0x10000018, data = 0x0000009c
# Interrput = 0x1
# bfm_read32  : addr = 0x10000000, data = 0x00000011
# bfm_write32 : addr = 0x10000000, data = 0x00000011
# bfm_read32  : addr = 0x00001000, data = 0x12345678
# bfm_read32  : addr = 0x00001004, data = 0x12345678
# bfm_read32  : addr = 0x00001008, data = 0x12345678
# bfm_read32  : addr = 0x0000100c, data = 0x12345678
# bfm_read32  : addr = 0x00001010, data = 0x12345678
# bfm_read32  : addr = 0x00001014, data = 0x12345678
# bfm_read32  : addr = 0x00001018, data = 0x12345678
# bfm_read32  : addr = 0x0000101c, data = 0x12345678
# bfm_read32  : addr = 0x00001020, data = 0x12345678
# bfm_read32  : addr = 0x00001024, data = 0x12345678
# bfm_read32  : addr = 0x00001028, data = 0x12345678
# bfm_read32  : addr = 0x0000102c, data = 0x12345678
# bfm_read32  : addr = 0x00001030, data = 0x12345678
# bfm_read32  : addr = 0x00001034, data = 0x12345678
# bfm_read32  : addr = 0x00001038, data = 0x12345678
# bfm_read32  : addr = 0x0000103c, data = 0x12345678
# ** Note: Data structure takes 7471320 bytes of memory
#          Process time 0.12 seconds
#          $finish    : ../avalon_bfm_sim/avalon_cpu.sv(88)
#    Time: 3490100 ps  Iteration: 0  Instance: /test_bench/DUT/the_avalon_cpu_0/avalon_cpu_0
# 1
# Break in Module avalon_cpu at ../avalon_bfm_sim/avalon_cpu.sv line 88


これで終了とする。
  1. 2010年03月07日 05:31 |
  2. SystemVerilog
  3. | トラックバック:0
  4. | コメント:0

庭の梅

庭の梅が満開です。つくばの梅まつりに行こうと思っていたのですが、奥さんも忙しいし、家にいます。でも食器洗いや換気扇フィルタの交換、灯油購入、給湯器タンクへの灯油入れなどに結構忙しいです。
ume_1_100306.jpg

ume_2_100306.jpg

  1. 2010年03月06日 15:34 |
  2. 日記
  3. | トラックバック:0
  4. | コメント:0

技術発表会と技術研究会で発表

3月17日に技術発表会で”Spartan3A Starter Kit による DDR2 SDRAM コントローラの実装”という題で発表します。あまりFPGAをやっている人がいないので、かなり一般的な内容にしています。もし、近くの方で聞きにこられる方がいらしたら聴きに来てください。プログラムはここです(予稿だけ見られて、報告書は発表後に公開されます)。でも他は全く関係ない発表内容です。

3月18日には、(連チャンで発表です)技術研究会で、”FPGAを使用したCMOSカメラ・ディスプレイ回路の製作”という題で発表します。プログラムはここです。報告書はCMOSカメラでとった画像が液晶ディスプレイに表示されるまでですが、発表では、エッジ検出フィルタ、ラプラシアンフィルタの画像、MPウェーブレット変換後の画像なども紹介する予定です。こっちは参加申し込みはもう締切で、参加申し込みはできないのかな?

#バッチリ所属と名前が入っているので、誰だかバレちゃいますね。。。
  1. 2010年03月06日 05:29 |
  2. その他のFPGAの話題
  3. | トラックバック:0
  4. | コメント:2

無償ツールで実践する「ハード・ソフト協調検証」をやってみる6(ライブラリ化のまとめ)

さて、avalon_cpuにaltera_avalon_mm_master_bfmモジュールとSystemVerilogのコードをまとめたメリットについてまとめてみようと思う。
以前は、”無償ツールで実践する「ハード・ソフト協調検証」をやってみる4(シミュレーション)”の様に、SOPC BuilderでインスタンスしたAvalon-MM Master BFMとテストするスレーブデバイスのAvalon-MM Slave(onchi_memory2_0)、SystemVerilogファイルのtb_prog.sv、C言語で書かれたテストベンチ(dpi_main.c)があった。
そして、下図の様な接続になっていた。
hard_soft_18_100302.png

最初に、SystemVerilogファイル(tb_prog.sv)のinitial文からCの関数 dpi_main()を呼び出す。dpi_main()から test32(), test16(), test8() を呼び出し、その中から tb_prog.svのtaskを呼び出す。そこから、Avalon-MM Master BFMのAvalon Master BFM API(set_command_addressなど)を呼び出して、Avalon-MM Slave(onchi_memory2_0)に読み書きする。

次にライブラリ化をした場合だが、
Avalon-MM Master BFMをインスタンスして、その後にSystemVerilogファイルが追加されて1つのファイル(avalon_cpu.sv)になっている。この接続図を図に書くと下のようになる。
hard_soft_24_100306.png

ここでのメリットを列挙すると
1. `BFM.set_command_request()などで使われる。`BFMで指定された階層情報を含んだvalon-MM Master BFMのインスタンス名が、cpuだけとなって、階層が変わったときに変更する必要がない。
2. avalon_cpu.sv にポートを追加して、機能を拡張することができる。(”無償ツールで実践する「ハード・ソフト協調検証」(7) ―― DMAの割り込み機能を確かめられるようにする”を参照)
  1. 2010年03月06日 05:10 |
  2. SystemVerilog
  3. | トラックバック:0
  4. | コメント:0

無償ツールで実践する「ハード・ソフト協調検証」をやってみる5(ライブラリ化)

17.ライブラリ化する
無償ツールで実践する「ハード・ソフト協調検証」(6) ―― 協調シミュレーションを実行するの2ページ目の”17.ライブラリ化する”のavalon_cpu.svのコードをコピーして、avalon_cpu.svとしてセーブした。これにtb_prog.svファイルを追加した。avalon_cpu.svファイルに一部を示す。(リスト11のコードを引用させていただきます。)

module avalon_cpu (
    input  wire        clk,
    input  wire        reset,
    output wire [31:0] avm_address,
    output wire [2:0]  avm_burstcount,
    input  wire [31:0] avm_readdata,
    output wire [31:0] avm_writedata,
    input  wire        avm_waitrequest,
    output wire        avm_write,
    output wire        avm_read,
    output wire [3:0]  avm_byteenable,
    input  wire        avm_readdatavalid        
);
    altera_avalon_mm_master_bfm #(
    )
    .............. // AV_ADDRESS_W 等の定義
    cpu (
        .clk                    (clk),
        .reset                  (reset),
        .address                (avm_address),
        .avm_burstcount         (avm_burstcount),
        .avm_readdata           (avm_readdata),
        .avm_writedata          (avm_writedata),
        .avm_waitrequest        (avm_waitrequest),
        .avm_write              (avm_write),
        .avm_read               (avm_read),
        .avm_byteenable         (avm_byteenable), 
        .avm_readdatavalid      (avm_readdatavalid),
        .avm_begintransfer      (),
        .avm_beginbursttransfer () 
    );
    
    `define BFM cpu


    // =========================================================================
    // DPI-C
    // =========================================================================

    `ifndef TEST_BFM
    import "DPI-C" context task dpi_main();
    `endif // TEST_BFM

    export "DPI-C" task bfm_write32;
    export "DPI-C" task bfm_read32;
    export "DPI-C" task bfm_write16;
    export "DPI-C" task bfm_read16;
    export "DPI-C" task bfm_write8;
    export "DPI-C" task bfm_read8;
    export "DPI-C" task bfm_nop;

    // =========================================================================
    // Main
    // =========================================================================

    initial begin

    `BFM.init();

    `ifdef TEST_BFM
    test_bfm;
    `else
    dpi_main();
    `endif // TEST_BFM

    #100;
    $finish(2);
    end
    
    ............ // tb_prog.svの残り
    
endmodule : avalon_cpu 


System ContentsタブのComponent LibraryからProjectの下のNew component... をダブルクリックすると、Component Editorダイアログが立ち上がった(ハード・ソフト協調検証」(6)の図18)。
Nextボタンをクリックして、HDL Filesタブに移動して、Addボタンをクリックして、avalon_cpu.svを追加する。(ハード・ソフト協調検証」(6)の図19)
そうすると、エラーがたくさん出る。これはSOPC Builder がSystemVerilogに対応していないからだと思う。
hard_soft_19_100303.png

これだと、avalon_cpuはSOPC Builderのコンポーネントとして認識されないようだ?ハード・ソフト協調検証」(6)の図21にも図22にも何も表示されない。
どうもおかしいので、Verification Engineerの戯言さんのブログで聞いてみたら、`ifdef DPI_Cが必要とのことだった。それを加えた全ソースをリスト11から引用させていただきます。(Verification Engineerの戯言さん、ありがとうございました。問題があったらお知らせください)

module avalon_cpu (
    input  wire        clk,
    input  wire        reset,
    output wire [31:0] avm_address,
    output wire [2:0]  avm_burstcount,
    input  wire [31:0] avm_readdata,
    output wire [31:0] avm_writedata,
    input  wire        avm_waitrequest,
    output wire        avm_write,
    output wire        avm_read,
    output wire [3:0]  avm_byteenable,
    input  wire        avm_readdatavalid        
);
    altera_avalon_mm_master_bfm #(
        .AV_ADDRESS_W             (32),
        .AV_SYMBOL_W              (8),
        .AV_NUMSYMBOLS            (4),
        .AV_BURSTCOUNT_W          (3),
        .USE_READ                 (1),
        .USE_WRITE                (1),
        .USE_ADDRESS              (1),
        .USE_BYTE_ENABLE          (1),
        .USE_BURSTCOUNT           (1),
        .USE_READ_DATA            (1),
        .USE_READ_DATA_VALID      (1),
        .USE_WRITE_DATA           (1),
        .USE_BEGIN_TRANSFER       (0),
        .USE_BEGIN_BURST_TRANSFER (0),
        .USE_WAIT_REQUEST         (1),
        .AV_BURST_LINEWRAP        (1),
        .AV_BURST_BNDR_ONLY       (1),
        .AV_MAX_PENDING_READS     (1),
        .AV_FIX_READ_LATENCY      (1)
    )
    cpu (
        .clk                    (clk),
        .reset                  (reset),
        .address                (avm_address),
        .avm_burstcount         (avm_burstcount),
        .avm_readdata           (avm_readdata),
        .avm_writedata          (avm_writedata),
        .avm_waitrequest        (avm_waitrequest),
        .avm_write              (avm_write),
        .avm_read               (avm_read),
        .avm_byteenable         (avm_byteenable), 
        .avm_readdatavalid      (avm_readdatavalid),
        .avm_begintransfer      (),
        .avm_beginbursttransfer () 
    );
    
    `define BFM cpu

    `ifdef DPI_C
        // =========================================================================
        // DPI-C
        // =========================================================================

        `ifndef TEST_BFM
        import "DPI-C" context task dpi_main();
        `endif // TEST_BFM

        export "DPI-C" task bfm_write32;
        export "DPI-C" task bfm_read32;
        export "DPI-C" task bfm_write16;
        export "DPI-C" task bfm_read16;
        export "DPI-C" task bfm_write8;
        export "DPI-C" task bfm_read8;
        export "DPI-C" task bfm_nop;

        // =========================================================================
        // Main
        // =========================================================================

        initial begin

        `BFM.init();

        `ifdef TEST_BFM
        test_bfm;
        `else
        dpi_main();
        `endif // TEST_BFM

        #100;
        $finish(2);
        end

        // =========================================================================
        // Task
        // =========================================================================

        import avalon_mm_pkg::*;

        task automatic bfm_run( Request_t request, int addr, int byte_enable, inout int data );

        `BFM.set_command_request(request);
        `BFM.set_command_address(addr);
        `BFM.set_command_byte_enable(byte_enable,0);
        `BFM.set_command_idle(0,0);
        `BFM.set_command_init_latency(0);
        `BFM.set_command_burst_count(1);
        `BFM.set_command_burst_size(1);

        if( request == REQ_WRITE )
          `BFM.set_command_data(data, 0);

        `BFM.push_command();

        while(1) begin
          @(posedge `BFM.clk);
          if(`BFM.get_response_queue_size() > 0)
            break;
        end

        `BFM.pop_response();

        if( request == REQ_READ )
          data = `BFM.get_response_data(0);

        endtask : bfm_run  

        task automatic bfm_read32(  int unsigned addr, output int unsigned data );
        int byte_enable;

        if( addr & 'h3 ) begin // address check
            data = 'hffff_ffff;
            return;
        end

        byte_enable = 'hf;

        bfm_run( REQ_READ, addr, byte_enable, data );
        $display("bfm_read32  : addr = 0x%h, data = 0x%x", addr, data );
          
        endtask : bfm_read32

        task automatic bfm_write32( int unsigned addr, input int unsigned data );
        int byte_enable;

        if( addr & 'h3 ) begin // address check
            return;
        end

        byte_enable = 'hf;

        bfm_run( REQ_WRITE, addr, byte_enable, data );
        $display("bfm_write32 : addr = 0x%h, data = 0x%x", addr, data );

        endtask : bfm_write32

        task automatic bfm_read16(  int unsigned addr, output shortint unsigned data );
        int byte_enable;
        int unsigned word;

        if( addr & 'h1 ) begin // address check
            data = 'hffff;
            return;
        end

        case ( addr & 'h2 )
          0 : byte_enable = 'h3;
          2 : byte_enable = 'hc;
        endcase
          
        bfm_run( REQ_READ, addr, byte_enable, word );

        case( addr & 'h2 )
          0 : data = (word & 'h0000_ffff) >>  0;
          2 : data = (word & 'hffff_0000) >> 16;
        endcase

        $display("bfm_read16  : addr = 0x%h, data = 0x%x", addr, data );
          
        endtask : bfm_read16

        task automatic bfm_write16( int unsigned addr, input shortint unsigned data );
        int byte_enable;
        int unsigned word;

        if( addr & 'h1 ) begin // address check
            return;
        end

        case ( addr & 'h2 )
          0 : begin byte_enable = 'h3; word = (data <<  0) & 'h0000_ffff; end
          2 : begin byte_enable = 'hc; word = (data << 16) & 'hffff_0000; end
        endcase

        bfm_run( REQ_WRITE, addr, byte_enable, word );
        $display("bfm_write16 : addr = 0x%h, data = 0x%x", addr, data );

        endtask : bfm_write16

        task automatic bfm_read8(  int unsigned addr, output byte unsigned data );
        int byte_enable;
        int unsigned word;

        case ( addr & 'h3 )
          0 : byte_enable = 'h1;
          1 : byte_enable = 'h2;
          2 : byte_enable = 'h4;
          3 : byte_enable = 'h8;
        endcase

        bfm_run( REQ_READ, addr, byte_enable, word );

        case ( addr & 'h3 )
          0 : data = (word & 'h0000_00ff) >>  0;
          1 : data = (word & 'h0000_ff00) >>  8;
          2 : data = (word & 'h00ff_0000) >> 16;
          3 : data = (word & 'hff00_0000) >> 24;
        endcase

        $display("bfm_read8   : addr = 0x%h, data = 0x%x", addr, data );
          
        endtask : bfm_read8

        task automatic bfm_write8( int unsigned addr, input byte unsigned data );
        int byte_enable;
        int unsigned word;

        case ( addr & 'h3 )
          0 : begin byte_enable = 'h1; word = (data <<  0) & 'h0000_00ff; end
          1 : begin byte_enable = 'h2; word = (data <<  8) & 'h0000_ff00; end
          2 : begin byte_enable = 'h4; word = (data << 16) & 'h00ff_0000; end
          3 : begin byte_enable = 'h8; word = (data << 24) & 'hff00_0000; end
        endcase

        bfm_run( REQ_WRITE, addr, byte_enable, word );
        $display("bfm_write8  : addr = 0x%h, data = 0x%x", addr, data );

        endtask : bfm_write8

        task automatic bfm_nop( int no );

        for( int n=0 ; n<no ; n++ )
          @(posedge `BFM.clk);

        endtask : bfm_nop

        task test_bfm;
        int unsigned addr;

        addr = 'h0000_0000;

        for ( int n=0 ; n<4 ; n+=4 ) begin : int_loop    
          int unsigned a, b;

          a  = 'h1234_5678;
          bfm_write32( addr, a );
          bfm_read32 ( addr, b );
          $display("addr = 0x%h, exp = 0x%h, data = 0x%h", addr, b, a );  
        end

        addr = 'h0000_1000;
        for ( int n=0 ; n<4 ; n+=2 ) begin : short_loop
          shortint unsigned a, b;
          
          a  = 'h4567 + n*2; 
          bfm_write16( addr + n, a );
          bfm_read16 ( addr + n, b );
          $display("addr = 0x%h, exp = 0x%h, data = 0x%h", addr, b, a );  
          a += a;
        end

          addr = 'h0000_2000;
        for ( int n=0 ; n<4 ; n++ ) begin : byte_loop
          byte unsigned a, b;
          
          a  = 'h12 + n*4;
          bfm_write8( addr + n, a );
          bfm_read8 ( addr + n, b );
          $display("addr = 0x%h, exp = 0x%h, data = 0x%h", addr, b, a );
          a += a;
        end

        endtask : test_bfm 
    `else // DPI_C
    
    `endif // DPI_C

endmodule : avalon_cpu 


これだと、HDL Filesタブに移動して、Addボタンをクリックして、avalon_cpu.svを追加してもエラーは発生しない。(ハード・ソフト協調検証」(6)の図19
以下順番に続けると、Analyzing avalon_cpu.sv Completedダイアログが表示される(ハード・ソフト協調検証」(6)の図20)。
closeボタンをクリックすると、HDL Filesにavalon_cpu.sv が入っている。
hard_soft_16_100301.png

Nextボタンをクリックすると、Signalsタブが表示される(ハード・ソフト協調検証」(6)の図21)。
次々にボタンをクリックして行くと、ハード・ソフト協調検証」(6)の図22から図24までが表示された。
Libraryにavalon_cpuが表示された。
hard_soft_17_100301.png

Avalon MM Master BFMを削除して、生成したavalon_cpuを入れて、onchip_memory2_0と接続した。
hard_soft_20_100303.png

その後、Generateボタンでシステムを生成し、成功した。

次に、シミュレーションを行うが、その前に、setup_sim.doの書き換えを行う。setup_sim.doはSOPC BuilderのGenerateで作り直されている。よって、下の部分を変更して、setup_dpi_lib.do としてセーブした。下にalias _vsimの部分とvlogの部分を抜き出す。

alias _vsim {vsim -t ps +nowarnTFMPC -sv_root prog -sv_lib dpi_main -L lpm_ver -L sgate_ver -L altera_mf_ver -L altgxb_ver -L stratixiigx_hssi_ver -L stratixgx_ver -L stratixgx_gxb_ver -L stratixiigx -L altera_ver -L stratixiii_ver -L stratixii_ver -L cycloneii_ver -L cycloneiii_ver -L stratixiv_hssi_ver -L arriaii_ver -L arriaii_pcie_hip_ver -L arriaii_hssi_ver -L stratixiv_pcie_hip_ver -L cycloneiv_pcie_hip_ver -L cycloneiv_hssi_ver -L hardcopyiv_pcie_hip_ver -L hardcopyiv_hssi_ver test_bench} } else {
alias _vsim {vsim -t ps +nowarnTFMPC -sv_root prog -sv_lib dpi_main test_bench } }


-sv_root prog -sv_lib dpi_mainを付け加えた。

vlog -sv +incdir+.. ../avalon_bfm.v;


-svを付け加えた。
これで、ModelSim AE 6.5bを起動し、avalon_bfm_sim.mpfをオープンして(オープンしてあった)、Transcriptペインで、

do setup_sim_lib.do


を実行した。次に(sを実行してコンパイルが抜けていました。追加します。)

_vsim


を実行すると、シミュレーションがスタートした。
次に、

do wave.do

を行っても、信号はwaveウインドウに表示されなかったので、Simウインドウのtest_bench -> DUT -> the_avalon_cpu_0 -> avalon_cpu_0 を選択して、Objectウインドウに表示された信号をwaveにドラックアンドドロップした。

run -all

をしてRUNするが、finishしない。
hard_soft_21_100304.png

そういえば、Simウインドウのtest_bench -> DUT -> the_avalon_cpu_0 -> avalon_cpu_0 を選択してもSystemVerilogの信号名が表示されないのはおかしい?
そうかそういえば、コンパイルするときに DPI_C を define していないから当たり前か?
コンパイル時にdefine をしてくれるオプションを探すことにした。ModelSimのリファレンスマニュアルを見ると、コンパイルはvlogで行うことがわかった。そして、+define+macro_nameでコンパイル時にdefine 出来ることがわかった。
早速、setup_sim_lib.do のvlog の行を下のように変更した。

vlog -sv +define+DPI_C +incdir+.. ../avalon_bfm.v;


その後、ModelSim AE 6.5bのTranscriptペインで、

do setup_sim_lib.do


を実行して、次に

s


を実行したら、vsimも走って、シミュレーションの準備が終了した。Simウインドウのtest_bench -> DUT -> the_avalon_cpu_0 -> avalon_cpu_0 を選択すると、Objectウインドウに信号名が表示されたので、それをwaveウインドウにドラックアンドドロップした。waveウインドウの信号名のRadix をHexadicmal に変更した。その上で、

run -all


を実行したら、finishのダイアログが表示されて、うまく行った。Noボタンをクリックすると、前回と同様に波形が表示された
hard_soft_22_100305.png

やっとうまく行った。うれしい。。。これで、SOPC Builderで新しいコンポーネントとして作ったバストランザクションモデルをCから起動してシミュレーションを行うことができた。
Verification Engineerの戯言さん、ありがとうございました。無事に成功しました。

(2010/03/05:追記)
コメントでvlogさんに教えていただきました。ありがとうございました。
ModelSimのProjectに入れれば、右クリックのプロパティで開いたProject Complier SettingsダイアログのVerilog & System VerilogタブのOther Verilog OptionsのMacro...ボタンをクリックして開いたDefine MacroダイアログのMacro NameにDPI_Cを入れればコンパイル時にMacroが定義されるそうです。
hard_soft_23_100305.png
  1. 2010年03月05日 04:52 |
  2. SystemVerilog
  3. | トラックバック:0
  4. | コメント:4

kicad-2010-02-28-RC5

久しぶりにKicadのホームページを見たら、kicad-2010-02-28-RC5が出ていたので、早速インストールしました。
kicadを起動して、以前に試作(CADデータを作っただけ)のSpartan3ボードを開いてみました。すると、右にVisiblesが増えていて、表示するレイヤーやRenderを選ぶことができるようになっていました。
下の図は内層を非表示にしたプリント基板の図です。
kicad_1_100303.png

  1. 2010年03月03日 19:56 |
  2. CADツール
  3. | トラックバック:0
  4. | コメント:2

無償ツールで実践する「ハード・ソフト協調検証」をやってみる4(シミュレーション)

今日は、無償ツールで実践する「ハード・ソフト協調検証」(6) ―― 協調シミュレーションを実行するの2ページ目から、

15.シミュレーションを行う
ModelSim AE 6.5bを起動し、avalon_bfm_sim.mpfをオープンして(オープンしてあった)、Transcriptペインで、

do setup_sim.do


を実行した。(setup_sim.do は”無償ツールで実践する「ハード・ソフト協調検証」をやってみる3(協調シミュレーション準備)”で、書き換えてある。更に後で使用するためにsetup_sim_org.doにコピーしておく)次に

_vsim

を実行すると、シミュレーションがスタートした。
hard_soft_12_100301.png

同様にTranscriptペインで

do wave.do

を実行すると、ModelSimにwaveペインが追加され、信号がロードされた。
hard_soft_13_100301.png

Transcriptペインで、

run -All

を実行すると、下に示すように、シミュレーションが終了し、Write3回、Read3回実行されているのが見えた(波形が見えないので、waveウインドウをアンドックしました)。
hard_soft_14_100301.png
hard_soft_15_100301.png

これで、DPI-Cでのバスアクセスのシミュレーションが完了した。一瞬でシミュレーションが終了する。これがNios2のIPコアを使用して、同様にシミュレーションすると長いシミュレーション時間が必要になるということだ。たぶんそうなんだろう?
ここで、なぜCのテストベンチが動作するかだが、_vsimの記述の最初の方には下のように記述されている

alias _vsim {vsim -t ps +nowarnTFMPC -sv_root prog -sv_lib dpi_main ...


-sv_lib dpi_mai でdpi_main.dll を呼び出しているのだと思う(14.C言語プログラムをコンパイルする)。

シミュレーションの流れを下の図に示す。
hard_soft_18_100302.png

最初に、SystemVerilogファイル(tb_prog.sv)のinitial文からCの関数 dpi_main()を呼び出す。dpi_main()から test32(), test16(), test8() を呼び出し、その中から tb_prog.svのtaskを呼び出す。そこから、Avalon-MM Master BFMのAvalon Master BFM API(set_command_addressなど)を呼び出して、Avalon-MM Slave(onchi_memory2_0)に読み書きする。今のところ、以上のように理解している。

1つ疑問がある。それは、gcc でコンパイルしたdpi_main.c をdpi_main.dllにして、vsimでリンクしているようだが、このDLLを読み込みタイミングはいつか?ということだ。Cのテストベンチを書き換えたときに、いつから反映されるのか?という疑問がある。vsimをquitする必要があるのか?restart すれば更新されてリンクされるのか?DLLの知識があれば自明なのかもしれないが、わからないのでやってみようと思う。(必要なときにリンクされるはずなので、書き換えば大丈夫のような気もするし、そもそも使用中で書き換えさせてくれない?と言う可能性もあるのかな?)

Avalon Verification IP Suite User Guideを眺めていると、普通にVerilogのテストベンチからもスティミュラスを入力できるようだ。
  1. 2010年03月02日 06:00 |
  2. SystemVerilog
  3. | トラックバック:0
  4. | コメント:2