0

我目前正在尝试在 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 <= Ecran(coordX,coordY);

如果我用整数值替换 coordX 或 coordY 之一,它工作正常(显示与缓冲区不匹配,但它工作),但如果我对它们都使用变量,它会在合成过程中崩溃。我很确定我对数组做错了什么(我刚刚学会了如何使用它们),即使它似乎与一些工作代码匹配。我也可能(并且可能)使用过大的数组。

如果有人知道我做错了什么,或者对如何在 vhdl 中创建屏幕缓冲区有更好的方法,我们将不胜感激。

非常感谢您提前。

4

2 回答 2

2

我不确定 VGA 是如何工作的,但是查看您的代码,我相信您的“绘图过程”存在根本问题。您正在尝试像软件开发人员而不是硬件开发人员那样做某事。

简而言之,将大部分流程嵌套在这个 if 语句下

if (drawing = '1') and clk25 = '1' and busy = '0' then

是你的问题。我可以看到两个原因。首先,您以与时钟完全异步的速率递增循环中的计数器(您说如果时钟 = '1'),该时钟在非有限周期内为高电平。因此,该增量器的更新仅受通过计数器的传播延迟的限制。所有计数器必须是同步的(如果rising_edge(clk))或(如果clock = 1 和clk'event)。

另一个错误与您当前的组合设置(异步)有关,如果您将其设置为同步过程,它将消失。通过在组合逻辑中的 if 语句之后立即执行 busy <= '1' ,您实际上是在硬件中停用该块。根据您编写同步解决方案的方式,这对您来说可能是也可能不是问题。

最后,这也是因为您正在考虑编程软件而不是硬件,您在 if 语句的开头执行 busy<='1' 并在 if 语句的末尾执行 busy<='0'。对于同步或异步设计,无论如何这只会导致忙 <='0'。相反,(当你同步时)在你的 if 语句之外有 busy <= '0' ,在你的 if 语句内有 busy <= '1' 。每次执行该语句时,busy 将在整个时钟信号中为 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一无所知

于 2012-01-18T20:53:37.373 回答
1

如果我用整数值替换 coordX 或 coordY 之一,它工作正常(显示与缓冲区不匹配,但它工作),但如果我对它们都使用变量,它会在合成过程中崩溃。我很确定我对数组做错了什么(我刚刚学会了如何使用它们),即使它似乎与一些工作代码匹配。我也可能(并且可能)使用过大的数组。

问题是您正在尝试为由小块 RAM 组成的大内存构建读取多路复用器。对于特定的构建平台,足够的块和问题变得难以解决。

您可以修改视频定时生成器以解耦显示读取地址,在这种情况下允许您将 TAB_BUFFER 定义为更小(0 到 639、0 到 479),从而节省三分之二的内存(307,200 对 1 M 像素)。目前尚不清楚这是否会将问题缩小到足够小以使其合成,如果确实如此,它是否会足够快。

无论如何,您可能还希望将帧缓冲区地址与当前的水平和垂直计数器分离,或者使用单独的显示地址计数器,或者通过将零作为一行上的第一个可见像素或显示器中的第一个可见行来传递。这样的想法将使您不必在写入期间进行地址转换。

您可以尝试定义内存设计以克服无法合成它的问题。这可以像放置一样简单,也可以像创建层次结构一样复杂。这个想法是通过减少工作量来减少合成中的一些艰苦工作。

于 2012-01-19T08:05:28.127 回答