Search code examples
vhdlfpgatic-tac-toe

VHDL code for Tic tac toe game?


I have 18 output and 9 push switches to work with and one led as output which changing its states each time the push button is pressed to automate the chance of two players. my code is not working, pls help my code is...expected behavour is that when momentarily in1 switch is high then play_to_play should toggle on each event of the inputs and according to play_to_play status and in1 high either ou11 or ou21 should go high i.e one player has played his chance and automatically at the next event it takes that it is player 2 chance

library IEEE;   
use IEEE.STD_LOGIC_1164.ALL;  
entity TicTac is     
    Port ( in1 : in  STD_LOGIC;  
           in2 : in  STD_LOGIC;  
           in3 : in  STD_LOGIC;   
           in4 : in  STD_LOGIC;  
           in5 : in  STD_LOGIC;  
           in6 : in  STD_LOGIC;  
           in7 : in  STD_LOGIC;   
           in8 : in  STD_LOGIC;   
           in9 : in  STD_LOGIC;   
              reset : in  STD_LOGIC;  
            p_to_play : out STD_Logic;   
           p1_win : out  STD_LOGIC;   
           p2_win : out  STD_LOGIC;   
           ou11 : out  STD_LOGIC;   
           ou12 : out  STD_LOGIC;   
           ou13 : out  STD_LOGIC;   
           ou14 : out  STD_LOGIC;   
           ou15 : out  STD_LOGIC;   
           ou16 : out  STD_LOGIC;   
           ou17 : out  STD_LOGIC;   
           ou18 : out  STD_LOGIC;   
           ou19 : out  STD_LOGIC;   
           ou21 : out  STD_LOGIC;   
           ou22 : out  STD_LOGIC;   
           ou23 : out  STD_LOGIC;   
           ou24 : out  STD_LOGIC;   
           ou25 : out  STD_LOGIC;  
           ou26 : out  STD_LOGIC;  
           ou27 : out  STD_LOGIC;   
           ou28 : out  STD_LOGIC;   
           ou29 : out  STD_LOGIC);   
