35

テストベンチでクロックを作成する方法を教えてください。私はすでに1つの答えを見つけましたが、スタックオーバーフローに関する他の人は、これを達成するための代替またはより良い方法があることを示唆しています:

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;

ENTITY test_tb IS 
END test_tb;

ARCHITECTURE behavior OF test_tb IS

    COMPONENT test
        PORT(clk : IN std_logic;)
    END COMPONENT;

   signal clk : std_logic := '0';
   constant clk_period : time := 1 ns;

BEGIN

   uut: test PORT MAP (clk => clk);       

   -- Clock process definitions( clock with 50% duty cycle is generated here.
   clk_process :process
   begin
        clk <= '0';
        wait for clk_period/2;  --for 0.5 ns signal is '0'.
        clk <= '1';
        wait for clk_period/2;  --for next 0.5 ns signal is '1'.
   end process;

END;

(ソースはこちら

4

4 に答える 4

37

私の好きなテクニック:

signal clk : std_logic := '0'; -- make sure you initialise!
...
clk <= not clk after half_period;

finished私は通常、これをシグナルで拡張して、クロックを停止できるようにします。

clk <= not clk after half_period when finished /= '1' else '0';

std_logicシグナルにアイテムを使用する場合finished、テスト環境内のすべてのアイテムから駆動できます。

signal finished : std_logic;

....
stimulus_process:process
begin
   finished <= '0';
   drive_various_signals_sync_with_clk;
   finished <= '1';
end process;

monitor_process:process
begin
   finished <= '0';
   check_all_signals_until_all_tests_complete;
   finished <= '1';
end process;

注意点: half_period2 で除算して別の定数から計算する場合は注意が必要です。シミュレーターには「時間分解能」設定があり、多くの場合デフォルトでナノ秒に設定されています...その場合、結果5 ns / 2は次のようになり2 nsます。 4nsの期間!シミュレーターをピコ秒に設定すると、すべてがうまくいきます (いずれにせよ、クロック時間を表すためにピコ秒の端数が必要になるまでは!)

于 2013-07-28T20:13:17.610 に答える
23

複数のクロックが異なる周波数で生成される場合、プロシージャが並行プロシージャ コールとして呼び出されると、クロック生成が簡素化されます。Martin Thompson によって言及された時間分解能の問題は、手順で異なる高時間と低時間を使用することで少し軽減される可能性があります。クロック生成の手順を含むテスト ベンチは次のとおりです。

library ieee;
use ieee.std_logic_1164.all;

entity tb is
end entity;

architecture sim of tb is

  -- Procedure for clock generation
  procedure clk_gen(signal clk : out std_logic; constant FREQ : real) is
    constant PERIOD    : time := 1 sec / FREQ;        -- Full period
    constant HIGH_TIME : time := PERIOD / 2;          -- High time
    constant LOW_TIME  : time := PERIOD - HIGH_TIME;  -- Low time; always >= HIGH_TIME
  begin
    -- Check the arguments
    assert (HIGH_TIME /= 0 fs) report "clk_plain: High time is zero; time resolution to large for frequency" severity FAILURE;
    -- Generate a clock cycle
    loop
      clk <= '1';
      wait for HIGH_TIME;
      clk <= '0';
      wait for LOW_TIME;
    end loop;
  end procedure;

  -- Clock frequency and signal
  signal clk_166 : std_logic;
  signal clk_125 : std_logic;

begin

  -- Clock generation with concurrent procedure call
  clk_gen(clk_166, 166.667E6);  -- 166.667 MHz clock
  clk_gen(clk_125, 125.000E6);  -- 125.000 MHz clock

  -- Time resolution show
  assert FALSE report "Time resolution: " & time'image(time'succ(0 fs)) severity NOTE;

end architecture;

時間分解能は、テスト ベンチで最後に同時アサートを使用して、情報としてターミナルに出力されます。

プロシージャを別のパッケージに配置すると、clk_genテスト ベンチからテスト ベンチへの再利用が簡単になります。

クロックの波形を下図に示します。

clk_166 および clk_125 の波形

この手順では、より高度なクロック ジェネレーターを作成することもできます。これにより、時間分解能による制限にもかかわらず、要求された周波数に一致するように時間をかけて調整できます。これを次に示します。

-- Advanced procedure for clock generation, with period adjust to match frequency over time, and run control by signal
procedure clk_gen(signal clk : out std_logic; constant FREQ : real; PHASE : time := 0 fs; signal run : std_logic) is
  constant HIGH_TIME   : time := 0.5 sec / FREQ;  -- High time as fixed value
  variable low_time_v  : time;                    -- Low time calculated per cycle; always >= HIGH_TIME
  variable cycles_v    : real := 0.0;             -- Number of cycles
  variable freq_time_v : time := 0 fs;            -- Time used for generation of cycles
begin
  -- Check the arguments
  assert (HIGH_TIME /= 0 fs) report "clk_gen: High time is zero; time resolution to large for frequency" severity FAILURE;
  -- Initial phase shift
  clk <= '0';
  wait for PHASE;
  -- Generate cycles
  loop
    -- Only high pulse if run is '1' or 'H'
    if (run = '1') or (run = 'H') then
      clk <= run;
    end if;
    wait for HIGH_TIME;
    -- Low part of cycle
    clk <= '0';
    low_time_v := 1 sec * ((cycles_v + 1.0) / FREQ) - freq_time_v - HIGH_TIME;  -- + 1.0 for cycle after current
    wait for low_time_v;
    -- Cycle counter and time passed update
    cycles_v := cycles_v + 1.0;
    freq_time_v := freq_time_v + HIGH_TIME + low_time_v;
  end loop;
end procedure;

ここでも、パッケージを介して再利用すると便利です。

于 2013-07-29T12:49:53.123 に答える
13

同時シグナル割り当て:

library ieee;
use ieee.std_logic_1164.all;

entity foo is
end;
architecture behave of foo is
    signal clk: std_logic := '0';
begin
CLOCK:
clk <=  '1' after 0.5 ns when clk = '0' else
        '0' after 0.5 ns when clk = '1';
end;

ghdl -a foo.vhdl
ghdl -r foo --stop-time=10ns --wave=foo.ghw
ghdl:info: --stop-time
gtkwave foo.ghw によってシミュレーションが停止されました

ここに画像の説明を入力

シミュレーターはプロセスをシミュレートし、プロセス ステートメントと同等のプロセスに変換されます。シミュレーション時間は、センシティビティ句またはセンシティビティ リストのイベントを駆動するときに、wait for または after を使用することを意味します。

于 2013-07-28T06:11:06.277 に答える
1

クロックの使用方法とアサーションの実行方法

この例では、クロックを生成し、サイクルごとに入力を与えて出力をアサートする方法を示します。ここでは単純なカウンターをテストします。

重要なアイデアは、processブロックが並行して実行されるため、クロックは入力およびアサーションと並行して生成されるということです。

library ieee;
use ieee.std_logic_1164.all;

entity counter_tb is
end counter_tb;

architecture behav of counter_tb is
    constant width : natural := 2;
    constant clk_period : time := 1 ns;

    signal clk : std_logic := '0';
    signal data : std_logic_vector(width-1 downto 0);
    signal count : std_logic_vector(width-1 downto 0);

    type io_t is record
        load : std_logic;
        data : std_logic_vector(width-1 downto 0);
        count : std_logic_vector(width-1 downto 0);
    end record;
    type ios_t is array (natural range <>) of io_t;
    constant ios : ios_t := (
        ('1', "00", "00"),
        ('0', "UU", "01"),
        ('0', "UU", "10"),
        ('0', "UU", "11"),

        ('1', "10", "10"),
        ('0', "UU", "11"),
        ('0', "UU", "00"),
        ('0', "UU", "01")
    );
begin
    counter_0: entity work.counter port map (clk, load, data, count);

    process
    begin
        for i in ios'range loop
            load <= ios(i).load;
            data <= ios(i).data;
            wait until falling_edge(clk);
            assert count = ios(i).count;
        end loop;
        wait;
    end process;

    process
    begin
        for i in 1 to 2 * ios'length loop
            wait for clk_period / 2;
            clk <= not clk;
        end loop;
        wait;
    end process;
end behav;

カウンターは次のようになります。

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all; -- unsigned

entity counter is
    generic (
        width : in natural := 2
    );
    port (
        clk, load : in std_logic;
        data : in std_logic_vector(width-1 downto 0);
        count : out std_logic_vector(width-1 downto 0)
    );
end entity counter;

architecture rtl of counter is
    signal cnt : unsigned(width-1 downto 0);
begin
    process(clk) is
    begin
        if rising_edge(clk) then
            if load = '1' then
                cnt <= unsigned(data);
            else
                cnt <= cnt + 1;
            end if;
        end if;
    end process;
    count <= std_logic_vector(cnt);
end architecture rtl;

関連: https://electronics.stackexchange.com/questions/148320/proper-clock-generation-for-vhdl-testbenches

于 2016-06-21T10:23:25.987 に答える