Vhdl 这是不是;“故障安全”;时钟多路复用器真的故障安全吗?

Vhdl 这是不是;“故障安全”;时钟多路复用器真的故障安全吗?,vhdl,verilog,fpga,hdl,Vhdl,Verilog,Fpga,Hdl,我发现这个设计是在 作者声称它是故障安全的,但我认为,当q3/q4的输出变低时,如果到相应的或门(或_三,或_四)的时钟信号的路由延迟大于到或门的路由延迟+q3/q4到或门的时钟输出延迟,它仍然可能有故障。为了避免这些小故障,第三季度/第四季度的输出必须在时钟上升沿上走高,在时钟下降沿上走低。我的评估正确吗 还要注意,我链接的页面上的示意图与verilog不太匹配(verilog中没有使用q3的qbar输出),并且用于生成模拟的测试台将clk_a和clk_b转换 `timescale 1ns/1

我发现这个设计是在

作者声称它是故障安全的,但我认为,当q3/q4的输出变低时,如果到相应的或门(或_三,或_四)的时钟信号的路由延迟大于到或门的路由延迟+q3/q4到或门的时钟输出延迟,它仍然可能有故障。为了避免这些小故障,第三季度/第四季度的输出必须在时钟上升沿上走高,在时钟下降沿上走低。我的评估正确吗

还要注意,我链接的页面上的示意图与verilog不太匹配(verilog中没有使用q3的qbar输出),并且用于生成模拟的测试台将clk_a和clk_b转换

`timescale 1ns/100ps

module clk_switch (
   // Outputs
   out_clk,
   // Inputs
   clk_a, clk_b, select
   );

   input clk_a;
   input clk_b;
   input select;

   output out_clk;
wire   out_clk;

reg q1,q2,q3,q4;
wire or_one, or_two,or_three,or_four;

