-- BCD counter using HP QDSP-6064 7 segment display
-- Steven J. Merrifield, June 2016

library ieee;
use ieee.std_logic_1164.all;

entity LED is
	port (clk : in std_logic;
			segments : out std_logic_vector(6 downto 0); -- 'g' downto 'a'
			cathodes : out std_logic_vector(3 downto 0)
		);
end LED;

architecture arch of LED is

function dec2seg(num : integer) return std_logic_vector is
begin
	case num is
		when 0 => return("0111111");
		when 1 => return("0000110");
		when 2 => return("1011011");
		when 3 => return("1001111");
		when 4 => return("1100110");
		when 5 => return("1101101");
		when 6 => return("1111101");
		when 7 => return("0000111");
		when 8 => return("1111111");
		when 9 => return("1101111");
		when others => return("0000000");
	end case;
end dec2seg;

constant clock_max : integer := 25_000_000;
constant refresh_max : integer := 10000;

begin
	process
		variable clock_counter : integer := 0;
		variable refresh_counter : integer := 0;
		variable cathode_num : integer range 0 to 3 := 0;
		variable digit0 : integer range 0 to 9 := 0;
		variable digit1 : integer range 0 to 9 := 0;
		variable digit2 : integer range 0 to 9 := 0;
		variable digit3 : integer range 0 to 9 := 0;
	begin
		wait until rising_edge(clk);
		if (clock_counter < clock_max) then
			clock_counter := clock_counter + 1;
		else
			clock_counter := 0;
			if (digit0 /= 9) then
				digit0 := digit0 + 1;
				elsif (digit0 = 9) and (digit1 /= 9) then
					digit0 := 0;
					digit1 := digit1 + 1;
					elsif (digit0 = 9) and (digit1 = 9) and (digit2 /= 9) then
						digit0 := 0;
						digit1 := 0;
						digit2 := digit2 + 1;
						elsif (digit0 = 9) and (digit1 = 9) and (digit2 = 9) and (digit3 /= 9) then
							digit0 := 0;
							digit1 := 0;
							digit2 := 0;
							digit3 := digit3 + 1;
							elsif (digit3 = 9) then
								digit0 := 0;
								digit1 := 0;
								digit2 := 0;
								digit3 := 0;
			end if;
		end if;
		
		if (refresh_counter < refresh_max) then
			refresh_counter := refresh_counter + 1;
		else
			refresh_counter := 0;
			if (cathode_num /= 3) then
				cathode_num := cathode_num + 1;
			else
				cathode_num := 0;
			end if;
			case cathode_num is
				when 0 => segments <= dec2seg(digit0); cathodes <= "1110";
				when 1 => segments <= dec2seg(digit1); cathodes <= "1101";
				when 2 => segments <= dec2seg(digit2); cathodes <= "1011";
				when 3 => segments <= dec2seg(digit3); cathodes <= "0111";
				when others => segments <= "0000000"; cathodes <= "1111";
			end case;
		end if;
			
	end process;
end arch;
