wake-up-neo.net

VHDL - Wie soll ich eine Uhr in einer Testumgebung erstellen?

Wie erstelle ich eine Uhr in einer Testumgebung? Ich habe bereits eine Antwort gefunden, jedoch haben andere auf Stapelüberlauf vorgeschlagen, dass es alternative oder bessere Wege gibt, um dies zu erreichen:

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;

(Quelle hier )

21
alexdavey

Meine bevorzugte Technik:

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

Normalerweise erweitere ich dies mit einem finished Signal, damit ich die Uhr anhalten kann:

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

Gotcha-Warnung: Wenn Sie half_period Durch Division durch 2 aus einer anderen Konstante berechnen, ist Vorsicht geboten. Der Simulator verfügt über eine Einstellung für die "Zeitauflösung", die häufig standardmäßig Nanosekunden beträgt. In diesem Fall ist 5 ns / 2 Ergibt sich zu 2 ns, So dass Sie einen Zeitraum von 4ns haben! Stellen Sie den Simulator auf Pikosekunden ein und alles wird gut (bis Sie Bruchteile einer Pikosekunde benötigen, um Ihre Uhrzeit darzustellen!)

24
Martin Thompson

Wenn mehrere Takte mit unterschiedlichen Frequenzen erzeugt werden, kann die Takterzeugung vereinfacht werden, wenn eine Prozedur als gleichzeitiger Prozeduraufruf aufgerufen wird. Das von Martin Thompson erwähnte Problem der Zeitauflösung kann ein wenig gemildert werden, indem in der Prozedur unterschiedliche Zeiten für hohe und niedrige Zeiten verwendet werden. Der Prüfstand mit Verfahren zur Takterzeugung ist:

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;

Die Zeitauflösung wird zur Information auf das Terminal gedruckt, wobei die gleichzeitige Bestätigung zuletzt auf dem Prüfstand verwendet wird.

Wenn das clk_gen Die Prozedur wird in eine separate Verpackung gegeben, und die Wiederverwendung von Prüfstand zu Prüfstand ist unkompliziert.

Die Wellenform für Uhren ist in der folgenden Abbildung dargestellt.

Waveforms for clk_166 and clk_125

In der Prozedur kann auch ein fortschrittlicherer Taktgenerator erstellt werden, der die Zeitperiode anpassen kann, um sie an die angeforderte Frequenz anzupassen, obwohl die zeitliche Auflösung begrenzt ist. Dies wird hier gezeigt:

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

Die Wiederverwendung durch ein Paket wird wieder Nizza sein.

18
Morten Zilmer

Gleichzeitige Signalzuweisung:

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: Simulation gestoppt von --stop-time
gtkwave foo.ghw

enter image description here

Simulatoren simulieren Prozesse und sie werden in den Prozess umgewandelt, der Ihrer Prozessanweisung entspricht. Die Simulationszeit impliziert die Verwendung des Wartens auf oder nach Fahrereignissen für Sensitivitätsklauseln oder Sensitivitätslisten.

10
user1155120

Wie man eine Uhr benutzt und Behauptungen aufstellt

In diesem Beispiel wird gezeigt, wie Sie einen Takt erzeugen und für jeden Zyklus Eingänge und Ausgänge aktivieren. Hier wird ein einfacher Zähler getestet.

Die Schlüsselidee ist, dass die process Blöcke parallel laufen, so dass der Takt parallel zu den Eingaben und Zusicherungen generiert wird.

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;

Der Zähler würde folgendermaßen aussehen:

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;

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