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;