原创 【转】VHDL设计举例:一个游戏程序

2010-11-5 01:08 908 2 2 分类: FPGA/CPLD

--   Copyright (c) 1993,1994 by Exemplar Logic, Inc.  All Rights Reserved.


--


-- This source file may be used and distributed without restriction  


-- provided that this copyright statement is not removed from the file


-- and that any derivative work contains this copyright notice.       


--


-----------


--


--  This is a synthesizable description that implements an emulator


--  of the Mancala game (African beans game).


--


--  Description of the Hardware


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


--


--  The hardware for the game includes a number of displays, each with a button and


--  a light, that each represent a 'bin' that can store marbles (beans).


--


--  The display indicates the number of marbles in each bin at any given time.


--  The light indecates that the present bin is not empty and that pushing the


--  button is a valid move in the game.


--


--  The button for each display indicates that a player takes the marbles from


--  the selected bin, and takes them in his hand. The hand is represented by a


--  diplay itself (no button).


--


--  Each player has a home bin, located on opposite sides of the game. The home


--  bin is also represented by a display. There should not be a button on the


--  home bins, since the game does not allow the removal of marbles from the home


--  bins.


--


--  Besides this, the game has a button to start the game, and a reset for power-up


--  purposes.


--


--  Here is a picture that represents the hardware setup of the game :


--


--


--  *  == Light for valid move or to indicate the player who is active


--  O  == Button to make move


--  _


-- | |


--  -  == 7 - segment display


-- |_|


--


--                           work bins


--                  *   O     *   O     *   O     *   O


--                  _   _     _   _     _   _     _   _


--                 | | | |   | | | |   | | | |   | | | |


--                  -   -     -   -     -   -     -   -


--       *         |_| |_|   |_| |_|   |_| |_|   |_| |_|         *


--     _   _                                                   _   _


--    | | | |                                                 | | | |


--     -   -                                                   -   -


--    |_| |_|                                                 |_| |_|


--


-- home bin LEFT                                           home bin right


--                  *   O     *   O     *   O     *   O          


--                  _   _     _   _     _   _     _   _


--                 | | | |   | | | |   | | | |   | | | |


--                  -   -     -   -     -   -     -   -


--                 |_| |_|   |_| |_|   |_| |_|   |_| |_|


--


--                            work bins


--


--     _   _


--    | | | |


--     -   -                                              O  Start Game


--    |_| |_|


--


--    Hand bin


--


--


-- The Rules of the game


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


--


--    At the start of the game, the left player is active and can make a move.


--    The left player selects a bin (by pressing the corresponding button).


--    The machine will move the marbles from the bin (display) to the hand (diplay)


--    and drop one marble in each successive bin (clockwise) from the hand,


--    starting with the bin clock-wise adjecent to the selected bin.


--    A marble is never dropped in a opponents home bin (will be skipped).


--


--    If the last marble from the hand is dropped in an empty bin, the players


--    switch turns, and it is the other players turn to make a move.


--


--    If the last marble from the hand is dropped in the players home bin,


--    the player can make another move.


--


--    If the last marble from the hand is dropped in a non-empty work bin,


--    all the marbles from that bin will be moved back to the hand and the


 --   game proceeds.


--


--    The game ends if there are no more marbles in any of the work bins.


--


--    The winner of the game is the player who has most marbles in his/her


--    home bin at the end of the game.


--


--


--


--  About the design


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


--


--    The design contains a controller and a data path. The controller contains


--    a state machine that defines the overall state of the game (waiting for a


--    move, end of the game, playing).


--    The controller also has a register that defines which bin is active at any


--    point in time during active playing.


--


--    The controller provides signals for the data path to decrement the hand


--    marble count, or load the hand with the selected work bin count, or indecate


--    that the game is over and a winner should be defined etc.


--


--    The data path contains a register for each bin in the game.


--    The number of bins is easily programmable by setting a integer constant.


--    The data path also contains counters to decrement the hand marble count


--    or increment the bin marble counts.


--


--    The data path provides signals for the controller to indicate that the


--    hand bin is empty, or which of the work bins is empty.


--  


--    The work bin registers are loaded with a equal number of marbles at the start


--    of the game. The total number of marbles in the game is programmable by setting


--    a generic in the top entity.


--


--    The data path also includes light drivers for the lights on each button that


--    indicate a valid move, and the lights that indicate which player is active.


--    Two extra signals are generated by the data path that let the home bin


--    display of the winner of the game blink on and off (at the end of the game).


