Controller_SM.Vhd

------------------------------------------------------------------
--                             Controller_SM					--
-- File Name: Controller_SM.Vhd									--
-- Author: Kamesh Ramani.										--
-- Function : This is the state machine part of the controller  --
-- (The features are subject to change as the system evolves)	--
-- Created: 													--
-- Last Updated on: 2/11/03										--
------------------------------------------------------------------

-- IEEE Library
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;

ENTITY Controller_SM IS
--Generic parameters
generic (n: integer := 6);		-- Number of players
PORT(

	-- Global System Inputs
	Clk: IN	STD_LOGIC;		-- Global Clk
	Reset: IN	STD_LOGIC;	-- Global Reset
		
	-- Inputs from Control_SK module
	SK_PL: IN STD_LOGIC_VECTOR (n-1 downto 0);-- Bust for Players
	SK_Status: IN STD_LOGIC;	-- Status is ready
	SK_Game_Over: IN STD_LOGIC;	-- Current game over
	SK_Done: IN STD_LOGIC;		-- End of 100 games/player's chip gets over

	-- Outputs to the Card_Gen module
	CG_Start: OUT	STD_LOGIC;	-- Start Generating Cards in 
								-- Fixed sequence if 0
								-- Random Sequence if 1
		
	--Outputs to the House_Player module
	HP_Accept: out STD_LOGIC;		-- House Player Start

	-- Inputs from House_Player module
	HP_Hit: IN STD_LOGIC;			-- House Player Hit
	HP_Stand: IN STD_LOGIC;			-- House Player Stand

	--Outputs to the Player module
	PL_Accept: OUT STD_LOGIC_VECTOR (n-1 downto 0);	-- Start signals for n players
	
	-- Inputs from the Player modules
	PL_Hit: IN STD_LOGIC_VECTOR (n-1 downto 0);	-- Player Hit Singals for n players
	PL_Stand: IN STD_LOGIC_VECTOR (n-1 downto 0); -- Player Stand signals for n players
	PL_Status: IN STD_LOGIC_VECTOR (n-1 downto 0)	-- Player status - either in or out

	--Debug
	);
END Controller_SM;

architecture Control1er_SM_arch of Controller_SM is

signal Sequence:STD_LOGIC;-- Random or fixed sequence

--Signals related to Status_Mux
signal PL_Status_Mux: STD_LOGIC_VECTOR (n-1 downto 0);
signal Status_Select: STD_LOGIC;

--Signals related to Status_Reg
signal PL_Status_Reg: STD_LOGIC_VECTOR (n-1 downto 0);
signal Status_En: STD_LOGIC;

--Signals related to PL_Status_Mux
signal PL_Status_Sig : STD_LOGIC;

--Signals related to PL_Hit_Mux
signal PL_Hit_Sig : STD_LOGIC;

--Signals related to PL_Stand_Mux
signal PL_Stand_Sig : STD_LOGIC;

--Signals related to Counter Hands
-- Seven bits long since 100 in decimal needs 7 bits in Bin
signal Hands, Hands_Sig: STD_LOGIC_VECTOR(6 downto 0);
signal Hands_Inc, Hands_Clr: STD_LOGIC;

--Signals related to Counter_Cnt
-- Three bits long since n here is assumed 6
--n Dep
signal Cnt, Count: STD_LOGIC_VECTOR (3 downto 0);
signal Cnt_Inc, Cnt_Clr: STD_LOGIC;

--Signals related to Counter_Two
signal Two, Two_Cnt: STD_LOGIC_VECTOR(1 downto 0);
signal Two_Inc, Two_Clr: STD_LOGIC;

--Signals related to PL_Accept_Mux
-- Three bits long since n here is assumed 6
--n Dep
signal PL_Accept_Select: STD_LOGIC_VECTOR (3 downto 0);

-- Controller FSM states
type STATE_TYPE is (Idle, PL_card_init, HP_Card_Init, Black_Jack, PL_Play, HP_Play, Game_Over);
signal CurrentState, NextState: STATE_TYPE;

--Component declaration of Player_Mux
--n Dep
COMPONENT Player_Mux
PORT(
	PL_Value : OUT STD_LOGIC;
	PL_Vector: IN STD_LOGIC_VECTOR (5 downto 0);
	PL_Select: IN STD_LOGIC_VECTOR (3 downto 0)
	);
END COMPONENT;

begin

