基于VHDL的FPGA蛇形游戏

基于VHDL的FPGA蛇形游戏,vhdl,fpga,Vhdl,Fpga,我用VHDL编写了一个蛇游戏,使用Altera的DE2-115 FPGA。我用VGA协议将FPGA与显示器连接起来,以显示游戏 我在显示snake和在显示器上移动snake时遇到了一个问题(FPGA有4个,上/下/左/右) 在代码中,每次推底处于低状态时,使用SQ_X1和SQ_Y1进行移动 还有其他方法做动作吗?无需按下任何底部(使用循环或类似的方式),并在按下底部以模拟蛇的运动时改变方向 ARCHITECTURE behavior OF hw_image_generator IS SI

我用VHDL编写了一个蛇游戏,使用Altera的DE2-115 FPGA。我用VGA协议将FPGA与显示器连接起来,以显示游戏

我在显示snake和在显示器上移动snake时遇到了一个问题(FPGA有4个,上/下/左/右

在代码中,每次推底处于低状态时,使用SQ_X1SQ_Y1进行移动

还有其他方法做动作吗?无需按下任何底部(使用循环或类似的方式),并在按下底部以模拟蛇的运动时改变方向

ARCHITECTURE behavior OF hw_image_generator IS
    SIGNAL SQ_X1,SQ_Y1: INTEGER RANGE 0 TO 1688:=400; --initial position X      
    SIGNAL SQ_X2,SQ_Y2: INTEGER RANGE 0 TO 1688:=600; --initial position Y
    SIGNAL DRAW: STD_LOGIC;                                         

BEGIN
    SQ(column,row,SQ_X1,SQ_Y1,DRAW);    -- function that print a square (head of snake with SQ variables)   
    PROCESS(disp_ena, row, column, down, up, left, right)
    BEGIN
        IF(disp_ena = '1') THEN     --display time  
            IF (column=19 or column=1901 or row=19 or row=1181) THEN  -- print the border
                red <= (OTHERS => '1'); 
                green   <= (OTHERS => '0');
                blue <= (OTHERS => '0');
            ELSE
                red <= (OTHERS => '0');
                green   <= (OTHERS => '0');
                blue <= (OTHERS => '0');
            END IF;

            IF (DRAW = '1') THEN   -- it comes from a package that print a square (head of snake)
                red <= (OTHERS => '1');
                green   <= (OTHERS => '1');
                blue <= (OTHERS => '1');
            END IF;

            --up, down right and left are input of FPGA (push bottom)
            --SQs are the current postions of X and Y and the add is to make the movement
            IF(up='0' AND down='1' AND right='1' AND left='1' )THEN
                IF (SQ_X1-40 > 20) THEN 
                    SQ_X1<=SQ_X1-40;
                END IF;        
            END IF;

            IF(up='1' AND down='0' AND right='1' AND left='1')THEN
                IF (SQ_X1+40 < 1180) THEN 
                    SQ_X1<=SQ_X1+40;
                END IF; 
            END IF;
            IF(tup='1' AND down='1' AND right='0' AND left='1')THEN
                IF (SQ_Y1+40 < 1900) THEN 
                    SQ_Y1<=SQ_Y1+40;
                END IF; 
            END IF;
            IF(up='1' AND down='1' AND right='1' AND left='0')THEN
                IF (SQ_Y1-40 > 20) THEN 
                    SQ_Y1<=SQ_Y1-40;
                END IF;
            END IF;
        END IF;

    END PROCESS;
END BEHAVIOR;
hw_映像_生成器的架构行为是 信号SQ_X1,SQ_Y1:整数范围0至1688:=400--初始位置X 信号SQ_X2,SQ_Y2:整数范围0至1688:=600--初始位置Y 信号提取:标准逻辑; 开始 SQ(列、行、SQ_X1、SQ_Y1、绘图);--打印正方形的函数(带SQ变量的蛇头) 进程(显示、行、列、下、上、左、右) 开始 如果(disp_ena='1'),则——显示时间 如果(column=19或column=1901或row=19或row=1181),则--打印边框 红色“1”); 绿色“0”); 蓝色“0”); 其他的 红色“0”); 绿色“0”); 蓝色“0”); 如果结束; 如果(DRAW='1'),那么——它来自一个打印正方形(蛇头)的包 红色“1”); 绿色“1”); 蓝色“1”); 如果结束; --上、下、右、左为FPGA输入(推底) --SQs是X和Y的当前位置,add用于进行移动 如果(向上='0'和向下='1'以及向右='1'和向左='1'),则 如果(SQ_X1-40>20),则
SQ_X1首先,我建议您将显示器和位置更新功能拆分为单独的流程,以使事情更清楚

您似乎已经拥有了显示过程所需的一切,除了Paebbels在评论中提到的,这应该是一个同步(即计时)过程。我假定您的时钟名为
clk