--


--    The design does not include a merry-go-round display driver. This is done


--    outside this design, on the Aptix board.


--


--    The design does also not include a 18 bit clock devider that provides a


--    vary slow ticking clock to let humans follow the moves of the machine


--    cycle by cycle.


--


--  


library ieee ;


use ieee.std_logic_1164.all ;


package mancala_pack is


   type boolean_array is array (natural range <>) of boolean ;


   type player_t is (LEFT, RIGHT, BOTH, NEITHER) ;


   -- Define the number of bins in the game here.


   -- This include the two home bins


   constant nr_of_bins : natural := 10 ;


   -- Define the indexes of the two home bins


   constant OUTER_LEFT : natural := 0 ;


   constant OUTER_RIGHT : natural := nr_of_bins/2 ;



   -- Make a 'mask' constant that eliminates the home bins


   constant not_home_bins : boolean_array (nr_of_bins-1 downto 0) :=


       (OUTER_LEFT=>FALSE, OUTER_RIGHT=>FALSE, OTHERS=>TRUE) ;


   -- Component Declaration of the controller of the game


   component control


       generic (nr_of_bins : natural := 32) ;


       port (start_game : in boolean ;


           reset, clk : in std_logic ;


           buttons : in boolean_array (nr_of_bins-1 downto 0) ;


           empty_bins : in boolean_array (nr_of_bins-1 downto 0) ;


           hand_is_empty : in boolean ;


           active_bin : buffer boolean_array (nr_of_bins-1 downto 0) ;


           decrement_hand : out boolean ;


           load_hand_with_active_bin : out boolean ;


           the_player : out player_t ;


           end_of_the_game : out boolean ;


           waiting_for_move : out boolean


       ) ;


   end component ;


end mancala_pack ;


library ieee ;


use ieee.std_logic_1164.all ;


use work.mancala_pack.all ;


entity control is


   generic (nr_of_bins : natural := 10) ;


   port (start_game : in boolean ;


         reset, clk : in std_logic ;


         buttons : in boolean_array (nr_of_bins-1 downto 0) ;


         empty_bins : in boolean_array (nr_of_bins-1 downto 0) ;


         hand_is_empty : in boolean ;


         active_bin : buffer boolean_array (nr_of_bins-1 downto 0) ;


         decrement_hand : out boolean ;


         load_hand_with_active_bin : out boolean ;


         the_player : out player_t ;


         end_of_the_game : out boolean ;


         waiting_for_move : out boolean


   ) ;


end control ;


