2017-04-25 61 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並可能生成巨大的硬件。您可能正在查看狀態機,並在每個時鐘週期迭代一個單元。這取決於你的具體要求。 –