如何修复此代码中的时钟保持?

时间:2014-11-22 23:11:20

标签: vhdl timing vga

我试图用VHDL创建一个VGA驱动程序。

我需要640x480 @ 60 Hz,所以我需要25 MHz和31.5 KHz的时钟。 divider_h进程由50 MHz时钟驱动,产生25 MHz时钟。在25 MHz时钟的每个时钟周期h_counter按进程h_sync递增,当它达到某个值(H_FRONT + H_SYNC - 1)时,divider_v进程被触发并设置clock_v在短时间内达到1。

Quartus II的时序分析失败并出现警告:无法沿1条路径实现最小设置和保持要求时钟。编译报告中的时钟保持部分指出v_counter的MSB是罪魁祸首,最小松弛时间为-0.050 ns。第二低的松弛时间是0.218 ns,这很好。

我尝试将{1}的长1状态用于短暂的0状态,最小松弛时间增加到-0.019 ns,这仍然是不可接受的。

据我所知,保持时钟问题意味着在正确处理输入之前更改输入,因此我尝试使1和0都出现大致相同的时间段。令我惊讶的是,超过40条路径变为红色并出现同样的错误。

评论clock_v进程可以解决问题。

为什么MSB的松弛时间比其他位高得多?我该怎么做才能解决这个问题?

这是我的代码:

v_clock

失败路径的详细信息:

  • 来自:library ieee; use ieee.std_logic_1164.all; library Famikon; use Famikon.Types.all; use Famikon.VgaNames.all; entity VgaDriver is port ( -- inputs clock_50: in STD_LOGIC; -- 50 MHz reset: in bit; -- '1' resets r, g, b: in screen_pixel; -- bit_vector subtype -- outputs vga_x, vga_y: out hw_coord; -- integer subtype vga_drawing: out bit; hw_r, hw_g, hw_b: out hw_pixel; -- bit_vector subtype vga_hsync, vga_vsync: out bit; vga_blank, vga_clock: out bit ); end entity; architecture Arch of VgaDriver is signal clock_h, clock_v: std_logic; signal h_counter, v_counter: vga_counter; -- integer subtype signal h_coord, v_coord: hw_coord; -- integer subtype signal h_active, v_active: bit; begin -- some irrelevant code -- h_active <= '1' when (h_counter >= H_BLANK) else '0'; v_active <= '1' when (v_counter >= V_BLANK) else '0'; divider_h: process (clock_50) begin if (rising_edge(clock_50)) then clock_h <= not clock_h; end if; end process; divider_v: process (h_counter) begin if (h_counter /= H_FRONT + H_SYNC - 1) then clock_v <= '0'; else clock_v <= '1'; end if; end process; h_clock: process (clock_h, reset) begin if (rising_edge(clock_h)) then if (reset = '1') then h_counter <= 0; elsif (h_counter = H_TOTAL - 1) then h_counter <= 0; else h_counter <= h_counter + 1; end if; end if; end process; v_clock: process (clock_v, reset) begin if (rising_edge(clock_v)) then if (reset = '1') then v_counter <= 0; elsif (v_counter = V_TOTAL - 1) then v_counter <= 0; else v_counter <= v_counter + 1; end if; end if; end process; end architecture;
  • 收件人:v_counter[9]
  • 来自时钟:v_counter[9]
  • 到时钟:clock
  • 所需保持关系:0.000 ns
  • 所需的最短P2P时间:0.618 ns
  • 实际短缺P2P时间:0.568 ns
  • 最小松弛:-0.050 ns

clockv_counter。当我在此路径上使用 Locate in Design 时,Quartus指向bit_vector(9 downto 0)进程的第一行(一个v_clock)。

还有一个关于纹波时钟的警告提到所有rising_edge(clock_v)位,h_counter和三个门控时钟:clock_hEqual0和{{1} }。

2 个答案:

答案 0 :(得分:3)

如果您提供了失败路径的起点和终点,那将会有所帮助。看起来主要问题是您生成不同的时钟并且具有跨域时序问题或不完整的约束来建立不同域之间的关系。大概reset来自clock_50域,不应该直接在其他两个域中使用。更强大的解决方案是使用具有同步功能的单个时钟,以获得与clock_vclock_h相同的效果。

