在VHDL中创建低时钟频率的替代方法

在VHDL中创建低时钟频率的替代方法,vhdl,clock,conventions,xilinx-ise,spartan,Vhdl,Clock,Conventions,Xilinx Ise,Spartan,在过去,我问了一个关于复位的问题,以及如何将高时钟频率分解为一系列低时钟方波频率,其中每个输出是彼此的谐波,例如,第一个输出是10 Hz,第二个是20 Hz等 我收到了一些非常有用的答案,建议使用时钟使能引脚来创建较低的频率 我想到了另一个选择;使用一个不断递增的n位数字,并将该数字的最后x位作为时钟输出,其中x是输出数 对我来说,它在合成中起作用——但我很好奇——因为我从来没有在网上或其他地方看到过它,所以,我是否遗漏了一些东西,这意味着它实际上是一个糟糕的想法,我只是在为以后制造问题 我知道

在过去,我问了一个关于复位的问题,以及如何将高时钟频率分解为一系列低时钟方波频率,其中每个输出是彼此的谐波,例如,第一个输出是10 Hz,第二个是20 Hz等

我收到了一些非常有用的答案,建议使用时钟使能引脚来创建较低的频率

我想到了另一个选择;使用一个不断递增的n位数字,并将该数字的最后x位作为时钟输出,其中x是输出数

对我来说,它在合成中起作用——但我很好奇——因为我从来没有在网上或其他地方看到过它,所以,我是否遗漏了一些东西,这意味着它实际上是一个糟糕的想法,我只是在为以后制造问题

我知道这方面的限制是,我只能产生输入频率除以2的幂的频率,因此大多数情况下,它只能近似于所需的输出频率(但仍然是正确的顺序)。这是不建议使用的唯一原因吗

非常感谢

大卫