always @ (posedge clk_a)
begin
    if (clk_a == 1'b1)
    begin
       q1 <= q4;
       q3 <= or_one;
    end
end

always @ (posedge clk_b)
begin
    if (clk_b == 1'b1)
    begin
        q2 <= q3;
        q4 <= or_two;
    end
end

assign or_one   = (!q1) | (!select);
assign or_two   = (!q2) | (select);
assign or_three = (q3)  | (clk_a);
assign or_four  = (q4)  | (clk_b);

assign out_clk  = or_three & or_four;

endmodule 
`时标1ns/100ps
模块时钟开关(
//输出
外钟,
//投入
时钟a,时钟b,选择
);
输入时钟;
输入时钟;
输入选择;
输出时钟;
电线连接到时钟;
注册第一季度、第二季度、第三季度、第四季度;
电线或一号线、二号线、三号线或四号线;
始终@(posedge clk_a)
开始
如果(时钟a==1'b1)
开始
q1…我认为,当q3/q4的输出变低时,如果到相应的或门(或三或四)的时钟信号的路由延迟大于到或门的路由延迟+q3/q4到或门的时钟输出延迟,那么它仍然可能会有小故障。

这可能会澄清一点

图像可以单独缩放查看,它比这里显示的要大。正如埃米特·布朗博士可能会说的那样,我为模型的粗糙性道歉,它是我手边唯一的原理图编辑器。目的是显示De Morgan门等效值,显示时钟在高电平时被选通,q3和q4的输出延迟从各自时钟的上升沿开始,q3和q4具有各自时钟的剩余高波特率,用于输出延迟和时钟路由延迟


正如对问题的评论中所讨论的,对于特定时钟,存在从select到q3或q4的D输入的亚稳态路径,其中如果一个或两个时钟与select无关(VHDL源中的sel),如果选通选择未能满足受影响触发器的设置或保持时间,则q3或q4的亚稳态恢复时间必须小于其各自时钟的高波特率。这是一个时钟速度限制,可以通过增加从两个时钟域操作之间的无时钟启用周期来解决。

我继续为VHDL转换创建了一个测试台和模拟,在
clk_b到或_four
上有一个小的(10 ps)路由延迟。当然,在真正的FPGA中,
q4/C到或_-four
路径上会有几个延迟,但是
clk-b到或_-four
的路由延迟仍然可能更长。输出的整个选通也将被吸收到单个4输入LUT中,但这不会改变这种输出行为

我担心的小故障可以在480ns附近看到:

有谁能想出这样一个原因:这不会/不可能在目标上发生?静态时序分析会阻止这种情况吗

library ieee;
use ieee.std_logic_1164.all;
entity clk_switch is
   port(
      out_clk : out std_logic;
      clk_a   : in  std_logic;
      clk_b   : in  std_logic;
      sel     : in  std_logic
   );
end clk_switch;

architecture rtl of clk_switch is
   signal q1 : std_logic;
   signal q2 : std_logic;
   signal q3 : std_logic;
   signal q4 : std_logic;

   signal or_one   : std_logic;
   signal or_two   : std_logic;
   signal or_three : std_logic;
   signal or_four  : std_logic;

   signal clk_b_routed : std_logic;
begin
   clk_b_routed <= clk_b after 10 ps;

   process(clk_a)
   begin
      if (clk_a'event and clk_a='1') then
         q1 <= q4;
         q3 <= or_one;
      end if;
   end process;

   process(clk_b)
   begin
      if (clk_b'event and clk_b='1') then
         q2 <= q3;
         q4 <= or_two;
      end if;
   end process;

    or_one <= not q1 or not sel;
    or_two <= not q2 or sel;
    or_three <= q3 or clk_a;
    or_four  <= q4 or clk_b_routed;
    out_clk <= or_three and or_four;
end rtl;

library ieee;
use ieee.std_logic_1164.all;
entity tb_clk_switch is
end tb_clk_switch;
architecture testbench of tb_clk_switch is
    component clk_switch is
        port(
            clk_a   : in  std_logic;
            clk_b   : in  std_logic;
            out_clk   : out std_logic;
            sel     : in  std_logic
        );
    end component;

    signal clk_a : std_logic := '0';
    signal clk_b : std_logic := '0';
    signal out_clk : std_logic := '0';
    signal sel   : std_logic := '0';
begin
    clk_a <= not clk_a after 10 ns; --periods arbitrary
    clk_b <= not clk_b after 23 ns;
    sel   <= not sel   after 200 ns;
    uut : clk_switch
    port map (
        clk_a => clk_a,
        clk_b => clk_b,
        out_clk => out_clk,
        sel   => sel
    );
end testbench;
ieee库;
使用ieee.std_logic_1164.all;
实体clk_开关为
港口(
输出时钟:输出标准逻辑;
时钟a:在标准逻辑中;
clk_b:标准逻辑中;
sel:在标准逻辑中
);
终端时钟开关;
clk_交换机的体系结构rtl是
信号q1:std_逻辑;
信号q2:std_逻辑;
信号q3:std_逻辑;
信号q4:std_逻辑;
信号或一:标准逻辑;
信号或二:标准逻辑;
信号或三:标准逻辑;
信号或四:标准逻辑;
信号时钟b_路由:标准逻辑;
开始

clk_b_routed这个部分对我来说看起来很奇怪
总是@(posedge clk_a)if(clk_a==1'b1)
,因为posedge只会在
clk_a==1'b1
时触发,所以看起来是一个冗余语句,我认为它不会可靠地改变合成的输出(不同的工具可以以不同的方式处理它,例如添加mux/忽略它)。有一个亚稳态路径,从
select
或_two
q4
,需要在
clk\u b
的高波特率期间恢复q4亚稳态。对于
不选择
通过
或_one
q2
,这两种情况同样适用于任意打开
选择的情况。这是一个时钟速度限制,可能的触发器速度减去
或_-one
或_-two
门和路由延迟的一半,以允许亚稳态恢复。克服速度限制需要更长的非时钟周期(更多的触发器,重新计时
select
)。是的,我注意到了亚稳态问题,但假设select满足活动时钟的设置/保持(它实际改变或_-one/或_-two的值)会导致故障吗?我想是的,但我不是100%确定。通过
或_three
或_three
的选通“关闭”发生在相应的时钟高时,新时钟在高时启用<代码>或_三个
或_四个
De Morgan等效和门
out_clk
De Morgan或gate产品。在亚稳态恢复施加的触发器速度限制内,它应该是无故障的。每个时钟取决于启用前禁用的另一个时钟。我完全同意由于异步选择而禁用的时钟的时钟速度限制。我更关心的是要激活的新时钟(在两个时钟都被禁用后)何时在时钟上升的几乎同一时间从选通中释放。这是人为造成问题的一种方式。它没有显示来自clk_b的第四季度保持器过电压/输出延迟。很容易想象第四季度和/或四横跨时钟树上的两个不同分支,或者在时钟树上有10 ps的延迟。第四季度的输出延迟为零,或者第四季度到第四季度的路由延迟为零,这就有点不太可能了
library ieee;
use ieee.std_logic_1164.all;
entity clk_switch is
   port(
      out_clk : out std_logic;
      clk_a   : in  std_logic;
      clk_b   : in  std_logic;
      sel     : in  std_logic
   );
end clk_switch;

architecture rtl of clk_switch is
   signal q1 : std_logic;
   signal q2 : std_logic;
   signal q3 : std_logic;
   signal q4 : std_logic;

   signal or_one   : std_logic;
   signal or_two   : std_logic;
   signal or_three : std_logic;
   signal or_four  : std_logic;

   signal clk_b_routed : std_logic;
begin
   clk_b_routed <= clk_b after 10 ps;

   process(clk_a)
   begin
      if (clk_a'event and clk_a='1') then
         q1 <= q4;
         q3 <= or_one;
      end if;
   end process;

   process(clk_b)
   begin
      if (clk_b'event and clk_b='1') then
         q2 <= q3;
         q4 <= or_two;
      end if;
   end process;

    or_one <= not q1 or not sel;
    or_two <= not q2 or sel;
    or_three <= q3 or clk_a;
    or_four  <= q4 or clk_b_routed;
    out_clk <= or_three and or_four;
end rtl;

library ieee;
use ieee.std_logic_1164.all;
entity tb_clk_switch is
end tb_clk_switch;
architecture testbench of tb_clk_switch is
    component clk_switch is
        port(
            clk_a   : in  std_logic;
            clk_b   : in  std_logic;
            out_clk   : out std_logic;
            sel     : in  std_logic
        );
    end component;

    signal clk_a : std_logic := '0';
    signal clk_b : std_logic := '0';
    signal out_clk : std_logic := '0';
    signal sel   : std_logic := '0';
begin
    clk_a <= not clk_a after 10 ns; --periods arbitrary
    clk_b <= not clk_b after 23 ns;
    sel   <= not sel   after 200 ns;
    uut : clk_switch
    port map (
        clk_a => clk_a,
        clk_b => clk_b,
        out_clk => out_clk,
        sel   => sel
    );
end testbench;