一个游戏程序.vhd
上传用户:easylife05
上传日期:2013-03-21
资源大小:42k
文件大小:19k
- --
- -- 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 ;
-