IEEE库;
使用IEEE.STD_LOGIC_1164.ALL;
使用IEEE.NUMERIC_STD.ALL;
UNISIM图书馆;
使用UNISIM.VComponents.all;
使用IEEE.math_real.all;
实体CLK_分隔符为
通用(输入频率:整数;--只能将输入频率除以2的幂a
输出1_频率:整数
);
端口(SYSCLK:标准逻辑中;
复位N:在标准逻辑中;
OUT1:OUT STD_逻辑——实际除法器为2^(上限[log2(输入/频率)])
OUT2:OUT标准逻辑)--实际输出是输入超过上述值
端时钟分频器;
Clk_分配器的架构是
常数除法器:整数:=输入\频率/输出1 \频率;
常量计数器_位:整数:=整数(ceil(log2(实数(除法器)));
信号计数器:无符号(计数器位-1到0):=(其他=>“0”);
开始
进程:进程(SYSCLK)
开始
如果上升沿(SYSCLK),则

计数器从功能上讲,两个输出
OUT1
OUT2
可以用作时钟,但这种制作时钟的方法不可缩放,可能会在实现中造成问题,因此这是一个坏习惯。然而,理解为什么会这样当然很重要

它不可伸缩的原因是,FPGA中用作时钟的每个信号都将通过一个特殊的时钟网络进行分配,在这个时钟网络中,延迟和偏移都有明确的定义,因此每个时钟上的所有触发器和存储器都会同步更新。此类时钟网的数量非常有限,通常在FPGA设备中为10到40个,对使用和位置的一些限制使得规划时钟网的使用通常更加关键。因此,通常需要为真正的异步时钟预留时钟网络,在这种情况下,除了使用时钟网络之外别无选择

它可能导致问题的原因是,基于计数器中的位创建的时钟没有保证的定时关系。因此,如果需要在这些时钟域之间移动数据,则需要额外的同步约束,以确保正确处理时钟域交叉(CDC)。这是通过对合成和/或静态时序分析(STA)的约束来实现的,通常有点棘手,因此使用简化STA的设计方法是节省设计时间的习惯


因此,在可以使用公共时钟,然后生成同步时钟启用信号的设计中,这应该是首选方法。对于上述特定设计,只需检测相关
计数器
位的
'0'
'1'
转换,然后在检测到转换的单个周期中断言时钟启用,即可生成时钟启用。然后可以使用单个时钟网络,以及2个时钟使能,如
CE1
CE2
,并且不需要特殊的STA约束。

Morten已经在中指出了该理论。 借助两个示例,我将演示使用生成的时钟而不是时钟启用时遇到的问题

时钟分布 首先,必须注意所有目标触发器的时钟到达(几乎)同一时间。否则,即使是具有两级的简单移位寄存器,也会出现如下故障:

process(clk_gen)
begin
  if rising_edge(clk_gen) then
    tmp <= d;
    q   <= tmp;
  end if;
end if;
以下测试台仅在输入
d
处输入“1”,因此,
q
在1个时钟边缘后应为“0”,在两个时钟边缘后应为“1”

library ieee;
use ieee.std_logic_1164.all;

entity shift_reg_tb is
end shift_reg_tb;

architecture sim of shift_reg_tb is
  signal clk_gen : std_logic;
  signal d       : std_logic;
  signal q       : std_logic;
begin  -- sim
  DUT: entity work.shift_reg port map (clk_gen => clk_gen, d => d, q => q);

  WaveGen_Proc: process
  begin
    -- Note: registers inside DUT are initialized to zero
    d       <= '1';                     -- shift in '1'
    clk_gen <= '0';
    wait for 2 ns;
    clk_gen <= '1';                     -- just one rising edge
    wait for 2 ns;
    assert q = '0' report "Wrong output" severity error;
    wait;
  end process WaveGen_Proc;
end sim;
现在,只需通过该测试台的寄存器0输入新的数据值“11”:

library ieee;
use ieee.std_logic_1164.all;

entity handover_tb is
end handover_tb;

architecture sim of handover_tb is
  signal clk_orig : std_logic := '0';
  signal d        : std_logic_vector(1 downto 0);
  signal q        : std_logic_vector(1 downto 0);
begin  -- sim
  DUT: entity work.handover port map (clk_orig => clk_orig, d => d, q => q);

  WaveGen_Proc: process
  begin
    -- Note: registers inside DUT are initialized to zero
    d <= "11";
    clk_orig <= '0';
    for i in 0 to 7 loop                -- 4 clock periods
      wait for 2 ns;
      clk_orig <= not clk_orig;
    end loop;  -- i
    wait;
  end process WaveGen_Proc;
end sim;
ieee库;
使用ieee.std_logic_1164.all;
实体移交是
结束移交;;
切换的架构sim_tb为
信号时钟源:标准逻辑:='0';
信号d:标准逻辑向量(1到0);
信号q:std_逻辑_向量(1到0);
开始——模拟
DUT:entity work.handover端口映射(clk_orig=>clk_orig,d=>d,q=>q);
WaveGen_过程:过程
开始
--注:DUT内的寄存器初始化为零

d只是为了澄清-你说它不可缩放是什么意思?
library ieee;
use ieee.std_logic_1164.all;

entity shift_reg_tb is
end shift_reg_tb;

architecture sim of shift_reg_tb is
  signal clk_gen : std_logic;
  signal d       : std_logic;
  signal q       : std_logic;
begin  -- sim
  DUT: entity work.shift_reg port map (clk_gen => clk_gen, d => d, q => q);

  WaveGen_Proc: process
  begin
    -- Note: registers inside DUT are initialized to zero
    d       <= '1';                     -- shift in '1'
    clk_gen <= '0';
    wait for 2 ns;
    clk_gen <= '1';                     -- just one rising edge
    wait for 2 ns;
    assert q = '0' report "Wrong output" severity error;
    wait;
  end process WaveGen_Proc;
end sim;
library ieee;
use ieee.std_logic_1164.all;
library unisim;
use unisim.vcomponents.all;

entity handover is
  port (
    clk_orig : in  std_logic;                      -- original clock
    d        : in  std_logic_vector(1 downto 0);   -- data input
    q        : out std_logic_vector(1 downto 0));  -- data output
end handover;

architecture rtl of handover is
  signal div_q   : std_logic := '0';    -- output of clock divider
  signal bufg_o  : std_logic := '0';    -- output of clock buffer
  signal clk_gen : std_logic;           -- generated clock
  signal reg_0_q : std_logic_vector(1 downto 0) := "00";  -- output of register 0
  signal reg_1_d : std_logic_vector(1 downto 0);     -- data input  of register 1
  signal reg_1_q : std_logic_vector(1 downto 0) := "00";  -- output of register 1
begin  -- rtl

  -- Generate a clock by dividing the original clock by 2.
  -- The 100 ps delay is the clock-to-output time of the flip-flop.
  div_q <= not div_q after 100 ps when rising_edge(clk_orig);

  -- Add global clock-buffer as well as mimic some delay.
  -- Clock arrives at (almost) same time on all destination flip-flops.
  clk_gen_bufg : BUFG port map (I => div_q, O => bufg_o);
  clk_gen <= transport bufg_o after 1000 ps;

  -- Sample data input with original clock
  reg_0_q <= d after 100 ps when rising_edge(clk_orig);

  -- Different wire delays between register 0 and register 1 for each bit
  reg_1_d(0) <= transport reg_0_q(0) after  500 ps;
  reg_1_d(1) <= transport reg_0_q(1) after 1500 ps;

  -- All flip-flops of register 1 are clocked at the same time due to clock buffer.
  reg_1_q <= reg_1_d after 100 ps when rising_edge(clk_gen);
  q <= reg_1_q;
end rtl;
library ieee;
use ieee.std_logic_1164.all;

entity handover_tb is
end handover_tb;

architecture sim of handover_tb is
  signal clk_orig : std_logic := '0';
  signal d        : std_logic_vector(1 downto 0);
  signal q        : std_logic_vector(1 downto 0);
begin  -- sim
  DUT: entity work.handover port map (clk_orig => clk_orig, d => d, q => q);

  WaveGen_Proc: process
  begin
    -- Note: registers inside DUT are initialized to zero
    d <= "11";
    clk_orig <= '0';
    for i in 0 to 7 loop                -- 4 clock periods
      wait for 2 ns;
      clk_orig <= not clk_orig;
    end loop;  -- i
    wait;
  end process WaveGen_Proc;
end sim;