library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity traffic_light_controller is
    Port ( 
        clk       : in  STD_LOGIC;     -- 系统时钟
        reset     : in  STD_LOGIC;     -- 系统复位
        manual    : in  STD_LOGIC;     -- 手动控制信号
        a_light   : out STD_LOGIC_VECTOR(2 downto 0);  -- A方向灯: 红|黄|绿
        b_light   : out STD_LOGIC_VECTOR(2 downto 0);  -- B方向灯: 红|黄|绿  
        countdown : out INTEGER range 0 to 45          -- 倒计时显示
    );
end traffic_light_controller;

architecture Behavioral of traffic_light_controller is
    -- 定义交通灯状态
    type state_type is (
        A_GREEN_B_RED,    -- A绿B红
        A_YELLOW_B_RED,   -- A黄B红
        A_RED_B_GREEN,    -- A红B绿
        A_RED_B_YELLOW    -- A红B黄
    );
    
    signal current_state : state_type;
    signal counter : INTEGER range 0 to 45;
    signal sec_counter : INTEGER range 0 to 50000000;
    constant CLK_FREQ : INTEGER := 50000000;  -- 假设50MHz时钟
    
begin
    -- 时钟分频进程：生成1秒时钟
    process(clk, reset)
    begin
        if reset = '1' then
            sec_counter <= 0;
        elsif rising_edge(clk) then
            if manual = '0' then  -- 正常模式
                if sec_counter = CLK_FREQ - 1 then
                    sec_counter <= 0;
                else
                    sec_counter <= sec_counter + 1;
                end if;
            else  -- 手动模式，停止计时
                sec_counter <= sec_counter;
            end if;
        end if;
    end process;

    -- 主控制进程
    process(clk, reset)
    begin
        if reset = '1' then
            current_state <= A_GREEN_B_RED;
            counter <= 40;
            a_light <= "001";  -- A绿
            b_light <= "100";  -- B红
            countdown <= 40;
            
        elsif rising_edge(clk) then
            if manual = '1' then  -- 手动控制模式
                a_light <= "100";  -- 所有红灯
                b_light <= "100";
                countdown <= counter;  -- 保持当前计数
            else  -- 自动模式
                case current_state is
                    when A_GREEN_B_RED =>
                        a_light <= "001";
                        b_light <= "100";
                        countdown <= counter;
                        
                        if sec_counter = CLK_FREQ - 1 then
                            if counter > 0 then
                                counter <= counter - 1;
                            else
                                current_state <= A_YELLOW_B_RED;
                                counter <= 5;
                            end if;
                        end if;
                        
                    when A_YELLOW_B_RED =>
                        a_light <= "010";
                        b_light <= "100";
                        countdown <= counter;
                        
                        if sec_counter = CLK_FREQ - 1 then
                            if counter > 0 then
                                counter <= counter - 1;
                            else
                                current_state <= A_RED_B_GREEN;
                                counter <= 40;
                            end if;
                        end if;
                        
                    when A_RED_B_GREEN =>
                        a_light <= "100";
                        b_light <= "001";
                        countdown <= counter;
                        
                        if sec_counter = CLK_FREQ - 1 then
                            if counter > 0 then
                                counter <= counter - 1;
                            else
                                current_state <= A_RED_B_YELLOW;
                                counter <= 5;
                            end if;
                        end if;
                        
                    when A_RED_B_YELLOW =>
                        a_light <= "100";
                        b_light <= "010";
                        countdown <= counter;
                        
                        if sec_counter = CLK_FREQ - 1 then
                            if counter > 0 then
                                counter <= counter - 1;
                            else
                                current_state <= A_GREEN_B_RED;
                                counter <= 40;
                            end if;
                        end if;
                end case;
            end if;
        end if;
    end process;

end Behavioral;
