【问题标题】:VHDL - How should I create a clock in a testbench?VHDL - 我应该如何在测试台中创建时钟?
【发布时间】:2013-07-28 02:10:29
【问题描述】:

我应该如何在测试台中创建时钟?我已经找到了一个答案,但是堆栈溢出的其他人建议有替代或更好的方法来实现这一点:

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;

(来源here

【问题讨论】:

  • 这个方法很好用。

标签: simulation vhdl clock hardware-programming


【解决方案1】:

我最喜欢的技术:

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;

问题提醒: 如果您从另一个常数除以 2 来计算 half_period,则需要小心。模拟器有一个“时间分辨率”设置,通常默认为纳秒......在这种情况下,5 ns / 2 是 @987654329 @所以你最终得到了 4ns 的时间!将模拟器设置为皮秒,一切都会好起来的(直到你需要皮秒的分数来表示你的时钟时间!)

【讨论】:

  • 先生,您如何定义完成的信号?我不明白时钟怎么会停止在完成?
【解决方案2】:

如果以不同的频率生成多个时钟,则如果将一个过程称为并发过程调用,则可以简化时钟生成。 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 过程被放置在一个单独的包中,那么从一个测试台重用到另一个测试台就变得简单了。

时钟波形如下图所示。

还可以在该过程中创建更高级的时钟发生器,它可以随着时间的推移调整周期以匹配请求的频率,尽管受到时间分辨率的限制。此处显示:

-- 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;

通过一个包再次重用会很好。

【讨论】:

    【解决方案3】:

    并发信号分配:

    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

    模拟器模拟流程,并将其转换为与您的流程声明等效的流程。模拟时间意味着在为敏感性子句或敏感性列表驱动事件时使用等待或之后。

    【讨论】:

      【解决方案4】:

      如何使用时钟并进行断言

      此示例说明如何生成时钟,并为每个周期提供输入和断言输出。这里测试了一个简单的计数器。

      关键思想是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

      【讨论】:

        猜你喜欢
        • 2015-08-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多