library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity game is
port (
clk : in std_logic;
rst : in std_logic;
run : in std_logic;
psData : in std_logic;
psClock : in std_logic;
Red : out std_logic;
Green : out std_logic;
Blue : out std_logic;
vs : out std_logic;
hs : out std_logic;
LED : out std_logic_vector(7 downto 0)
);
end game;
architecture Behavioral of game is
component raminfr is
port (
clk : in std_logic;
we : in std_logic;
addr : in integer range 0 to 199;
saddr : in integer range 0 to 199;
di : in std_logic_vector(2 downto 0);
sdo : out std_logic_vector(2 downto 0)
);
end component;
component keyboardVhdl is
Port (
CLK, RST, KD, KC: in std_logic;
keyboard : out std_logic_vector(2 downto 0)
);
end component;
component vga_controller is
Port ( clk : in std_logic;
reset : in std_logic;
hs : out std_logic;
vs : out std_logic;
blank : out std_logic;
hpix : out std_logic_vector(9 downto 0);
vpix : out std_logic_vector(9 downto 0)
);
end component;
component board is
Port ( Clk : in std_logic;
Blank : in std_logic;
DrawH : in std_logic_vector(9 downto 0);
DrawV : in std_logic_vector(9 downto 0);
address : out integer range 0 to 199;
do : in std_logic_vector(2 downto 0);
Red : out std_logic;
Blue : out std_logic;
Green : out std_logic;
currentPiece0 : in integer range 0 to 199;
currentPiece1 : in integer range 0 to 199;
currentPiece2 : in integer range 0 to 199;
currentPiece3 : in integer range 0 to 199;
currentColor : in std_logic_vector(2 downto 0)
);
end component;
--Keycodes
constant key_nothing : std_logic_vector(2 downto 0) := "000";
constant key_left : std_logic_vector(2 downto 0) := "001";
constant key_right : std_logic_vector(2 downto 0) := "010";
constant key_down : std_logic_vector(2 downto 0) := "011";
--Not implemented, but maybe it will become so.
--constant key_drop : std_logic_vector(2 downto 0) := "100";
type state_of_anarchy is (reset, adding_new_piece,
waiting, GAME_OVER, move_left_or_right,
turn_action, --Like.. move the block down and see if it hit anything
action_done, --Reset counters and go back to waiting state
plant_0, plant_1, plant_2, plant_3, --Plant the four pieces in PieceLoactions into memory
line_break, -- Check if they completed any lines and, if so, remove them.
start_state -- Before "run" is pressed :)
);
signal State, Next_State : state_of_anarchy;
signal resetting : bit;
subtype row is integer range 0 to 19;
subtype boardSize is integer range 0 to 199;
type boardArray is array (natural range <>) of bit;
type boardLocation is array (natural range <>) of boardSize;
type rowArray is array (natural range <>) of row;
signal boardState : boardArray(boardSize);
signal pieceLocations : boardLocation(0 to 3) := (0,0,0,0);
signal next_pieceLocations : boardLocation(0 to 3) := (0,0,0,0);
subtype numPieces is integer range 0 to 27;
subtype pieceRelative is integer range -30 to 30;
subtype color is std_logic_vector(2 downto 0);
type colorArray is array (natural range<>) of color;
type piece is array (0 to 3) of pieceRelative;
type piecesArray is array (natural range <>) of piece;
signal boardStateAddr : integer range 0 to 200; -- 200 = special
signal boardStateInput : bit;
signal currentColor : color;
constant getRow : rowArray (boardSize) := (
0,0,0,0,0,0,0,0,0,0,
1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,
8,8,8,8,8,8,8,8,8,8,
9,9,9,9,9,9,9,9,9,9,
10,10,10,10,10,10,10,10,10,10,
11,11,11,11,11,11,11,11,11,11,
12,12,12,12,12,12,12,12,12,12,
13,13,13,13,13,13,13,13,13,13,
14,14,14,14,14,14,14,14,14,14,
15,15,15,15,15,15,15,15,15,15,
16,16,16,16,16,16,16,16,16,16,
17,17,17,17,17,17,17,17,17,17,
18,18,18,18,18,18,18,18,18,18,
19,19,19,19,19,19,19,19,19,19
);
constant pieces : piecesArray (numPieces) := (
(0,-1,1,10), -- Hat
(0,-2, -1, 1), -- pipe
(0, -1, 1, 11), -- "L"
(0, 1, 10, 11), -- Cube
(0, 9, -1, 1), -- Reverse "L"
(0, 10, 1, -9), -- Zig
(0, 10, -1, -11), -- Zag
(0,-1,1,10), -- Hat
(0,-2, -1, 1), -- pipe
(0, -1, 1, 11), -- "L"
(0, 1, 10, 11), -- Cube
(0, 9, -1, 1), -- Reverse "L"
(0, 10, 1, -9), -- Zig
(0, 10, -1, -11), -- Zag
(0,-1,1,10), -- Hat
(0,-2, -1, 1), -- pipe
(0, -1, 1, 11), -- "L"
(0, 1, 10, 11), -- Cube
(0, 9, -1, 1), -- Reverse "L"
(0, 10, 1, -9), -- Zig
(0, 10, -1, -11), -- Zag
(0,-1,1,10), -- Hat
(0,-2, -1, 1), -- pipe
(0, -1, 1, 11), -- "L"
(0, 1, 10, 11), -- Cube
(0, 9, -1, 1), -- Reverse "L"
(0, 10, 1, -9), -- Zig
(0, 10, -1, -11) -- Zag
);
constant pieceColors : colorArray (numPieces) := (
('1','0','0'),
('0','1','0'),
('0','0','1'),
('1','1','0'),
('0','1','1'),
('1','0','1'),
('0','0','0'),
('1','0','0'),
('0','1','0'),
('0','0','1'),
('1','1','0'),
('0','1','1'),
('1','0','1'),
('0','0','0'),
('1','0','0'),
('0','1','0'),
('0','0','1'),
('1','1','0'),
('0','1','1'),
('1','0','1'),
('0','0','0'),
('1','0','0'),
('0','1','0'),
('0','0','1'),
('1','1','0'),
('0','1','1'),
('1','0','1'),
('0','0','0')
);
signal nextPiece : numPieces;
signal currentPiece : numPieces;
signal nextCurrentPiece : numPieces;
signal sigAddr : boardSize;
signal cur_sigAddr : boardSize;
signal sigAddr2 : boardSize;
signal sigDi : std_logic_vector(2 downto 0);
signal sigSdo : std_logic_vector(2 downto 0);
signal sigWe : std_logic;
signal sigKeyboard, lastSigKeyboard : std_logic_vector(2 downto 0);
signal sigPsData : std_logic;
signal sigPsClk : std_logic;
signal sigHs : std_logic;
signal sigVs : std_logic;
signal sigBlank : std_logic;
signal sigHpix : std_logic_vector(9 downto 0);
signal sigVpix : std_logic_vector(9 downto 0);
signal sigRed : std_logic;
signal sigGreen : std_logic;
signal sigBlue : std_logic;
signal clockCounter : std_logic_vector(24 downto 0);
constant clock_zero : std_logic_vector(24 downto 0) := "0000000000000000000000000";
begin
bram_unit : raminfr
Port Map (
clk => clk,
we => sigWe,
addr => sigAddr,
saddr => sigAddr2,
di => sigDi,
sdo => sigSdo
);
keyboard_input : keyboardVhdl
Port Map (
CLK => clk,
RST => Rst,
KD => sigPsData,
KC => sigPsClk,
keyboard => sigKeyboard
);
vga_controller_instance : vga_controller
Port Map (
Clk => clk,
reset => Rst,
hs => sigHs,
vs => sigVs,
blank => sigBlank,
hpix => sigHpix,
vpix => sigVpix
);
board_mapper : board
Port Map(
Clk => Clk,
Blank => sigBlank,
DrawH => sigHpix,
DrawV => sigVpix,
address => sigAddr2,
do => sigSdo,
Red => sigRed,
Blue => sigBlue,
Green => sigGreen,
currentPiece0 => pieceLocations(0),
currentPiece1 => pieceLocations(1),
currentPiece2 => pieceLocations(2),
currentPiece3 => pieceLocations(3),
currentColor => currentColor
);
currentColor <= pieceColors(currentPiece);
sigPsData <= psData;
sigPsClk <= psClock;
Red <= sigRed;
Blue <= sigBlue;
Green <= sigGreen;
hs <= sigHs;
vs <= sigVs;
set_leds_here : process (State)
begin
case State is
when reset =>
LED <= "10000001";
when start_state =>
LED <= "01000000";
when waiting =>
LED <= "00100000";
when GAME_OVER =>
LED <= "01010101";
when others =>
LED <= "11111111";
end case;
end process;
assign_state : process (Clk, Rst)
begin
if (Rst = '1') then
State <= reset;
elsif (clk'Event and clk = '1') then
if (State = reset) then
resetting <= '1';
else
resetting <= '0';
end if;
State <= Next_State;
end if;
end process;
asssign_next_piece_Locations : process (Clk)
begin
if (Clk'Event and clk = '1') then
pieceLocations <= next_pieceLocations;
end if;
end process;
random_number_imaginer_and_clock : process (Clk, State, resetting)
begin
if (State = reset) then
if (resetting = '0') then
clockCounter <= clock_zero;
else
clockCounter <= clockCounter + 1;
end if;
nextPiece <= 0;
elsif (State = action_done) then
clockCounter <= clock_zero;
nextPiece <= nextPiece;
elsif (clk'event and clk = '1') then
clockCounter <= clockCounter + 1;
if (nextPiece = 27) then
nextPiece <= 0;
else
nextPiece <= nextPiece + 1;
end if;
end if;
end process;
maintain_sigaddr_blah : process (Clk)
begin
if (clk'event and clk = '1') then
cur_sigAddr <= sigAddr;
end if;
end process;
the_crazyness : process (Clk, boardStateAddr, boardStateInput)
begin
if (Clk'event and clk = '1') then
for i in 0 to 199 loop
if (i = boardStateAddr) then
boardState(i) <= boardStateInput;
else
boardState(i) <= boardState(i);
end if;
end loop;
end if;
end process;
setnextCurrentPiece : process (Clk, State)
begin
if (state = reset) then
currentPiece <= 0;
elsif (Clk'event and clk = '1') then
currentPiece <= nextCurrentPiece;
end if;
end process;
fabsdfhasdfuhasd : process (Clk, SigKeyboard)
begin
if (clk'event and clk='1') then
lastSigKeyboard <= sigKeyboard;
--sigMyKeyCount <= nextsigMyKeyCount;
end if;
end process;
do_awesome_stuff : process (Clk, sigKeyboard, Rst, Run, currentPiece, pieceLocations, State, resetting, cur_sigAddr, nextPiece, clockCounter, lastSigKeyboard)
variable Shift : pieceRelative;
variable can_insert : bit;
begin
sigDi <= "000";
sigWe <= '0';
sigAddr <= 0;
Shift := 0;
can_insert := '0';
boardStateAddr <= 200;
boardStateInput <= '0';
nextCurrentPiece <= currentPiece;
next_pieceLocations <= pieceLocations;
--nextsigMyKeyCount <= sigMyKeyCount;
case State is
when reset=>
if (resetting = '0') then --Just started resetting then
sigAddr <= 0;
else
sigAddr <= cur_sigAddr + 1;
end if;
sigDi <= "111";
--nextsigMyKeyCount <= sigKeyCount;
--sigDi <= clockCounter(2 downto 0);
sigWe <= '1';
boardStateAddr <= cur_sigAddr;
boardStateInput <= '0';
next_pieceLocations(0) <= 0;
next_pieceLocations(1) <= 0;
next_pieceLocations(2) <= 0;
next_pieceLocations(3) <= 0;
if (cur_sigAddr = 198) then
Next_State <= start_state;
else
Next_State <= reset;
end if;
when start_state =>
--Clock Counter is COUNTING :D
if (run = '1') then
Next_State <= adding_new_piece;
else
Next_State <= start_state;
end if;
when adding_new_piece =>
Shift := 4; --Insert at middle of top row
-- Step One: Determine if new piece will *fit* on the board.
-- Remember to update this if any pieces are stored that go
-- more than one row up from the insertion point
if (pieces(nextPiece)(0) < -5) then
Shift := Shift + 10;
elsif (pieces(nextPiece)(1) < -5) then
Shift := Shift + 10;
elsif (pieces(nextPiece)(2) < -5) then
Shift := Shift + 10;
elsif (pieces(nextPiece)(3) < -5) then
Shift := Shift + 10;
end if;
-- Step TWO: Check if we CAN insert that piece without conflict.
can_insert := '1';
if (boardState(pieces(nextPiece)(0) + Shift) = '1') then
can_insert := '0';
elsif (boardState(pieces(nextPiece)(1) + Shift) = '1') then
can_insert := '0';
elsif (boardState(pieces(nextPiece)(2) + Shift) = '1') then
can_insert := '0';
elsif (boardState(pieces(nextPiece)(3) + Shift) = '1') then
can_insert := '0';
end if;
--Step THREE-A: SET THE NEW PIECE!
if (can_insert = '1') then
next_pieceLocations(0) <= pieces(nextPiece)(0) + Shift;
next_pieceLocations(1) <= pieces(nextPiece)(1) + Shift;
next_pieceLocations(2) <= pieces(nextPiece)(2) + Shift;
next_pieceLocations(3) <= pieces(nextPiece)(3) + Shift;
Next_State <= waiting;
nextcurrentPiece <= nextPiece;
--Step THREE-B: BOOO GAME OVER MUAHAHAHAHAHA
else
Next_State <= GAME_OVER;
end if;
when waiting =>
if (clockCounter > "1000000000000000000000" and sigKeyboard /= key_nothing) then
--nextsigMyKeyCount <= sigKeyCount;
--We've waited long enough to allow the player to move or something
if (sigKeyboard = key_left or sigKeyboard = key_right) then
Next_State <= move_left_or_right;
--elsif (sigKeyboard = key_down) then
else --Same as above since no key_drop
Next_State <= turn_action;
end if;
elsif (clockCounter > "100000000000000000000000") then
--Turn's up!
Next_State <= turn_action;
else
Next_State <= waiting;
end if;
when move_left_or_right =>
if (LastSigKeyboard = key_left) then
Shift := -1;
else
Shift := 1;
end if;
--Step One: Check if we can move without hitting a block.
can_insert := '1';
if (boardState(pieceLocations(0) + Shift) = '1') then
can_insert := '0';
elsif (boardState(pieceLocations(1) + Shift) = '1') then
can_insert := '0';
elsif (boardState(pieceLocations(2) + Shift) = '1') then
can_insert := '0';
elsif (boardState(pieceLocations(3) + Shift) = '1') then
can_insert := '0';
--Step Two - Check if doing that would cause us to wrap between rows.
elsif (shift = 1 and pieceLocations(0) = 199) then
can_insert := '0';
elsif (shift = 1 and pieceLocations(1) = 199) then
can_insert := '0';
elsif (shift = 1 and pieceLocations(2) = 199) then
can_insert := '0';
elsif (shift = 1 and pieceLocations(3) = 199) then
can_insert := '0';
elsif (getRow(pieceLocations(0)) /= getRow(pieceLocations(0) + Shift)) then
can_insert := '0';
elsif (getRow(pieceLocations(1)) /= getRow(pieceLocations(1) + Shift)) then
can_insert := '0';
elsif (getRow(pieceLocations(2)) /= getRow(pieceLocations(2) + Shift)) then
can_insert := '0';
elsif (getRow(pieceLocations(3)) /= getRow(pieceLocations(3) + Shift)) then
can_insert := '0';
end if;
--Step Three-A: We cannot! Screw that, we're going back to waiting.
if (can_insert = '0') then
Next_State <= waiting;
else
--Step Three-B: We Can! Move it!
next_pieceLocations(0) <= PieceLocations(0) + Shift;
next_pieceLocations(1) <= PieceLocations(1) + Shift;
next_pieceLocations(2) <= PieceLocations(2) + Shift;
next_pieceLocations(3) <= PieceLocations(3) + Shift;
Next_State <= action_done;
end if;
when action_done =>
--Clock resets here.
Next_State <= waiting;
when turn_action =>
can_insert := '1';
Shift := 10;
--Step One: Check if we're at the bottom of the board
--Seperate from checking room so we never add shift and go out of bounds
if (pieceLocations(0) > 189) then
can_insert := '0';
elsif (pieceLocations(1) > 189) then
can_insert := '0';
elsif (pieceLocations(2) > 189) then
can_insert := '0';
elsif (pieceLocations(3) > 189) then
can_insert := '0';
--Step Two: Check if there is room to move the piece down
elsif (boardState(pieceLocations(0) + Shift) = '1') then
can_insert := '0';
elsif (boardState(pieceLocations(1) + Shift) = '1') then
can_insert := '0';
elsif (boardState(pieceLocations(2) + Shift) = '1') then
can_insert := '0';
elsif (boardState(pieceLocations(3) + Shift) = '1') then
can_insert := '0';
end if;
--Step Three-A: We cannot move, plant and new piece
if (can_insert = '0') then
Next_State <= plant_0;
--Step Three-B: Move.
else
next_pieceLocations(0) <= PieceLocations(0) + Shift;
next_pieceLocations(1) <= PieceLocations(1) + Shift;
next_pieceLocations(2) <= PieceLocations(2) + Shift;
next_pieceLocations(3) <= PieceLocations(3) + Shift;
Next_State <= action_done;
end if;
when plant_0 =>
boardStateInput <= '1';
boardStateAddr <= pieceLocations(0);
sigAddr <= PieceLocations(0);
sigDi <= pieceColors(currentPiece);
sigWe <= '1';
Next_State <= plant_1;
when plant_1 =>
boardStateInput <= '1';
boardStateAddr <= pieceLocations(1);
sigAddr <= PieceLocations(1);
sigDi <= pieceColors(currentPiece);
sigWe <= '1';
Next_State <= plant_2;
when plant_2 =>
boardStateInput <= '1';
boardStateAddr <= pieceLocations(2);
sigAddr <= PieceLocations(2);
sigDi <= pieceColors(currentPiece);
sigWe <= '1';
Next_State <= plant_3;
when plant_3 =>
boardStateInput <= '1';
boardStateAddr <= pieceLocations(3);
sigAddr <= PieceLocations(3);
sigDi <= pieceColors(currentPiece);
sigWe <= '1';
Next_State <= line_break;
when line_break =>
next_state <= adding_new_piece;
--adding_new_piece;
when GAME_OVER =>
next_state <= GAME_OVER;
when others =>
next_state <= GAME_OVER;
end case;
end process;
end Behavioral;