--Player_Mux chooses the Status of the current player
--Component instantiation of Player_Mux
PL_Stat_Mux: Player_Mux 
	PORT MAP (
		PL_Value => PL_Status_Sig,
		PL_Vector => PL_Status_Reg,
		PL_Select => Cnt
		);

--PL_Hit_Mux chooses the Hit signal of the current player
--Component instantiation of Player_Mux
PL_Hit_Mux: Player_Mux 
	PORT MAP (
		PL_Value => PL_Hit_Sig,
		PL_Vector => PL_Hit,
		PL_Select => Cnt
		);

--PL_Hit_Mux chooses the Stand signal of the current player
--Component instantiation of Player_Mux
PL_Stand_Mux: Player_Mux 
	PORT MAP (
		PL_Value => PL_Stand_Sig,
		PL_Vector => PL_Stand,
		PL_Select => Cnt
		);

-- Debug 

-- Controller FSM
State_machine: process(CurrentState, Hands, SK_Done, Cnt, PL_Status_Sig, Two_Cnt, SK_Status, Sequence, PL_Status_Sig, PL_Stand_Sig,
						PL_Hit_Sig)
begin

-- Default all outputs to FALSE
CG_Start <= '0';Status_EN <= '0';
Cnt_Inc <= '0'; Cnt_Clr <= '0';
Two_Inc <= '0'; Two_Clr <= '0';
Hands_Inc <= '0'; Hands_Clr <= '0';
HP_Accept <= '0'; Status_Select <= '0';

case CurrentState is

	when Idle =>
		-- End of game if either 100 hands played or chips get over
		if (Hands > X"64") then
			NextState <= Idle;
		elsif (Hands <= X"64") then
			if (SK_Done = '1')then
				Hands_Clr <= '1';
				NextState <= Idle;
			elsif (SK_Done = '0')then
				Status_Select <= '0';
				Status_En <= '1';
				Hands_Inc <= '1';
				NextState <= PL_Card_Init;
				-- Decide of what sequence to start
				if (Sequence = '0') then
					CG_Start <= '0';
				else
					CG_Start <= '1';
				end if;
			end if;
		end if;
	when PL_Card_Init =>
		if (Cnt <= X"6") then --n Dep
			-- if player is in
			if (PL_Status_Sig = '0') then
				PL_Accept_Select <= X"7";
			elsif (PL_Status_Sig = '1') then
					-- Give card to player
					PL_Accept_Select <= Cnt;
			end if;
			if (Cnt = X"6") then --n Dep
				Cnt_Clr <= '1';
				NextState <= HP_Card_Init;
			else
				Cnt_Inc <= '1';
				NextState <= PL_Card_Init;
			end if;
		elsif (Cnt > X"6") then --n Dep
			Cnt_Clr <= '1';
		end if;

	when HP_Card_Init =>
		PL_Accept_Select <= X"7";
		-- give cards to house
		HP_Accept <= '1';
		-- give two cards initially to both house and players
		if (Two_Cnt >= "01") then
			Two_clr <= '1';
			NextState <= Black_Jack;
		elsif (Two_Cnt < "01") then
			Two_Inc <= '1';
			NextState <= PL_Card_Init;
		end if;

	-- when black jack dont give cards to that player anymore
	when Black_Jack =>
		case (SK_Status) is
		when '1' =>
			Status_Select <= '1';
			Status_En <= '1';
			NextState <= PL_Play;
		when '0'=>
			NextState <= Black_Jack;
		when others =>
			NextState <= Idle;
		end case;
		
	when PL_Play =>
		if (Cnt <= X"6") then --n Dep
		-- if SK is not done with calculating status keep checking
			if (SK_Status = '0') then
				NextState <= PL_Play;
			--if the current player is out
			elsif (PL_Status_Sig = '0') then
				PL_Accept_Select <= X"7";
				if (Cnt = X"6") then --n Dep
					Cnt_Clr <= '1';
					NextState <= HP_Play;
				else
					Cnt_Inc <= '1';
					NextState <= PL_Play;
				end if;
			elsif (PL_Status_Sig = '1') then
					-- if the player is not ready keep checking
					if ((PL_Hit_Sig = '0') AND (PL_Stand_Sig = '0')) then
						NextState <= PL_Play;
					-- if the player hits then send him a card
					elsif (PL_Hit_Sig = '1') then
						PL_Accept_Select <= Cnt;
						NextState <= PL_Play;
					-- if the player stands, move on to the next player
					elsif (PL_Stand_Sig = '1') then	
						PL_Accept_Select <= X"7";
						if (Cnt = X"6") then --n Dep
							Cnt_Clr <= '1';
							NextState <= HP_Play;
						else
							Cnt_Inc <= '1';
							NextState <= PL_Play;
						end if;
					end if;
			end if;
		elsif (Cnt > X"6") then --n Dep
			Cnt_Clr <= '1';
			NextState <= Idle;
		end if;

	when HP_Play =>
		-- if the HP is not ready keep checking
		if ((HP_Hit = '0') AND (HP_Stand = '0')) then
			NextState <= HP_Play;
		-- if he hits give him another card
		elsif (HP_Hit = '1') then
			HP_Accept <= '1';
			NextState <= HP_Play;
		elsif (HP_Stand = '1') then
			HP_Accept <= '0';
			NextState <= Game_Over;
		end if;

	when Game_Over =>	
		-- if the SK says game over go to the next game
		if (SK_Game_Over = '1') then
			Sequence <= '1';
			NextState <= Idle;
		elsif (SK_Game_Over = '0') then
			NextState <= Game_Over;
		end if;

	when others =>
		NextState <= Idle;

