VHDL - 非常规时钟模式生成

VHDL - Non-regular clock pattern generation

我的问题相对简单:在 VHDL 中是否可以使用进程和 after 关键字生成具有特定非规则模式的时钟 而无需

换句话说,如果我有一个生成这样的时钟的进程:

process(Start)
    begin   
        if Start = '0' then 
            clock <= '0';
        else if Start = '1' then
            clock <= '0',
            '1' after 25 ns,
            '0' after 35 ns,
            '1' after 50 ns,
            '0' after 75 ns,
            '1' after 105 ns,
            ...
end process;

我能否使用(例如)某些组件(例如某种延迟)获得相同的输出?

我知道它可能没有任何用处,但我的教授要求我们使用 structural VHDL 复制此练习。我只需要模拟它,我不需要让它可合成。

好的,您可以尝试使用其他关键字在进程块内生成延迟,例如 wait forloop。这是一个例子:

clock_gen: process
   constant duty_cycle : real := 0.40
   constant period : time := 100 ns ;
   constant clk_high : time := duty_cycle * period ;
begin
   loop
      clk <= '0';
      wait for period - clk_high; -- clock low time
      clk <= '1';
          wait for clk_high; -- clock high time
      end loop;
    end process;
end behavioral;

这是一个具有可变占空比和周期的时钟。

创建一个没有进程的时钟没有任何意义(结构 VHDL 不提供任何类型的同步),但是您可以通过将正确的逻辑应用于由提供的一些常规时钟信号来模拟特殊时钟模式例如一个测试平台。

例如考虑输入 2 个时钟(一个从 0 开始,另一个从 1 开始),这将使您有可能实现一个 2 状态机,将其视为基于周期性的计数器你的源时钟..

您还可以有 2 个时钟源,其中第二个时钟的周期是第一个时钟的两倍以获得 2^2 状态机,在这种情况下,您可以自由地以低电平 (0) 启动两个时钟。

这样您就可以在不使用任何过程的情况下实现所需的模式(不使用行为 VHDL)。

想象一个计数器,它对 5 ns 周期时钟进行计数,时钟的初始值为“0”,计数器的初始值为 (others => '0')。在计数 = 5 (25 ns)、7 (35 ns)、10 (50 ns) 时,组合信号切换变为真(“1”),...而其他切换设置为假(“0”)。如果时钟是连续的,您可以选择一个计数来将计数恢复为全“0”。切换信号是 D 触发器(时钟是输出)的使能信号,它的 Qnot 连接到高速时钟(从测试台外部提供)的 D 运行。即使以 5 ns 的增量最后确定计数的大小。

好吧,我们将计数比较值向下调整一个以补偿 D 触发器,它在结构上看起来像这样:

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

entity counter is           -- counts 0 to 31
    port (
        clk:    in  std_logic;
        count:  out std_logic_vector (4 downto 0);
        zero:   out std_logic
    );
end entity;

