2017-04-25 68 views
0

我一直在为Spartan3e在VHDL中实现蛇游戏。Vhdl Snake - 如何实现尾部自动化

我已经写了一个在VGA屏幕上绘制单元格正方形的部分,并且可以在正方形中移动它。

问题是尾部执行 - 到目前为止,我手动添加了另一个细胞段到我的蛇,但我想自动化它(例如在java中简单地使单元队列和设置下一个位置g细胞作为细胞之前)。我不知道如何在vhdl中编写如此复杂的函数。

这是我的代码:

begin 
    process (clk, reset, endOfGame) 
    begin 
     if reset='1' or endOfGame=true then 

     ball_y_reg <= to_unsigned(231,10); 
     ball_x_reg <= to_unsigned(311,10); 
     ball_x_reg_cell<=to_unsigned(231,10); 
     ball_y_reg_cell<=to_unsigned(311,10); 
-- velocity after reset schould be none 
     x_delta_reg <= ("0000000000"); 
     y_delta_reg <= ("0000000000"); 


     elsif (clk'event and clk='1') then 
     ball_x_reg_cell<=ball_x_next_cell; 
     ball_y_reg_cell<=ball_y_next_cell; 
     ball_x_reg <= ball_x_next; 
     ball_y_reg <= ball_y_next; 
     x_delta_reg <= x_delta_next; 
     y_delta_reg <= y_delta_next; 
     end if; 
    end process; 

    pix_x <= unsigned(pixel_x); 
    pix_y <= unsigned(pixel_y); 

    -- refr_tick: 1-clock tick asserted at start of v-sync 
    -- i.e., when the screen is refreshed (60 Hz) 
    refr_tick <= '1' when (pix_y=481) and (pix_x=0) else 
       '0'; 

    ---------------------------------------------- 
    -- pixel within wall 
    wall_on <= 
     '1' when ((WALL_X_LEFTSIDE_L<=pix_x) and (pix_x<=WALL_X_LEFTSIDE_R)) or ((WALL_X_RIGHTSIDE_L<=pix_x) and (pix_x<=WALL_X_RIGHTSIDE_R)) or ((WALL_Y_UPSIDE_U<=pix_y) and (pix_y<=WALL_Y_UPSIDE_D)) or ((WALL_Y_DOWNSIDE_U<=pix_y) and (pix_y<=WALL_Y_DOWNSIDE_D)) else 
     '0'; 
    -- wall rgb output 
    wall_rgb <= "001"; -- blue 



    ---------------------------------------------- 

    -- square ball 

    ball_x_l <= ball_x_reg; 
    ball_y_t <= ball_y_reg; 
    ball_x_r <= ball_x_l + BALL_SIZE - 1; 
    ball_y_b <= ball_y_t + BALL_SIZE - 1; 

    ball_x_l_cell <= ball_x_reg_cell; 
    ball_y_t_cell <= ball_y_reg_cell; 
    ball_x_r_cell <= ball_x_l_cell + BALL_SIZE - 1; 
    ball_y_b_cell <= ball_y_t_cell + BALL_SIZE - 1; 


    --tail 


    -- pixel within squared ball 
    sq_ball_on <= 
     '1' when ((ball_x_l<=pix_x) and (pix_x<=ball_x_r) and 
       (ball_y_t<=pix_y) and (pix_y<=ball_y_b)) 
       or 
       ((ball_x_l_cell<=pix_x) and (pix_x<=ball_x_r_cell) and 
       (ball_y_t_cell<=pix_y) and (pix_y<=ball_y_b_cell)) 
       else 
     '0'; 

    ball_x_next <= ball_x_reg + x_delta_reg 
        when refr_tick='1' else 
        ball_x_reg ; 
    ball_y_next <= ball_y_reg + y_delta_reg 
        when refr_tick='1' else 
        ball_y_reg ; 

    ball_x_next_cell <= ball_x_reg - BALL_SIZE when refr_tick='1' and CURRENT_DIRECTION = DIR_RIGHT 
        else ball_x_reg + BALL_SIZE when refr_tick='1' and CURRENT_DIRECTION = DIR_LEFT 
        else ball_x_reg when refr_tick='1' 
        else ball_x_reg_cell; 

    ball_y_next_cell <=  ball_y_reg - BALL_SIZE when refr_tick='1' and CURRENT_DIRECTION = DIR_UP 
         else ball_y_reg + BALL_SIZE when refr_tick='1' and CURRENT_DIRECTION = DIR_DOWN 
         else ball_y_reg when refr_tick='1' 
         else ball_y_reg_cell; 

    -- new bar y-position 
    process(ball_y_reg, ball_y_b, ball_y_t, refr_tick, btn, ball_x_reg ,ball_x_r, ball_x_l, x_delta_reg, y_delta_reg) 
    begin 
     x_delta_next <= x_delta_reg; 
     y_delta_next <= y_delta_reg; 


     if refr_tick='1' then 
     if btn(1)='1' and ball_y_b<(MAX_Y-1-BALL_SIZE) then 
      if CURRENT_DIRECTION /= DIR_UP then 

       CURRENT_DIRECTION <= DIR_DOWN; 
       y_delta_next <= BALL_V_P; -- move down 
       x_delta_next <= (others=>'0'); 

      end if; 
     elsif btn(0)='1' and ball_y_t > BALL_SIZE then 
      if CURRENT_DIRECTION /= DIR_DOWN then 

       CURRENT_DIRECTION <= DIR_UP; 
       y_delta_next <= BALL_V_N; -- move up 
       x_delta_next <= (others=>'0'); 

      end if; 
     elsif btn(2)='1' and ball_x_r<(MAX_X-1-BALL_SIZE) then 
      if CURRENT_DIRECTION /= DIR_LEFT then 

       CURRENT_DIRECTION <= DIR_RIGHT; 
       x_delta_next <= BALL_V_P; 
       y_delta_next <= (others=>'0'); 

      end if; 
     elsif btn(3)='1' and ball_x_l > BALL_SIZE then 
      if CURRENT_DIRECTION /= DIR_RIGHT then 

       CURRENT_DIRECTION <= DIR_LEFT; 
       x_delta_next <= BALL_V_N; 
       y_delta_next <= (others=>'0'); 

      end if; 
     end if; 

     if ball_x_l < WALL_X_LEFTSIDE_R or ball_y_t < WALL_Y_UPSIDE_D or ball_y_b > WALL_Y_DOWNSIDE_U or ball_x_r > WALL_X_RIGHTSIDE_L then 
     endOfGame <= true; 
     CURRENT_DIRECTION <= IDLE; 
     else 
     endOfGame <= false; 
     end if; 

     end if; 
    end process; 

“球X下一单元格” 份手动添加第二小区。

我一直在搜索包含类似问题的主题,但它没有涵盖在vhdl中。

感谢您的帮助!

回答

2

问题不在VHDL--不要迷失在VHDL和Java之间的语言差异中 - 这些在这里是微不足道的。

问题在于可合成性 - 您需要一个可以用硬件表示的概念设计。

你说你的Java实现使用一个队列 - 这将基于链接列表,节点(段)动态分配,并通过指针引用。事实上,你可以直接将它转换成VHDL,使用访问类型,新的和释放等等。您必须自己实现细节,而Java中可能有一个方便的库,即类。但这仅仅是一个细节。

不要走这条道路 - 访问类型,尤其是动态分配不是综合的 - 你不能正常地产生和硬件运行系统的空闲块...

(但你可能会做如果你想在模拟器中运行一个现有的Snake,与合成版本并行运行,比较它们的结果并验证可合成的Snake是否与已经被证实的软件版本相匹配如果你需要一个高可靠性的Snake设计用于军事,航空航天或者安全的关键要求,你需要这一步。)

你需要一个不同的硬件设计思维,基于知道什么是物理可实现的,以及如何把概念翻译成那个。

因此,您需要考虑如何在系统启动之前实现蛇段,并且只在需要时才开启。然后考虑在系统启动之前如何创建尽可能多的系统。

例如,某个细分受众群可能需要了解其颜色和X/Y坐标以及其他一些内容,例如,它是否已开启/可见。你怎么能代表这一切?

你可能会决定,玩过游戏并达到50个分段,100就足以赢得比赛。

现在,记录和固定大小的数组是绝对可合成的。

这可能会让你开始...

+0

感谢您的快速回答!我意识到vhdl语言的局限性,但是我正在询问实现技巧。我知道我必须使用包含正确和下一个位置,方向,可视性的记录数组。问题是,我如何通过并发语句来遍历记录数组,如我现在使用的单元格(段)。我需要做这样的操作,因为我必须面对动画。 –

+0

这取决于您的性能需求。一个简单的循环可以在单个时钟周期内迭代阵列的范围,但是会阻止将该阵列实现为BlockRam并可能生成巨大的硬件。您可能正在查看状态机,并在每个时钟周期迭代一个单元。这取决于你的具体要求。 –