end case;

end process;

-- To synchorinize the statemachine with Global Clk
State_Sync:process (Clk, Reset)
begin
    if (Reset='1') then
        CurrentState <= Idle;
    elsif (Clk'event and Clk = '1') then
        CurrentState <= NextState;
	end if;
end process;

-- Counter for Hands
Counter_Hands:process (Clk, Reset)
begin
    if (Reset='1') then
        Hands_Sig <= "0000000";
    elsif (Clk'event and Clk = '1') then
		if (Hands_Clr = '1') then
			Hands_Sig <= "0000000";
		elsif (Hands_Inc = '1') then
			Hands_Sig <= Hands_Sig + "0000001";
		end if;
    end if;
end process;
Hands <= Hands_Sig;


-- Counter for player's turn
Counter_Cnt:process (Clk, Reset)
begin
    if (Reset='1') then
        Count <= X"0";
    elsif (Clk'event and Clk = '1') then
		if (Cnt_Clr = '1') then
			Count <= X"0";
		elsif (Cnt_Inc = '1') then
			Count <= Count + X"1";
		end if;
    end if;
end process;
Cnt <= Count;

--Counter for giving cards twice initially
Counter_Two:process (Clk, Reset)
begin
   if (Reset='1') then
        Two <= "00";
    elsif (Clk'event and Clk = '1') then
		if (Two_Clr = '1') then
			Two <= "00";
		elsif (Two_Inc = '1') then
			Two <= Two + "01";
		end if;
   end if;
end process;
Two_Cnt <= Two;



-- Status Register
-- This register stores the status of the players
-- Initially the status is loaded when the palyers
-- say they are in or out
-- The status is changed again when the skore keeper
-- says they are bust or black jack.
Status_Reg: process (Clk, Reset, Status_En, PL_Status_Mux)
begin
	if (Reset='1') then
		PL_Status_Reg <= (others => '0');
	elsif (CLK'event and CLK='1') then
		if (Status_En = '1') then
			PL_Status_Reg <= PL_Status_Mux;
		elsif (Status_En = '0') then
			NULL;
		end if;
	end if;
end process;

--Status_Mux
--This mux selects between the status signals from
-- either the Player or the Score_Keeper.
Status_Mux: process (Status_Select, PL_Status, SK_PL)
begin
	case Status_Select is
	when '0' =>
		PL_Status_Mux <= PL_Status;	--Select status from player
	when '1' =>
		PL_Status_Mux <= SK_PL;		--Select status from SK
	when others =>
		PL_Status_Mux <= (others => '0'); -- Default value
	end case;
end process;

--PL_Accept_Mux
--This mux selects the given player's Accept signal
PL_Accept_Mux: process (PL_Accept_Select)
begin
	--n Dep
	case PL_Accept_Select is
	when X"1" =>
		PL_Accept <= "000001";
	when X"2" =>
		PL_Accept <= "000010";
	when X"3" =>
		PL_Accept <= "000100";
	when X"4" =>
		PL_Accept <= "001000";
	when X"5" =>
		PL_Accept <= "010000";
	when X"6" =>
		PL_Accept <= "100000";		
	when others =>
		PL_Accept <= (others => '0'); -- Default value
	end case;
end process;
end Control1er_SM_arch;