-- See the file "LICENSE" for the full license governing this code. --

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.lt16x32_global.all;
use work.wishbone.all;
use work.config.all;

entity wb_segment_adv is
	generic(
		memaddr		:	generic_addr_type; --:= CFG_BADR_SEG;
		addrmask	:	generic_mask_type --:= CFG_MADR_SEG;
	);
	port(
		clk		: in  std_logic;
		rst		: in  std_logic;
		wslvi	:	in	wb_slv_in_type;
		wslvo	:	out	wb_slv_out_type;

        anodes : out std_logic_vector(7 downto 0);
        cathodes : out std_logic_vector(7 downto 0)
	);
end wb_segment_adv;

architecture Behavioral of wb_segment_adv is

    signal ack : std_logic;

	signal hex_register : std_logic_vector(63 downto 0);
    signal data_out : std_logic_vector(31 downto 0);
    signal data_in : std_logic_vector(31 downto 0);
    signal data_in_changed : std_logic;

    signal hex : std_logic_vector(4 downto 0);

    signal timer_overflow : std_logic;
    signal overflow_counter : integer range 0 to 7;

    component hex2physical
    port(
        hex : in std_logic_vector(4 downto 0);
        cathodes : out std_logic_vector(7 downto 0)
    );
    end component;

    component simple_timer
    generic(
        timer_start : std_logic_vector (31 downto 0)
    );
    port(
        clk : in std_logic;
        rst : in std_logic;
        timer_overflow : out std_logic
    );
    end component;

begin

    converter : hex2physical
    port map(
        hex => hex,
        cathodes => cathodes
    );

    timer: simple_timer
    generic map (timer_start => x"00000008") -- for simulation
    -- generic map (timer_start => x"00000F00") -- for board
    port map(
        clk => clk,
        rst => rst,
        timer_overflow => timer_overflow
    );
    
	process(clk)
	begin
		if clk'event and clk='1' then
			if rst = '1' then
				ack	<= '0';
				data_out <= (others=>'0');
                data_in	<= (others=>'0');
                data_in_changed <= '0';
			else
                data_out <= (others=>'0');
                data_in	<= (others=>'0');
                data_in_changed <= '0';

				if wslvi.stb = '1' and wslvi.cyc = '1' then
				    if wslvi.we='0' then
                        -- data_out will stay 0
                    else
                        -- Write enable
                        data_in <= dec_wb_dat(wslvi.sel,wslvi.dat);
                        data_in_changed <= '1';
                    end if;
				
					if ack = '0' then
						ack	<= '1';
					else
						ack	<= '0';
					end if;
				else
					ack <= '0';
				end if;
			end if;
		end if;
	end process;

    process(clk)
        variable v_data : std_logic_vector(3 downto 0);
        variable v_off : std_logic;
        variable v_write : std_logic;
        variable v_clear : std_logic;
        variable v_shift : std_logic;
    begin
        if clk'event and clk='1' then
			if rst = '1' then
				hex_register <= (others=>'0');
			else
                if data_in_changed = '1' and ack = '1' then -- only check if ack was just raised
                    v_data := data_in(3 downto 0);
                    v_off := data_in(4);
                    v_write := data_in(8);
                    v_clear := data_in(16);
                    v_shift := data_in(24);
                    
                    -- No special care has to be taken to support
                    -- writing and shifting at the same time.
                    
                    if v_shift = '1' then
                        hex_register(63 downto 56) <= (others => '0');
                        hex_register(55 downto 0) <= hex_register(63 downto 8);
                    end if;
                        
                    if v_write = '1' then
                        hex_register(59 downto 56) <= v_data;
                        hex_register(60) <= not v_off; -- unclear if this should only be set when write is 1
                    end if;

                    if v_clear = '1' then
                        hex_register <= (others => '0');    
                    end if;
                end if;
            end if;
        end if;
    end process;

    process(clk)
    begin
        if clk'event and clk='1' then
            if rst = '1' then
                hex <= hex_register(4 downto 0);
                anodes <= (others => not '0');
                overflow_counter <= 0;
            else
                if timer_overflow = '1' then
                    if overflow_counter = 7 then
                        overflow_counter <= 0;
                    else
                        overflow_counter <= overflow_counter + 1;
                    end if;

                    anodes <= (others => not '0');
                    anodes(overflow_counter) <= not '1';
                    
                    hex <= hex_register(overflow_counter * 8 + 4 downto overflow_counter * 8);
                end if;
            end if;
        end if;
    end process;

	wslvo.dat <= data_out;

	wslvo.ack	<= ack;
	wslvo.wbcfg	<= wb_membar(memaddr, addrmask);

end Behavioral;