architecture exemplar of control is


   type state_t is (PLAY, WAIT_FOR_MOVE, END_OF_GAME);


   -- The state variables for the controller state machine


   signal present_state, next_state : state_t ;


   -- A separate register (one-hot) defines which bin is active


   signal present_active_bin : boolean_array(nr_of_bins-1 downto 0) ;


   signal player : player_t ;


   signal switch_player : boolean ;


   signal last_bin_was_empty, next_bin_is_empty : boolean ;


   -- Shift routine to shift to the next bin.


   function shift(sel : boolean_array) return boolean_array is


   begin


      -- shift this register to the right, roll over right bit to left


      return sel(sel'right) & sel(sel'left downto sel'right+1);


   end ;


   -- General routine to check if a boolean array contains all 'false' elements.


   function is_empty (bins : boolean_array) return boolean is


      constant empty : boolean_array (bins'range) := (others=>false) ;


   begin


      return (bins = empty) ;


   end ;


begin


   process (clk, reset)


   begin


       if (reset='1') then


           present_state <= END_OF_GAME ;


           last_bin_was_empty <= FALSE ;


           present_active_bin <= (others=>false) ;


       elsif (clk'event and clk='1') then


           present_state <= next_state ;


           last_bin_was_empty <= next_bin_is_empty ;


           present_active_bin <= active_bin ;


       end if ;


   end process ;


   process (start_game,present_state,hand_is_empty,empty_bins,buttons,


            present_active_bin, last_bin_was_empty, player)


       variable next_active_bin : boolean_array (present_active_bin'range) ;


   begin


       load_hand_with_active_bin <= FALSE ;


       decrement_hand <= FALSE ;


       switch_player <= FALSE ;


       waiting_for_move <= FALSE ;


       next_bin_is_empty <= FALSE ;


       end_of_the_game <= FALSE ;


       case present_state is


         when PLAY =>


           if (hand_is_empty) then


               -- No more marbles in the hand.


                if (is_empty (present_active_bin AND not_home_bins)) then


                  -- Stop if we drop the last marble in our own bin


                   next_state <= WAIT_FOR_MOVE ;


                   active_bin <= (others=>false) ;


 


               elsif (last_bin_was_empty) then


                  -- Stop and switch players if we drop the last marble


                  -- in an empty bin


                   switch_player <= TRUE ;


                   next_state <= WAIT_FOR_MOVE ;


                   active_bin <= (others=>false) ;


               else


                  -- Continue if last marble dropped in a non-empty bin.


                  -- Re-load hand with the full bin contents.


                   next_state <= PLAY ;


                   active_bin <= present_active_bin ;


                   load_hand_with_active_bin <= TRUE ;


               end if ;


           else


               -- Regular state to go to next bin during play


               next_state <= PLAY ;


               decrement_hand <= TRUE ;


               -- go to the next bin


               next_active_bin := shift(present_active_bin) ;



               -- We dont have to drop a marble in the opponents bin :


               -- shift one bin further if this is about to happen


               if ((player=LEFT and next_active_bin(OUTER_RIGHT)) OR


                   (player=RIGHT and next_active_bin(OUTER_LEFT))) then


                   next_active_bin := shift (next_active_bin) ;


               end if ;


               -- If the bin we go to is empty, flag that now, since


               -- we need to do something different in the next cycle.


               if (NOT is_empty (next_active_bin AND empty_bins)) then


                   next_bin_is_empty <= TRUE ;


               end if ;


               active_bin <= next_active_bin ;


           end if ;


         when WAIT_FOR_MOVE =>


           waiting_for_move <= TRUE ;


           if (is_empty((NOT empty_bins) AND not_home_bins)) then


               -- Here, there are no more marbles in any of the


               -- play bins. This is the end of the game.


               next_state <= END_OF_GAME ;


               active_bin <= (others=>FALSE) ;


           elsif (is_empty(buttons AND (NOT empty_bins) AND not_home_bins)) then


               -- Here, No button was pushed that is valid (not


               -- selecting a empty bin and not selecting a home bin.


               next_state <= WAIT_FOR_MOVE ;


               active_bin <= (others=>FALSE) ;


           else


              -- Somebody pushed a button. Load the hand with selected


              -- bin and restart the play


               next_state <= PLAY ;


               load_hand_with_active_bin <= TRUE ;


               active_bin <= buttons ; -- Should have only ONE bit set


           end if ;


         when END_OF_GAME =>


           -- Let the datapath calculate who the winner is


           end_of_the_game <= TRUE ;


           active_bin <= (others=>false) ;


           if (start_game) then


               next_state <= WAIT_FOR_MOVE ;


           else


               next_state <= END_OF_GAME ;


           end if ;


       end case ;


   end process ;


 --


 -- Process that controls which player is on.


 -- The state machine defines when players have to be switched


 --


   process (clk, reset)


       procedure switch_players (signal pl : inout player_t) is


       begin


           if (pl=LEFT) then


               pl <= RIGHT ;


           elsif (pl=RIGHT) then


               pl <= LEFT ;


           end if ;


       end ;


   begin


       if (reset='1') then


           player <= NEITHER ;


       elsif (clk'event and clk='1') then


           if (start_game) then


               player <= LEFT ;


           else


               if (switch_player) then


                   switch_players (player) ;


               end if ;


           end if ;


       end if ;


   end process ;


   the_player <= player ;


end exemplar ;



library ieee ;


use ieee.std_logic_1164.all ;


use work.mancala_pack.all ;


entity mancala is


   generic (max_marbles : natural := 32) ;


   port (start_game              : boolean ;


         active_bin_value        : buffer integer range 0 to max_marbles-1;


         active_bin              : buffer  boolean_array(nr_of_bins-1 downto 0);


         blink_right, blink_left : inout std_logic;


         clk, reset              : in   std_logic;


         buttons                 : in   boolean_array(nr_of_bins-1 downto 0);


         button_lights           : out  boolean_array(nr_of_bins-1 downto 0);


         l_player, r_player      : out  std_logic


   ) ;


end mancala ;


architecture exemplar of mancala is


   subtype bin_integer is integer range 0 to max_marbles-1 ;


   type bin_integer_array is array (nr_of_bins-1 downto 0) of bin_integer ;


   -- The bins


   signal bins : bin_integer_array ;


   signal incremented_bin_value : bin_integer ;


   signal empty_bins : boolean_array (nr_of_bins-1 downto 0) ;


   -- The hand


   signal hand : bin_integer ;


   signal load_hand_with_active_bin : boolean ;


   signal decrement_hand : boolean ;


   signal hand_is_empty : boolean ;


   -- Which player is playing / winning


   signal player : player_t ;


   signal winner : player_t ; 


   signal waiting_for_move : boolean ;


   signal end_of_the_game : boolean ;


begin


   c : control generic map ( nr_of_bins=>nr_of_bins)


               port map ( -- To controller :


                          start_game=>start_game,


                          clk=>clk,


                          reset=>reset,


                          buttons=>buttons,


                          empty_bins=>empty_bins,


                          hand_is_empty=>hand_is_empty,


 


                          -- From controller :


                          active_bin=>active_bin,


                          decrement_hand=>decrement_hand,


                          load_hand_with_active_bin=>load_hand_with_active_bin,


                          the_player=>player,


                          end_of_the_game=>end_of_the_game,


                          waiting_for_move=>waiting_for_move


                  ) ;


 --


 -- Process the amount of marbles in the hand


 --


   process (clk, reset)


   begin


      if (reset='1') then


          hand <= 0 ;


      elsif clk'event and clk='1' then


          if (start_game) then


              hand <= 0 ;


          elsif (load_hand_with_active_bin) then


              hand <= active_bin_value ;


          elsif (decrement_hand and (not hand_is_empty)) then


              hand <= hand - 1 ;


          end if ;


      end if ;


   end process ;


   hand_is_empty <= (hand=0) ;


 --


 -- Process the amount of marbles in each bin


 --


   bin_procs : for i in bins'range generate


       process (reset, clk)


       begin


           if (reset='1') then


               bins(i) <= 0 ;


           elsif clk'event and clk='1' then


               if (start_game) then


                   -- Initialize the home bins to zero and the


                   -- work bins to a number that guarantees that there


                   -- will be max_marbles in the game.


                   if (i=OUTER_LEFT or i=OUTER_RIGHT) then


                       bins(i) <= 0 ;


                   else


                       bins(i) <= max_marbles/(nr_of_bins-2) ;


                   end if ;


               elsif (active_bin(i)) then


                   if (load_hand_with_active_bin) then


                       bins(i) <= 0 ;


                   elsif (decrement_hand and (not hand_is_empty)) then


                       bins(i) <= incremented_bin_value ;


                   end if ;


               end if ;


           end if ;


       end process ;


       empty_bins(i) <= bins(i) = 0 ;


   end generate ;


 --


 -- Select the bin (from the bins register) that is presently active


 --


   process (active_bin, bins)


   begin


      active_bin_value <= 0 ;


      for i in bins'range loop


          if (active_bin(i)) then


              active_bin_value <= bins(i) ;


          end if ;


      end loop ;


   end process ;


 --


 -- Calculate the incremented value of the presently selected bin


 --


   incremented_bin_value <= active_bin_value + 1 ;



 -- Generate the light signals for the player that is active


   l_player <= '1' when player=LEFT else '0' ;


   r_player <= '1' when player=RIGHT else '0' ;



 --


 -- Define the winner


 --


   winner <= NEITHER when NOT end_of_the_game ELSE


             BOTH when bins(OUTER_LEFT)=bins(OUTER_RIGHT) ELSE


             LEFT when bins(OUTER_LEFT)>bins(OUTER_RIGHT) ELSE


             RIGHT ;


 --


 -- Blink the display of the winner (on/off)


 --


   process (clk, reset)


   begin


      if (reset='1') then


          -- Displays ON


          blink_left <= '1' ;


          blink_right <= '1' ;


      elsif clk'event and clk='1' then


          case winner is


             when LEFT =>


                blink_left <= NOT blink_left ;


                blink_right <= '1' ;


             when RIGHT =>


                blink_left <= '1' ;


                blink_right <= NOT blink_right ;


             when BOTH =>


                blink_left <= NOT blink_left ;


                blink_right <= NOT blink_right ;


             when OTHERS =>


                blink_left <= '1' ;


                blink_right <= '1' ;


          end case ;


      end if ;


   end process ;


 --


 -- Button lights


 -- Light on each button for possible move


 --


   lights : for i in button_lights'range generate


       button_lights(i) <= TRUE when (waiting_for_move AND NOT empty_bins(i))


                           else FALSE ;


   end generate ;


end exemplar ;


PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
2
关闭 站长推荐上一条 /3 下一条