当需要生成时钟时,您不应尝试在FPGA架构中构建它们,而应使用板载PLL / DLL来管理它们。域之间的偏差可以通过这种方式得到更好的控制,时序分析器可以更好地处理这种情况。每个域都需要有自己的复位信号,并与其自己的时钟同步。

注册v_activeh_active以将比较逻辑与它们所提供的内容分开也是一个好主意。此外,您正在使用同步重置,因此无需在敏感列表中使用它们。

答案 1 :(得分:2)

由于您不包含Famikon库包,因此需要查找VGA时间。 (您的代码示例不是Minimal, Complete, and Verifiable example)。

Jenning想要让你的设计分析得到了以下内容:

package Types is
    subtype screen_pixel is bit_vector (3 downto 0);
    subtype hw_coord     is natural range 0 to 1023;
    subtype hw_pixel     is bit_vector (3 downto 0);
    subtype vga_counter  is natural range 0 to 1023;
end package;
package VgaNames is
    constant H_FRONT:   natural range 0 to 1023 := 16;
    constant H_SYNC:    natural range 0 to 1023 := 96;
    constant H_BACK:    natural range 0 to 1023 := 48;
    constant H_BLANK:   natural range 0 to 1023 := H_FRONT + H_SYNC + H_BACK;
    constant H_VISIBLE: natural range 0 to 1023 := 640;
    constant H_TOTAL:   natural range 0 to 1023 := H_BLANK + H_VISIBLE;

    constant V_FRONT:   natural range 0 to 1023 := 10;
    constant V_SYNC:    natural range 0 to 1023 := 2;
    constant V_BACK:    natural range 0 to 1023 := 33;
    constant V_BLANK:   natural range 0 to 1023 := V_FRONT + V_SYNC + V_BACK;
    constant V_VISIBLE: natural range 0 to 1023 := 480;
    constant V_TOTAL:   natural range 0 to 1023 := V_BLANK + V_VISIBLE;
end package;

您还会注意到首先列出消隐间隔:

h_active <= '1' when (h_counter >= H_BLANK) else '0';
v_active <= '1' when (v_counter >= V_BLANK) else '0';

您要么为vga_x和vga_y做偏移算术,要么使用单独的计数器。对于h_counter和v_counter,可以通过将显示的非空白部分设置为0来解决此问题。

然而,这不对vcount [9]设置时间问题负责。

还有其他问题。

divider_v: process (h_counter) begin
    if (h_counter /= H_FRONT + H_SYNC - 1) then
        clock_v <= '0';
    else
        clock_v <= '1';
    end if;
end process;

这看起来像是对纹波时钟负责。你试图通过组合逻辑产生clock_v。您不应该出于某些正当理由这样做 - 在h_counter位之间可能存在非对称延迟,并且门用于识别比较,即使使用LUT也存在多级组合逻辑,并且路由延迟可能不匹配。你的clock_v是否有效取决于布局的变化,它想要注册(可能是clock_h)。

回答者知道供应商对目标设备的用户以及实际的警告和错误消息是非常有帮助的。您可能会发现修复clock_v就足够了,但可能不是,在这种情况下我会想象凯文表示缺乏对设计的正确约束。

最近出现了堆栈交换问题的老式VHDL VGA时序发生器(参见VHDL VGA sync circuit)。它来自Pong P. Chu的书“用VHDL示例编写的FPGA协议,XILINX SPARTAN-3版本”的第12章,文件名list_ch12_01_vga_sync.vhd,可在作者companion website上找到的代码清单zip下载中找到。 正如Brian Drummond所指出的那样,对于那些不愿意使用编辑器搜索或打印输出的人来说,更难以阅读,将水平和垂直计数器分布在三个流程语句中(原始设计规范的视图对于某些品味而言过于平坦,并且看似过多的流程)。

Brian有一个额外的答案,它提供了一个组合过程的示例,并显示了水平计数器中垂直计数器计数器的嵌套。它还显示从“0000000000”(0)开始的非消隐水平和垂直间隔。您可能会注意到Brian还对h_active和v_active的等效信号进行了评论,但仍未注册。