vhdl 中的屏幕缓冲区导致合成期间崩溃

发布于 2024-12-27 11:41:44 字数 3193 浏览 2 评论 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 中创建屏幕缓冲区,任何帮助将不胜感激。

预先非常感谢您。

I am currently trying to create a screen buffer in VHDL (for a device that sends video data via VGA). I am using Xilinx ISE 13.1, and i am a begginer in VHDL.

My idea was to create a large bidimensional array containing the RGB value of each pixel (on 8 bits).

I can write in the array with no problem, but it becomes more complicated when I have to read it : The synthesis becomes extremely long, and XST just completely saturates the memory untill the computer shuts down by itself.

Here is a simplified version of my code, just trying to draw a red 45° line :

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

Main process :

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;

Drawing process (actually drawing a line in an ugly way but i just wanted to get anything in the buffer).

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;

The line that causes me troubles is the one where i try to access the value at some coordinates in the buffer:

if Ecran(coordX,coordY) = '1' then

I also tried to do like this :

red_out <= Ecran(coordX,coordY);

If i replace one of coordX or coordY by an integer value, it works fine (the display doesnt match the buffer but it works), but if i use variables for both of them it crashes during synthesis. I am pretty sure i did something wrong with the array (i just learned how to use them), even if it seems to match some working codes. I could also (and probably) be using a too large array.

If anyone have an idea of what i did wrong, or have a better method on how to create a screen buffer in vhdl, any help would be very appreciated.

Thank you very much in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

还给你自由 2025-01-03 11:41:44

我不确定 VGA 是如何工作的,但看看你的代码,我相信你的“绘图过程”有根本性的错误。您正在尝试以软件开发人员而不是硬件开发人员的身份做某事。

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

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

就是您的问题。我能看出两个原因。首先,您以完全与时钟异步的速率递增循环中的计数器(您说如果时钟=“1”),该速率在非有限周期内较高。因此,该增量器的更新仅受通过计数器的传播延迟的限制。所有计数器必须同步(如果上升沿(clk))或(如果时钟 = 1 且 clk'event)。

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

最后,这又是因为您正在考虑编程软件而不是硬件,因此您在 if 语句的开头处执行 busy<='1' ,并在 if 语句的末尾处执行 busy<='0' 。对于同步或异步设计,无论如何这都将导致 busy <='0'。相反,(当您进行同步时)在 if 语句外部设置 busy <= '0',在 if 语句内部设置 busy <= '1'。每次执行该语句时,busy 的整个时钟信号都会为 1。

当您对 VHDL 进行编程时,您需要考虑连续(异步)或周期性(与时钟同步)执行的每个命令。即使 if 语句中的某个事件不为 true,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一无所知

Im not sure how VGA works but looking at your code I believe there is something fundamentally wrong with your "Drawing Process". You are attempting to do something as a software developer would rather than a hardware developer.

In short, nesting most of the process under this if statement

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

is your problem. Two reasons I can see. First you are incrementing counters in the loop at rate totally asynch to the clock (you say if clock = '1') which is high for a non finite period. The update of that incrementer is therefor limited only by propegation delay through the counter. All counters must be synchronous (if rising_edge(clk)) or (if clock = 1 and clk'event).

The other error has to do with your current combinatorial setup (asynch) which will go away if you make this into a synchronous process. By doing busy <= '1' right after the if statement in the combinatorial logic you are essentially deactivating that block in hardware. Depending on how you code your synchronous solution this may or may not be a problem for you.

Lastly, and again this is because you are thinking of programming software not hardware, you do busy<='1' at the beginning and busy<='0' at the end of the if statement. For either the synch or asynch design this will just result in busy <='0' no matter what. Instead, (when you go synchronous) have busy <= '0' outside of your if statement and busy <= '1' inside of your if statement. Every time the statement executes busy will be 1 for the entirety of the clock signal.

When you program VHDL you need to think about every single command executing either continuously (asynchronus) or periodically (synchronously with the clock). Even if an event in an if statement is not true, all the events in the if statement are being executed. The if statement merely acts as an "enable". Having said all of this, the following code might be doing what you want.

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;

I think that your "drawer" is really just pre loading the large array and that your other process which is setting colors is in fact your writer? I got the impression that you were incrementing through an entire row then shifting down a column as you write red/green/blue bits to the screen? Again I don't know anything about VGA

↘紸啶 2025-01-03 11:41:44

如果我用整数值替换 coordX 或 coordY 之一,它就可以工作
很好(显示与缓冲区不匹配,但它可以工作),但是如果我使用
它们的变量在合成过程中都会崩溃。我很漂亮
当然我对数组做错了(我刚刚学会了如何使用
它们),即使它看起来与某些工作代码匹配。我也可以(并且
可能)使用了太大的数组。

问题是您正在尝试为由小块 RAM 组成的大内存构建一个读取多路复用器。足够多的块,对于您特定的构建平台来说,问题变得棘手。

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

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

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

If I replace one of coordX or coordY by an integer value, it works
fine (the display doesn't match the buffer but it works), but if i use
variables for both of them it crashes during synthesis. I am pretty
sure i did something wrong with the array (i just learned how to use
them), even if it seems to match some working codes. I could also (and
probably) be using a too large array.

The issue is you're trying to build a read multiplexer for a large memory comprised of small blocks of RAM. Enough blocks and the problem becomes intractable for you're particular build platform.

You could modify you video timing generator to uncouple display read addresses, allowing you in this case to define your TAB_BUFFER smaller (0 to 639, 0 to 479), saving two thirds of the memory (307,200 versus 1 M Pixels) . It's not clear that would scale the problem down small enough to make it synthesize, and if it does, whether it would be fast enough.

You'd likely also want to uncouple frame buffer addresses from the present horizontal and vertical counters anyway either using separate display address counters or otherwise by passing through zero as the first visible pixel on a line or first visible line in the display. The idea being this would save you from having to do address translation during writes.

You could try defining the memory design to overcome the inability to synthesize it. This could be as simple as doing placement or as complex as creating hierarchy. The idea is you take some of the hard work away from synthesis by giving it less work to do.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文