我目前正在尝试用VHDL创建一个屏幕缓冲区(用于通过VGA发送视频数据的设备)。我正在使用Xilinx ISE 13.1,而且我是VHDL的初学者。
我的想法是创建一个包含每个像素RGB值的大型二维数组(8位)。
我可以毫无问题地在数组中写入,但是当我必须阅读它时它变得更加复杂:合成变得非常长,并且XST只是完全使内存饱和,直到计算机自行关闭。
以下是我的代码的简化版本,只是尝试绘制一个红色的45°线:
entity Pilotage_ecran is
port(clk25 : in std_logic; --25MHz clock
red_out : out std_logic; --Untill the problem is solved, i use only 1 bit to set colors
green_out : out std_logic;
blue_out : out std_logic;
hs_out : out std_logic;
vs_out : out std_logic);
end Pilotage_ecran;
architecture Behavioral of Pilotage_ecran is
signal horizontal_counter : std_logic_vector (9 downto 0);
signal vertical_counter : std_logic_vector (9 downto 0);
signal drawing : std_logic; --Signal that is set to 1 when the active video area is reached
signal busy : std_logic; --Signal to avoid launching the drawing process twice in parallel
--The array (actually containing single bits instead of vectors untill I solve the problem)
type TAB_BUFFER is array(0 to 1023, 0 to 1023) of std_logic;
signal Ecran : TAB_BUFFER := (others=>'0');
begin
主要流程:
process (clk25)
variable coordX : integer;
variable coordY : integer;
begin
if clk25'event and clk25 = '1' then
if (horizontal_counter >= "0010010000" ) -- 144 : limits of active video area
and (horizontal_counter < "1100010000" ) -- 784
and (vertical_counter >= "0000100111" ) -- 39
and (vertical_counter < "1100010000" ) -- 519
then
drawing <= '1';
coordX := conv_integer (horizontal_counter);
coordY := conv_integer (vertical_counter);
if Ecran(coordX,coordY) = '1' then --Here is the problem
red_out <= '1';
green_out <= '0';
blue_out <= '0';
else
red_out <= '0';
green_out <= '0';
blue_out <= '0';
end if;
else
drawing <= '0';
end if;
--Hsync and Vsync come after, but the code is safe and tested
end if;
end process;
绘图过程(实际上以丑陋的方式绘制一条线,但我只想在缓冲区中获取任何内容)。
draw :
process (drawing, clk25, busy)
--Coordinates of the starting point (actually random values...)
variable i : integer;
variable j : integer;
begin
if (drawing = '1') and clk25 = '1' and busy = '0' then
busy <= '1';
i :=300;
j :=300;
--The loop setting the coordinates of the line to '1'
loopx : while (i<=350) loop
Ecran(i,j) <= '1';
i := i+1;
j := j+1;
end loop loopx;
busy <='0';
end if;
end process draw;
end Behavioral;
导致我麻烦的那一行是我试图访问缓冲区中某些坐标的值:
如果Ecran(coordX,coordY)='1'则
我也尝试这样做:
red_out&lt; = Ecran(coordX,coordY);
如果我用整数值替换coordX或coordY中的一个,它工作正常(显示器不匹配缓冲区但它可以工作),但如果我使用它们的变量,它会在合成期间崩溃。我很确定我对数组做了一些错误(我刚刚学会了如何使用它们),即使它似乎与某些工作代码相匹配。我也可能(并且可能)使用太大的阵列。
如果有人知道我做错了什么,或者有更好的方法来了解如何在vhdl中创建屏幕缓冲区,那么任何帮助都会非常感激。
非常感谢你。
答案 0 :(得分:2)
我不确定VGA是如何工作的但是看看你的代码我相信你的“绘图过程”存在根本性的错误。你试图做一些软件开发人员而不是硬件开发人员。
简而言之,在if语句
下嵌套大部分进程if (drawing = '1') and clk25 = '1' and busy = '0' then
是你的问题。我能看到的两个原因。首先,你在循环中递增计数器的速率完全与时钟异步(你说如果时钟='1'),这在非有限时间内是高的。因此,该增量器的更新仅受到通过计数器的推迟延迟的限制。所有计数器必须是同步的(如果rising_edge(clk))或(如果clock = 1和clk'event)。
另一个错误与您当前的组合设置(异步)有关,如果您将其设置为同步过程,它将会消失。通过在组合逻辑中的if语句之后执行busy&lt; ='1',您实际上是在硬件中停用该块。根据您对同步解决方案的编码方式,这对您来说可能是也可能不是问题。
最后,这又是因为你正在考虑编程软件而不是硬件,你在开始时忙着&lt; ='1'而在if语句结束时忙&lt; ='0'。无论是同步还是异步设计,无论如何都会导致繁忙的&lt; ='0'。相反,(当你同步时)在if语句之外忙碌&lt; ='0'并且在if语句中忙碌&lt; ='1'。每次语句执行忙时,整个时钟信号都为1。
编程VHDL时,您需要考虑连续(异步)或定期(与时钟同步)执行的每个命令。即使if语句中的事件不为真,也会执行if语句中的所有事件。 if语句仅用作“启用”。说完所有这些后,下面的代码可能正在做你想要的。
draw : process (clk25)
--Coordinates of the starting point (actually random values...)
variable i : integer := 300;
variable j : integer := 300;
begin
if (rising_edge(clk)) then
busy <= '0';
if (i<=350) then
busy <= '1';
Ecran(i,j) <= '1';
i := i+1;
j := j+1;
end if;
end if;
end process draw;
我认为你的“抽屉”实际上只是预加载大型数组,而你设置颜色的其他过程实际上是你的作者?当你把红色/绿色/蓝色位写到屏幕上时,我的印象是你在整行中递增然后向下移动一列?我对VGA
一无所知答案 1 :(得分:1)
如果我用整数值替换coordX或coordY中的一个,它就可以工作 很好(显示器与缓冲区不匹配,但它有效),但如果我使用 两者的变量在合成过程中崩溃。我很漂亮 确定我做了一些错误的数组(我刚学会了如何使用 他们),即使它似乎匹配一些工作代码。我也可以(和 可能)使用太大的数组。
问题是你正在尝试为由小块RAM组成的大容量内存构建一个读多路复用器。足够的块和问题变得棘手,因为你是特定的构建平台。
您可以修改视频定时发生器以解除显示读取地址,在这种情况下允许您将TAB_BUFFER定义为较小(0到639,0到479),从而节省三分之二的内存(307,200对比1 M像素)。目前尚不清楚将问题缩小到足以使其合成,如果确实如此,它是否足够快。
您可能还想要使用单独的显示地址计数器从当前水平和垂直计数器中解除帧缓冲区地址,或者通过将0作为显示器中的第一个可见像素或第一条可见线路。这样做的想法可以使您免于在写入期间进行地址转换。
您可以尝试定义内存设计以克服无法合成它。这可以像放置一样简单,也可以像创建层次结构一样复杂。这个想法是你通过减少工作量来完成一些艰苦的工作。