我试图用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
clock
是v_counter
。当我在此路径上使用 Locate in Design 时,Quartus指向bit_vector(9 downto 0)
进程的第一行(一个v_clock
)。
还有一个关于纹波时钟的警告提到所有rising_edge(clock_v)
位,h_counter
和三个门控时钟:clock_h
,Equal0
和{{1} }。
答案 0 :(得分:3)
如果您提供了失败路径的起点和终点,那将会有所帮助。看起来主要问题是您生成不同的时钟并且具有跨域时序问题或不完整的约束来建立不同域之间的关系。大概reset
来自clock_50
域,不应该直接在其他两个域中使用。更强大的解决方案是使用具有同步功能的单个时钟,以获得与clock_v
和clock_h
相同的效果。
当需要生成时钟时,您不应尝试在FPGA架构中构建它们,而应使用板载PLL / DLL来管理它们。域之间的偏差可以通过这种方式得到更好的控制,时序分析器可以更好地处理这种情况。每个域都需要有自己的复位信号,并与其自己的时钟同步。
注册v_active
和h_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的等效信号进行了评论,但仍未注册。