PROCESS(clk)
BEGIN
    IF rising_edge(clk) THEN
        --display time 
        IF(disp_ena = '1') THEN 
            -- print the border                
            IF (column=19 or column=1901 or row=19 or row=1181) THEN
                red <= (OTHERS => '1'); 
                green   <= (OTHERS => '0');
                blue <= (OTHERS => '0');
            ELSE
                red <= (OTHERS => '0');
                green   <= (OTHERS => '0');
                blue <= (OTHERS => '0');
            END IF;

            IF (DRAW = '1') THEN   
                red <= (OTHERS => '1');
                green   <= (OTHERS => '1');
                blue <= (OTHERS => '1');
            END IF;
        END IF;
    END IF;
END PROCESS;
然后,创建方向状态进程

process(clk) begin
    if rising_edge(clk) then
        if rst = '1' then
            direction <= DIR_UP;
        else
            if up = '0' then
                direction <= DIR_UP;
            elsif down = '0' then
                direction <= DIR_DOWN;
            elsif left = '0' then
                direction <= DIR_LEFT;
            elsif right = '0' then
                direction <= DIR_RIGHT;
            end if;
        end if;
    end if;
end process;
如果更新太快,您可能需要使用计数器再次划分此信号的频率,但至少您的计数器不必以百万计。根据此信号,您现在可以更新您的位置,如下所示:

process(clk)
begin
    if rising_edge(clk) then
        if rst = '1' then
            -- adapt starting position to your taste
            SQ_X1<= 100;
            SQ_Y1<= 100;
        elsif update_ce = '1' then
            case direction is
            when DIR_UP =>
                if SQ_X1 - 1 > 20 then 
                    SQ_X1 <= SQ_X1 - 1;
                end if;

            when DIR_DOWN =>
                if SQ_X1 + 1 < 1180 then 
                    SQ_X1 <= SQ_X1 + 1;
                end if; 

            when DIR_LEFT =>
                if SQ_Y1 - 1 > 20 then 
                    SQ_Y1 <= SQ_Y1 - 1;
                end if;

            when others =>
            -- DIR_RIGHT
                if SQ_Y1 - 1 > 20 then 
                    SQ_Y1 <= SQ_Y1 - 1;
                end if;                    
            end case;
        end if;
    end if;
end process;
过程(clk)
开始
如果上升沿(clk),则
如果rst='1',则
--根据您的口味调整起始位置
SQ_X1 20那么
SQ_X1
如果SQ_X1+1<1180,则
SQ_X1
如果SQ_Y1-1>20,则
SQ_Y1
--对
如果SQ_Y1-1>20,则

这个设计好像没有时钟!?没有钟它怎么工作?你模拟过你的代码吗?嗨,佩伯!时钟位于提供行和列的当前位置的其他模块中,因此在该模块中不需要时钟。对于拼写Ben Voigt,非常抱歉!我还在学英语!XDSo,如果这个模块没有时钟,谁应该综合翻译这行
SQ_X1这不是好的风格,在99.99%的设计中有一个错误。另一个clk是处理这个状态机,因为问题已经解决了!谢谢佩培尔!因为启用哪个时钟周期并不重要,所以您可以用并发分配
update_ce@ben voigt替换整个进程,您完全正确。在这种情况下,我会在同步进程中这样做,因为1)它通过将更新进程逻辑从时钟启用生成逻辑中分离出来来帮助改进时序,2)它只需要一个触发器,3)额外的一个时钟周期延迟在这里不是问题。谢谢你的评论。这让我意识到,在这个过程中,我实际上并没有使用更新。刚修好。:)我有其他模块,每个时钟提供当前行和列,所以在这种情况下不需要。对于Philippe的意见,这是正确的解决方案,提前感谢您的想法!我用一个时钟做运动,用正确的分频器加上运动,用四个B-U-T-T-O-N-S XD分配每个方向,所以在这种情况下,它可以做我想要的。还有一个问题(我有一个X和Y的随机位置来生成蛇的食物,使其变大)我如何做蛇的运动?我的意思是当蛇向右/向左/向上/向下转弯时,所有的尾巴都跟随头部的运动。。。谢谢
signal update_ce : std_logic;

-- (...)

process(clk) begin
    if rising_edge(clk) then
        -- adapt the value to your taste
        if disp_ena = '1' and column = 1901 and row = 1181 then
            update_ce <= '1';
        else
            update_ce <= '0';
        end if;
    end if;
end process;
process(clk)
begin
    if rising_edge(clk) then
        if rst = '1' then
            -- adapt starting position to your taste
            SQ_X1<= 100;
            SQ_Y1<= 100;
        elsif update_ce = '1' then
            case direction is
            when DIR_UP =>
                if SQ_X1 - 1 > 20 then 
                    SQ_X1 <= SQ_X1 - 1;
                end if;

            when DIR_DOWN =>
                if SQ_X1 + 1 < 1180 then 
                    SQ_X1 <= SQ_X1 + 1;
                end if; 

            when DIR_LEFT =>
                if SQ_Y1 - 1 > 20 then 
                    SQ_Y1 <= SQ_Y1 - 1;
                end if;

            when others =>
            -- DIR_RIGHT
                if SQ_Y1 - 1 > 20 then 
                    SQ_Y1 <= SQ_Y1 - 1;
                end if;                    
            end case;
        end if;
    end if;
end process;