architecture foo of counter is
    signal cnt:     unsigned (count'range) := (others => '0'); -- start at zero
    constant period:    integer := 31;  -- 32 is the period of the the sequence
begin
    process (clk)
    begin
        if rising_edge (clk) then
            if cnt < period then
                cnt <= cnt + 1;
            else
                cnt <= (others => '0');
            end if;
        end if;
    end process;

    count <= std_logic_vector(cnt);

    zero <= '1' when cnt = 0 else  
            '0';
end architecture;

library ieee;
use ieee.std_logic_1164.all;

entity d_flip_flop is   -- has enable
    port (
        resetn: in  std_logic;
        clk:    in  std_logic;
        en:     in  std_logic;
        d:      in  std_logic;
        q:      out std_logic
    );
end entity;

architecture foo of d_flip_flop is
    signal qn: std_logic := '1';
begin
    process (resetn, clk)
    begin
        if resetn = '0' then
            qn <= '1';
        elsif rising_edge (clk) and en = '1' then
            qn <= not d;
        end if;
    end process;
    q <= not qn;
end architecture;

library ieee;
use ieee.std_logic_1164.all;

entity inv is
    port (
        a:  in  std_logic;
        o:  out std_logic
    );
end entity;

architecture foo of inv is
begin
    o <= not a;
end architecture;


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

entity toggle_pla_rom is
    port (
        count:  in  std_logic_vector (4 downto 0);
        toggle: out std_logic
    );
end entity;

architecture foo of toggle_pla_rom is
    type rom_array is array (0 to 31) of std_logic;   -- fully constrained
    constant rom: rom_array := ( 4 | 6 | 9 | 14 | 20 => '1', others => '0');
begin
    toggle <= rom(to_integer(unsigned(count)));
end architecture;

library ieee;
use ieee.std_logic_1164.all;

entity clock_gen is
    port (
        clk:    in  std_logic;
        clock:  out std_logic
    );
end entity;

architecture foo of clock_gen is
    signal toggle:  std_logic;
    signal resetn:  std_logic;
    signal din:     std_logic;
    signal count:   std_logic_vector (4 downto 0);
    signal q:       std_logic;
    signal nq:      std_logic;
    signal zero:    std_logic;
begin
CNTR:
    entity work.counter
        port map (
            clk => clk,
            count => count,
            zero => zero
        );

DIN_INV:
    entity work.inv
        port map (
            a => q,
            o => nq
        );

ZERO_INV:
    entity work.inv
        port map (
            a => zero,
            o => resetn
        );
DFF:
    entity work.d_flip_flop
        port map (
            resetn => resetn,
            clk => clk,
            en => toggle,
            d  => nq,
            q => q
        );

TOGGLE_LUT:
    entity work. toggle_pla_rom
        port map (
            count => count,
            toggle => toggle
        );

    clock <= q;

end architecture;

library ieee;
use ieee.std_logic_1164.all;

entity clock_gen_tb is
end entity;

architecture foo of clock_gen_tb is
    signal clk:     std_logic := '1';  -- clk has 5 ns period
    signal clock:   std_logic;
begin
CLOCKGEN:
    entity work.clock_gen
        port map (
            clk => clk,
            clock => clock
        );

CLKGEN:
    process
    begin
        wait for 2.5 ns;
        clk <= not clk;
        if now > 300 ns then
            wait;
        end if;
    end process;

MONITOR:
    process 
    begin
        wait for 0 ns;
        wait until clock'event;
        report "clock = " & std_logic'image(clock);
    end process;
end architecture;

用于确定发生切换的计数值的查找 table 可以替换为 and/ors 等,以获得真正的原始级别描述。

计数器缠绕,容易治愈(比如可以停止)。因为您没有指定任何进一步的边缘事件,所以它会根据您指定的边缘事件数量所需的大小进行定制。计数器的大小和事件的数量可以按比例增加。

当 运行 clock_gen_tb 测试台报告时钟事件并显示它符合您的规范时:

logarithmic_clock.vhdl:188:9:@0ms:(report note): clock = '0' logarithmic_clock.vhdl:188:9:@25ns:(report note): clock = '1' logarithmic_clock.vhdl:188:9:@35ns:(report note): clock = '0' logarithmic_clock.vhdl:188:9:@50ns:(report note): clock = '1' logarithmic_clock.vhdl:188:9:@75ns:(report note): clock = '0' logarithmic_clock.vhdl:188:9:@105ns:(report note): clock = '1' logarithmic_clock.vhdl:188:9:@160ns:(report note): clock = '0' logarithmic_clock.vhdl:188:9:@185ns:(report note): clock = '1' logarithmic_clock.vhdl:188:9:@195ns:(report note): clock = '0' logarithmic_clock.vhdl:188:9:@210ns:(report note): clock = '1' logarithmic_clock.vhdl:188:9:@235ns:(report note): clock = '0' logarithmic_clock.vhdl:188:9:@265ns:(report note): clock = '1'

前 6 次符合您的要求。

波形显示显示计数、切换、零(代表触发器复位)和时钟:

这个例子指出的一件事是,所有能够模拟的 VHDL 结构模型都是在行为上描述的。