VHDL设计举例:一个游戏程序
2012-10-17
标签:

--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 LEFThome bin right

--*O*O*O*O

--________

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

----------

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

--

--work bins

--

--__

--| | | |

----OStart 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: bufferboolean_array(nr_of_bins-1 downto 0);

blink_right, blink_left : inout std_logic;

clk, reset: instd_logic;

buttons: inboolean_array(nr_of_bins-1 downto 0);

button_lights: outboolean_array(nr_of_bins-1 downto 0);

l_player, r_player: outstd_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 ;

可能会用到的工具/仪表
相关文章
推荐文章
热门文章
章节目录
本站简介 | 意见建议 | 免责声明 | 版权声明 | 联系我们
CopyRight@2024-2039 嵌入式资源网
蜀ICP备2021025729号