------------------------------------------------------------------------
-- CPE 133 VHDL File: sseg_dec.vhd
-- Description: Special seven segment display driver;
--
--  two special inputs: 
-- 
--      VALID: if valid = 0, four dashes will be display
--             if valid = 1, decimal number appears on display
--
--       SIGN: if sign = 1, a minus sign appears in left-most digit
--             if sign = 0, no minus sign appears
--      
--
-- Author: bryan mealy (12-16-10)
--
-- revisions: 
------------------------------------------------------------------------

-----------------------------------------------------------------------
-----------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

-------------------------------------------------------------
-- 4 digit seven-segment display driver. Outputs are active
-- low and configured ABCEDFG in "segment" output. 
--------------------------------------------------------------
entity sseg_dec is
    Port (      ALU_VAL : in std_logic_vector(7 downto 0); 
					    SIGN : in std_logic;
						VALID : in std_logic;
                    CLK : in std_logic;
                DISP_EN : out std_logic_vector(3 downto 0);
               SEGMENTS : out std_logic_vector(7 downto 0));
end sseg_dec;

-------------------------------------------------------------
-- description of ssegment decoder
-------------------------------------------------------------
architecture my_sseg of sseg_dec is

   -- declaration of 8-bit binary to 2-digit BCD converter --
   component bin2bcdconv 
       Port ( BIN_CNT_IN : in std_logic_vector(7 downto 0);
                 LSD_OUT : out std_logic_vector(3 downto 0);
                 MSD_OUT : out std_logic_vector(3 downto 0);
                MMSD_OUT : out std_logic_vector(3 downto 0));
   end component;

	component clk_div
		 Port (  clk : in std_logic;
				  sclk : out std_logic);
	end component;
	
   -- intermediate signal declaration -----------------------
   signal   cnt_dig : std_logic_vector(1 downto 0); 
   signal   digit : std_logic_vector (3 downto 0); 
   signal   lsd,msd,mmsd : std_logic_vector(3 downto 0); 
	signal   sclk : std_logic; 

begin

   -- instantiation of bin to bcd converter -----------------
   my_conv: bin2bcdconv 
	port map ( BIN_CNT_IN => ALU_VAL, 
                 LSD_OUT => lsd, 
                 MSD_OUT => msd, 
                MMSD_OUT => mmsd); 

   my_clk: clk_div 
	port map (clk => clk,
	          sclk => sclk ); 

   -- advance the count (used for display multiplexing) -----
   process (SCLK)
   begin
      if (rising_edge(SCLK)) then 
         cnt_dig <= cnt_dig + 1; 
      end if; 
   end process; 


   -- select the display sseg data abcdefg (active low) -----
   segments <= "00000011" when digit = "0000"  else
               "10011111" when digit = "0001"  else
               "00100101" when digit = "0010"  else
               "00001101" when digit = "0011"  else
               "10011001" when digit = "0100"  else
               "01001001" when digit = "0101"  else
               "01000001" when digit = "0110"  else
               "00011111" when digit = "0111"  else
               "00000001" when digit = "1000"  else
               "00001001" when digit = "1001"  else
					"11111101" when digit = "1110" else   -- dash
					"11111111" when digit = "1110" else   -- blank
               "11111111"; 

   -- actuate the correct display --------------------------
   disp_en <= "1110" when cnt_dig = "00" else 
              "1101" when cnt_dig = "01" else
              "1011" when cnt_dig = "10" else
              "0111" when cnt_dig = "11" else
              "1111"; 

 
	process (cnt_dig, lsd, msd, mmsd, sign, valid)
	   variable mmsd_v, msd_v : std_logic_vector(3 downto 0);    
	begin
	   mmsd_v := mmsd; 
		msd_v := msd; 
		
		-- do the lead zero blanking for two msb's
		if (mmsd_v = X"0") then 
		   if (msd_v = X"0") then 
			   msd_v := X"F"; 
			end if; 
		   mmsd_v := X"F"; 
		end if; 
			
		if (valid = '1') then
			if (sign = '0') then
				case cnt_dig is
					when "00" => digit <= "1111"; 
					when "01" => digit <= mmsd_v; 
					when "10" => digit <= msd_v; 
					when "11" => digit <= lsd; 
					when others => digit <= "0000"; 
				end case; 
			else
				case cnt_dig is 
					when "00" => digit <= "1110"; 
					when "01" => digit <= mmsd_v; 
					when "10" => digit <= msd_v; 
					when "11" => digit <= lsd; 
					when others => digit <= "0000";
				end case;
			end if;
		else digit <= "1110";
		end if;
	end process;
			

end my_sseg;




