VHDL时钟同步器中的合成错误

时间:2013-07-14 11:50:59

标签: vhdl

我正在尝试在下面的VHDL代码中实现时钟同步和时钟分频器。时钟(clk_rx和clk_tx)应在总线上'RX'信号的上升沿和下降沿同步。我可以模拟以下但是它在ISE中无法合成,因为我正在使用“RX'EVENT”。任何人都可以提出替代方案吗? (Verilog也会工作)

-------------------------------------------- CLOCK DIVIDER- -------------------------------------------------- -------------------------------------

PROCESS (CLK_I, RX)
BEGIN
   IF (RX'EVENT) THEN
      clk_cnt <= to_unsigned(0,clk_cnt'LENGTH);  
   ELSIF (CLK_I'EVENT AND CLK_I = '1') THEN
       IF clk_cnt >2499 THEN
         clk_cnt <= to_unsigned(0,clk_cnt'LENGTH); 
      ELSE  
         clk_cnt <= clk_cnt + 1;    
       END IF;
   END IF;
END PROCESS;


clk_rx <= '1' WHEN  clk_cnt = 1250 ELSE '0';  -----clk_rx=1 only at the half of the counter period----------clk enable
clk_tx <= '1' WHEN  clk_cnt = 2499 ELSE '0';

4 个答案:

答案 0 :(得分:1)

问题不仅仅是你正在使用RX'EVENT,而是你在RX'EVENT条件下有一个CLK_I'EVENT条件。那只是不可综合的。

假设CLK_I的频率远高于RX'EVENT,请尝试使用CLK_I对RX进行采样。如果RX的先前值为低且当前值为高,则在CLK_I'EVENT上同步复位clk_cnt。请注意,如果RX与CLK_I真正异步,则需要担心亚稳态,您应该在之前添加2个触发器以同步RX ,以查找从0到1的变化。

答案 1 :(得分:0)

试试这段代码。 @Joe Hass解释说,我的代码中仍然没有触发器来解决RX的亚稳态问题。

there is a scheme用于同步RX信号。

PROCESS (CLK_I, RX)
BEGIN
   IF (CLK_I'EVENT AND CLK_I = '1') THEN
       IF (RX='1') THEN
          clk_cnt <= to_unsigned(0,clk_cnt'LENGTH);  
       ELSE
           IF clk_cnt >2499 THEN
               clk_cnt <= to_unsigned(0,clk_cnt'LENGTH); 
           ELSE  
               clk_cnt <= clk_cnt + 1;    
           END IF;
      END IF;
   END IF;
END PROCESS;

答案 2 :(得分:0)

您可以在下方找到代码建议。请注意以下属性:

  • clk_rx_o(clk_rx)和clk_rx_o(clk_tx)作为触发器的输出产生,因为为了避免在基于过程外的cnt的组合比较生成信号时可能发生的毛刺
  • rx_i由两个触发器同步,假设它尚未与clk_i同步
  • 时钟分割是2501,因为cnt从0 ... 2500开始由于换行时(cnt> 2499)。对于除以2500使用(cnt> = 2499)而不是。
  • VHDL编码风格:所有信号名称均为小写,VHDL语句也是小写,表达式周围的一致间距是为了便于阅读

代码:

library ieee;
use ieee.std_logic_1164.all;

entity mdl is
  port(
    clk_i    : in  std_logic;
    rx_i     : in  std_logic;
    clk_rx_o : out std_logic;
    clk_tx_o : out std_logic);
end entity;

library ieee;
use ieee.numeric_std.all;

architecture syn of mdl is

  signal rx_meta : std_logic;
  signal rx_sync : std_logic;
  signal cnt     : std_logic_vector(12 - 1 downto 0);

begin

  -- rx_i sync to clk_i
  process (clk_i) is
  begin
    if rising_edge(clk_i) then
      rx_meta <= rx_i;
      rx_sync <= rx_meta;
    end if;
  end process;

  process (clk_i) is
  begin
    if rising_edge(clk_i) then
      -- Clock align and divide
      if rx_sync = '1' then
        cnt <= std_logic_vector(to_unsigned(0, cnt'length));
      else
        if unsigned(cnt) > 2499 then
          cnt <= std_logic_vector(to_unsigned(0, cnt'length));
        else
          cnt <= std_logic_vector(unsigned(cnt) + 1);
        end if;
      end if;
      -- Clock generate as single cycle pulse
      clk_rx_o <= '0';
      if unsigned(cnt) = 1250 then
        clk_rx_o <= '1';
      end if;
      clk_tx_o <= '0';
      if unsigned(cnt) = 2499 then
        clk_tx_o <= '1';
      end if;
    end if;
  end process;

end architecture;

答案 3 :(得分:0)

非常感谢您的支持。

我将代码修改为@Joe和@MortenZdk建议。现在我能够合成它。 我必须检测“RX”的posedge和negedge。所以我改变了代码如下:

PROCESS(CLK_I)  -- Stabilizing the RX signal to avoid meta stable state
begin
  if rising_edge(CLK_I) then    
    rx_meta <= RX; 
    rx_sync <= rx_meta;      
  end if;
END PROCESS;

PROCESS (CLK_I)
BEGIN              
   IF (CLK_I'EVENT AND CLK_I = '1') THEN
     tmp_RX <= rx_sync;
     IF (rx_sync /= tmp_RX) THEN
       clk_cnt <= to_unsigned(0,clk_cnt'LENGTH);  
     ELSE
       IF clk_cnt >2499 THEN
         clk_cnt <= to_unsigned(0,clk_cnt'LENGTH); 
       ELSE  
         clk_cnt <= clk_cnt + 1;    
       END IF;
     END IF;
     -- Clock generate as single cycle pulse    
     clk_rx <= '0';
     IF clk_cnt = 1250 THEN
        clk_rx <= '1';
     END IF;
     clk_tx <= '0';
     IF clk_cnt = 2500 THEN
       clk_tx <= '1';
     END IF;

   END IF;
END PROCESS;