end TicTac;   
architecture Behavioral of TicTac is   
Signal temp1, temp2, temp3, temp4, temp5, temp6,temp7, temp8, temp9,p1_play :std_logic :='0';    
signal o11,o12,o13,o14,o15,o16,o17,o18,o19,o21,o22,o23,o24,o25,o26,o27,o28,o29 :std_logic :='0';    
signal p1win,p2win :std_logic :='0';    
begin   
process(in1,in2,in3,in4,in5,in6,in7,in8,in9,reset)
begin  

   if ((in1'event or in2'event or in3'event or in4'event or in5'event or in6'event or in7'event or in8'event or in9'event) and
    (in1='1' or in2 ='1' or in3='1' or in4='1' or in5='1' or in6='1' or in7='1' or in8='1' or in9='1')) then     
      p1_play <= not(p1_play);    
if(reset'event and reset= '1') then  
temp1 <='0';    
temp2 <='0';   
temp3 <='0';   
temp4 <='0';   
temp5 <='0';   
temp6 <='0';   
temp7 <='0';   
temp8 <='0';  
temp9 <='0';   
p1_play <= '0';  
p1win <='0';    
p2win <='0';    
o11 <='0';    
o12 <='0';   
o13 <='0';   
o14 <='0';   
o15 <='0';   
o16 <='0';   
o17 <='0';   
o18 <='0';   
o19 <='0';   
o21 <='0';   
o22 <='0';   
o23 <='0';   
o24 <='0';   
o25 <='0';   
o26 <='0';   
o27 <='0';   
o28 <='0';   
o29 <='0';   
end if;     
if(in1= '1') then   
temp1 <='1';   
end if;  
if(in2= '1') then   
temp2 <='1';   
end if;   
if(in3= '1') then
temp3 <='1';
end if;
if(in4= '1') then
temp1 <='1';
end if;
if(in5= '1') then
temp5 <='1';
end if;
if(in6= '1') then
temp6 <='1';
end if;
if(in7= '1') then
temp7 <='1';
end if;
if(in8= '1') then
temp8 <='1';
end if;
if(in9= '1') then
temp9 <='1';  
end if;    
if(p1_play='0' and temp1='1') then    
o11 <= '1';    
end if;    
if(p1_play='0' and temp2='1') then   
o12 <= '1';    
end if;    
if(p1_play='0' and temp3='1') then
o13 <= '1';    
end if;   
if(p1_play='0' and temp4='1') then
o14 <= '1';   
end if;    
if(p1_play='0' and temp5='1') then
o15 <= '1';    
end if;    
if(p1_play='0' and temp6='1') then
o16 <= '1';    
end if;    
if(p1_play='0' and temp7='1') then
o17 <= '1';   
end if;    
if(p1_play='0' and temp8='1') then
o18 <= '1';    
end if;    
if(p1_play='0' and temp9='1') then
o19 <= '1';    
end if;     
if(p1_play='1' and temp1='1') then
o21 <= '1';    
end if;   
if(p1_play='1' and temp2='1') then
o22 <= '1';    
end if;    
if(p1_play='1' and temp3='1') then
o23 <= '1';    
end if;    
if(p1_play='1' and temp4='1') then
o24 <= '1';    
end if;    
if(p1_play='1' and temp5='1') then
o25 <= '1';    
end if;    
if(p1_play='1' and temp6='1') then
o26 <= '1';    
end if;    
if(p1_play='1' and temp7='1') then
o27 <= '1';    
end if;    
if(p1_play='1' and temp8='1') then
o28 <= '1';    
end if;    
if(p1_play='1' and temp9='1') then
o29 <= '1';    
end if;    
if((o11='1' and o12='1' and o13='1') or (o14='1' and o15='1' and o16='1') or (o17='1' and o18='1' and o19='1')
or (o11='1' and o14='1' and o17='1') or (o12='1' and o15='1' and o18='1') or (o13='1' and o16='1' and o19='1')
or (o11='1' and o15='1' and o19='1') or (o13='1' and o15='1' and o17='1')) then
p1win <='1';    
end if;     
if((o21='1' and o22='1' and o23='1') or (o24='1' and o25='1' and o26='1') or (o27='1' and o28='1' and o29='1')
or (o21='1' and o24='1' and o27='1') or (o22='1' and o25='1' and o28='1') or (o23='1' and o26='1' and o29='1')
or (o21='1' and o25='1' and o29='1') or (o23='1' and o25='1' and o27='1')) then
p2win <='1';     
end if;   
end if;   
end process;   
ou11 <= o11;   
ou12 <= o12;   
ou13 <= o13;   
ou14 <= o14;   
ou15 <= o15;   
ou16 <= o16;   
ou17 <= o17;   

    ou18 <= o18;   
    ou19 <= o19;   
    ou21 <= o21;  
    ou22 <= o22;   
    ou23 <= o23;   
    ou24 <= o24;  
    ou25 <= o25;   
    ou26 <= o26;   
    ou27 <= o27;   
    ou28 <= o28;   
    ou29 <= o29;   
    p_to_play <= p1_play;   
    p1_win <= p1win;   
    p2_win <= p2win;   
    end Behavior

al;      

Solution

  • Processes in VHDL are not the same as processes on a regular programming language. All signal assignments within a process actually occur at the time the process completes (actually a delta time later, which is basically a 0 time difference). Since you are trying to use the value of temp that you just assigned earlier in the process, but it hasn't actually been written yet, you are not triggering your if statement until the next time the process runs.

    As an aside, I didn't notice any mechanism to prevent players from playing in spaces that they or their opponent already played.

    EDIT: Also, what do you plan to do with this? If you want to put it on a real FPGA with real switches it likely won't work because of an electromechanical phenomenon called switch bouncing that makes each press of a switch seem like many to the hardware.

    EDIT2: To fix this (still won't fix switch bouncing) you may want to scrap temp entirely (replacing it with the "in" signals) and put the entire contents of the process, except the reset stuff, inside your if statement that detects rising edges on the in signals.

    EDIT3: Here is a VHDL model for a 4x4 tic-tac-toe board with your hardware setup expanded to the 16 squares of a 4x4 board. See if you can understand what is done and why, then adapt it to a 3x3 board.

    library IEEE;   
    use IEEE.STD_LOGIC_1164.ALL;  
    entity TicTac is   
        Port (button : in  std_logic_vector(16 downto 1);  
              reset : in  std_logic;  
              p_to_play : out std_logic;   
              p1_win : out  std_logic := '0';   
              p2_win : out  std_logic := '0';   
              ou1 : out std_logic_vector(16 downto 1);    
              ou2 : out std_logic_vector(16 downto 1));   
    end TicTac;   
    architecture Behavioral of TicTac is    
    
        signal o1 : std_logic_vector(16 downto 1) := (others => '0');    
        signal o2 : std_logic_vector(16 downto 1) := (others => '0'); 
        signal o  : std_logic_vector(16 downto 1) := (others => '0');
        signal p  : std_logic;
        signal win  : std_logic;
        signal win1 : std_logic;
        signal win2 : std_logic; 
    
    begin   
        ou1 <= o1;
        ou2 <= o2;
        p_to_play <= p;
        p1_win <= win1;
        p2_win <= win2;
        win <= win1 or win2;
    
        gen_spots : for i in 1 to 16 generate --3 flip flops share a clock (button) for every space on the board
            process(button(i), reset)
            begin
                if(reset = '1') then
                    o(i)  <= '0';
                    o1(i) <= '0';
                    o2(i) <= '0';
                elsif(button(i)'event and button(i)='1' and o(i)='0' and win='0') then
                    o(i) <= '1';
                    if (p = '0') then
                        o1(i) <= '1';
                    else
                        o2(i) <= '1';
                    end if;
                end if;
            end process;
        end generate gen_spots;
    
        process(o) --determines current player by xoring the o values together.
            variable ot : std_logic;
        begin
            ot := '0';
            for i in 1 to 16 loop
                ot := ot xor o(i);
            end loop;
            p <= ot;
        end process;
    
        process(o1) --checks if player 1 wins
        begin
            win1 <= '0'; --only happens if none of the win1 <= '1' statements occur
            for i in 0 to 3 loop
                if (o1(1+i*4)='1' and o1(2+i*4)='1' and o1(3+i*4)='1' and o1(4+i*4)='1') then --rows
                    win1 <= '1';
                end if;
                if (o1(1+i)='1' and o1(5+i)='1' and o1(9+i)='1' and o1(13+i)='1') then --columns
                    win1 <= '1';
                end if;
            end loop;
            if (o1(1)='1' and o1(6)='1' and o1(11)='1' and o1(16)='1') or (o1(4)='1' and o1(7)='1' and o1(10)='1' and o1(13)='1') then --diagonals
                win1 <= '1';
            end if;
        end process;
    
        process(o2) --checks if player 2 wins
        begin
            win2 <= '0'; --only happens if none of the win2 <= '1' statements occur
            for i in 0 to 3 loop
                if (o2(1+i*4)='1' and o2(2+i*4)='1' and o2(3+i*4)='1' and o2(4+i*4)='1') then --rows
                    win2 <= '1';
                end if;
                if (o2(1+i)='1' and o2(5+i)='1' and o2(9+i)='1' and o2(13+i)='1') then --columns
                    win2 <= '1';
                end if;
            end loop;
            if (o2(1)='1' and o2(6)='1' and o2(11)='1' and o2(16)='1') or (o2(4)='1' and o2(7)='1' and o2(10)='1' and o2(13)='1') then --diagonals
                win2 <= '1';
            end if;
        end process;
    
    end Behavioral; 
    

    I haven't done exhaustive tests, but this compiles and works for a couple test cases.

    Please remember to mark this as the correct answer if it solved your problem.