--------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
--------------------------------------------------------------------
-- interface description for bin to bcd converter 
--------------------------------------------------------------------
entity bin2bcdconv is
    Port ( BIN_CNT_IN : in std_logic_vector(7 downto 0);
              LSD_OUT : out std_logic_vector(3 downto 0);
              MSD_OUT : out std_logic_vector(3 downto 0);
             MMSD_OUT : out std_logic_vector(3 downto 0));
end bin2bcdconv;

---------------------------------------------------------------------
-- description of 8-bit binary to 3-digit BCD converter 
---------------------------------------------------------------------
architecture my_ckt of bin2bcdconv is
begin
   process(bin_cnt_in)
       variable cnt_tot : INTEGER range 0 to 255 := 0; 
	    variable lsd,msd,mmsd : INTEGER range 0 to 9 := 0; 
   begin
	 
	 -- convert input binary value to decimal
	 cnt_tot := 0; 
    if (bin_cnt_in(7) = '1') then cnt_tot := cnt_tot + 128;  end if; 
    if (bin_cnt_in(6) = '1') then cnt_tot := cnt_tot +  64;  end if; 
    if (bin_cnt_in(5) = '1') then cnt_tot := cnt_tot +  32;  end if; 
    if (bin_cnt_in(4) = '1') then cnt_tot := cnt_tot +  16;  end if; 
    if (bin_cnt_in(3) = '1') then cnt_tot := cnt_tot +   8;  end if; 
    if (bin_cnt_in(2) = '1') then cnt_tot := cnt_tot +   4;  end if; 
    if (bin_cnt_in(1) = '1') then cnt_tot := cnt_tot +   2;  end if; 
    if (bin_cnt_in(0) = '1') then cnt_tot := cnt_tot +   1;  end if; 

	 -- initialize intermediate signals
    msd  := 0; 
	 mmsd := 0; 
	 lsd  := 0;
           
    --  calculate the MMSB
    for I in 1 to 2 loop
	    exit when (cnt_tot >= 0 and cnt_tot < 100); 
	    mmsd := mmsd + 1; -- increment the mmds count
	    cnt_tot := cnt_tot - 100;
    end loop; 
      	         
     --  calculate the MSB
    for I in 1 to 9 loop	     
       exit when (cnt_tot >= 0 and cnt_tot < 10); 
       msd := msd + 1; -- increment the mds count
	    cnt_tot := cnt_tot - 10;
    end loop; 
      	    
	 lsd := cnt_tot;   -- lsd is what is left over

	 -- convert lsd to binary
	 case lsd is 
	    when 9 =>  lsd_out <= "1001"; 
	    when 8 =>  lsd_out <= "1000"; 
	    when 7 =>  lsd_out <= "0111"; 
	    when 6 =>  lsd_out <= "0110"; 
	    when 5 =>  lsd_out <= "0101"; 
	    when 4 =>  lsd_out <= "0100"; 
	    when 3 =>  lsd_out <= "0011"; 
	    when 2 =>  lsd_out <= "0010"; 
	    when 1 =>  lsd_out <= "0001"; 
	    when 0 =>  lsd_out <= "0000"; 
	    when others =>  lsd_out <= "0000"; 
    end case; 

	 -- convert msd to binary
	 case msd is 
	    when 9 =>  msd_out <= "1001"; 
	    when 8 =>  msd_out <= "1000"; 
	    when 7 =>  msd_out <= "0111"; 
	    when 6 =>  msd_out <= "0110"; 
	    when 5 =>  msd_out <= "0101"; 
	    when 4 =>  msd_out <= "0100"; 
	    when 3 =>  msd_out <= "0011"; 
	    when 2 =>  msd_out <= "0010"; 
	    when 1 =>  msd_out <= "0001"; 
	    when 0 =>  msd_out <= "0000"; 
	    when others =>  msd_out <= "0000"; 
      end case; 

	 -- convert msd to binary
	 case mmsd is  
	    when 2 =>  mmsd_out <= "0010"; 
	    when 1 =>  mmsd_out <= "0001"; 
	    when 0 =>  mmsd_out <= "0000"; 
	    when others =>  mmsd_out <= "0000"; 
    end case; 

   end process; 
end my_ckt;


-----------------------------------------------------------------------
-----------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
-----------------------------------------------------------------------
-- Module to divide the clock 
-----------------------------------------------------------------------
entity clk_div is
    Port (  clk : in std_logic;
           sclk : out std_logic);
end clk_div;

architecture my_clk_div of clk_div is
   constant max_count : integer := (2200);  
   signal tmp_clk : std_logic := '0'; 
begin
   my_div: process (clk,tmp_clk)              
      variable div_cnt : integer := 0;   
   begin
      if (rising_edge(clk)) then   
         if (div_cnt = MAX_COUNT) then 
            tmp_clk <= not tmp_clk; 
            div_cnt := 0; 
         else
            div_cnt := div_cnt + 1; 
         end if; 
      end if; 
      sclk <= tmp_clk; 
   end process my_div; 
end my_clk_div;