--------------------------------------------------------------------------------
-- Company: Chalmers University of Technology
-- Engineer: Vikram Jain
-- 
-- Create Date:    17:51:45 11/15/2012 
-- Design Name: 
-- Module Name:    top - rtl 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: This is the top level design, and so the ports assigned to
--              pins have suffix "_pad". The design implements a variable
--              sine wave generator. The frequency of sine wave can be changed
--              by using a toggle switch on the development board. Since the 
--              switch / button contacts are imperfect, the respective signals 
--              on the FPGA pins are bouncing for a short period after switching.
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
--------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library UNISIM;
use UNISIM.VComponents.all;

entity top is
    port(clk_pad : in std_logic;
         reset_pad : in std_logic;
         inc_pad : in std_logic;
         dec_pad : in std_logic;
         out_data_pad : out std_logic_vector(15 downto 0)
    );
end;

architecture arch of top is

component clk_enable
    port(clk: in std_logic;
         reset: in std_logic;
         clk_generic: out std_logic;
         clk_6M : out std_logic;
         clk_250K : out std_logic
    );
end component;

component dds_compiler_0
    port(
        aclk : IN STD_LOGIC;
        m_axis_data_tvalid : OUT STD_LOGIC;
        m_axis_data_tdata : OUT STD_LOGIC_VECTOR(63 DOWNTO 0)
    );
end component;

component dds_compiler_1
    port(
        aclk : IN STD_LOGIC;
        m_axis_data_tvalid : OUT STD_LOGIC;
        m_axis_data_tdata : OUT STD_LOGIC_VECTOR(63 DOWNTO 0)
    );
end component;

component ila_0
    port(clk :in std_logic;
         probe0 : IN STD_LOGIC;
         probe1 : IN STD_LOGIC;
         probe2 : IN STD_LOGIC_VECTOR(3 downto 0);
         probe3 : IN STD_LOGIC;
         probe4 : IN STD_LOGIC;
         probe5 : IN STD_LOGIC;
         probe6 : IN STD_LOGIC_VECTOR(25 DOWNTO 0);
         probe7 : IN STD_LOGIC_VECTOR(25 DOWNTO 0)          
    );
end component;

signal sinegen_out : std_logic_vector(63 downto 0);
signal sinegen1_out : std_logic_vector(63 downto 0);
signal sinegen2_out : std_logic_vector(63 downto 0);
signal clk_6M_signal : std_logic;
signal clk_250K_signal : std_logic;
signal clk, clk_unbuf, rst : std_logic;
signal out_data : std_logic_vector(15 downto 0);
signal inc :std_logic;
signal dec : std_logic;
signal sine1 : std_logic;
signal sine2 : std_logic;
signal sine1_reg : std_logic;
signal sine2_reg : std_logic;
signal sine1_le : std_logic;
signal sine2_le : std_logic;
signal en_sine1 : std_logic;
signal en_sine2 : std_logic;
signal counter : unsigned(3 downto 0);
-- divide the system clock to capture slow events such as button press/release
constant CLK_SLOW_CNT_WIDTH  : integer := 8; --16;
signal clk_slow_cnt : unsigned(CLK_SLOW_CNT_WIDTH - 1 downto 0);
signal clk_slow : std_logic;

-- 2x slower clock (for ila only)
signal clk_div2 : std_logic;

-- 2x slower clk_slow (for ila_slow only)
signal clk_slow_div2 : std_logic;
    
begin

clk_ibufg : IBUFG 
    generic map (
      IOSTANDARD => "DEFAULT"
      )
    port map (
      I => clk_pad,
      O => clk_unbuf      
      );
  
  clk_bufg : BUFG
    port map (
      I => clk_unbuf,
      O => clk
      );
  
  rst_buf : IBUF
    port map (
      I => reset_pad,
      O => rst
      );
   
   inc_buf : IBUF
      port map (
        I => inc_pad,
        O => inc
        );
        
    dec_buf : IBUF
      port map (
        I => dec_pad,
        O => dec
        );
   
   led_buf : for i in 15 downto 0 generate
   out_buf_i : OBUF
    port map (
       I => out_data(i),
       O => out_data_pad(i)
       );
    end generate led_buf;

out_data(15 downto 0) <= sinegen_out(25 downto 10);

clk_enable1 : clk_enable
    port map(reset => rst,
             clk => clk,
             clk_6M => clk_6M_signal,
             clk_250K => clk_250K_signal
            );
    
sinegen1 : dds_compiler_0
    port map(aclk => clk_6M_signal,
             m_axis_data_tvalid => open,
             m_axis_data_tdata => sinegen1_out);
             
sinegen2 : dds_compiler_1
                 port map(aclk => clk_6M_signal,
                          m_axis_data_tvalid => open,
                          m_axis_data_tdata => sinegen2_out);
             
debug0 : ila_0
    port map(clk => clk,
             probe0 => clk_div2,
             probe1 => inc,
             probe2 => std_logic_vector(counter),
             probe3 => en_sine1,
             probe4 => en_sine2,
             probe5 => sine1_le,
             probe6 => sinegen_out(57 downto 32),
             probe7 => sinegen_out(25 downto 0));

sine1 <= inc;
sine2 <= dec;             

sine1_le <= sine1 and not sine1_reg;
sine2_le <= sine2 and not sine2_reg;
             
sinegen_out <= sinegen1_out when en_sine1 = '1' else
               sinegen2_out when en_sine2 = '1';
               
clk_div2_gen : process(rst, clk)
 begin
   if (rst = '1') then
     clk_div2 <= '0';
       
   elsif rising_edge(clk) then
     clk_div2 <= not clk_div2;
       
   end if;
     
 end process clk_div2_gen;
 
  clk_slow_gen : process(rst, clk)
  begin
    if (rst = '1') then
      clk_slow_cnt <= (others => '0');
        
    elsif rising_edge(clk) then
      clk_slow_cnt <= clk_slow_cnt + 1;
        
    end if;
      
  end process;

  clk_slow <= clk_slow_cnt(clk_slow_cnt'high - 1);
  clk_slow_div2 <= clk_slow_cnt(clk_slow_cnt'high);
               
vary_sine : process(clk,rst)
begin
    if rst = '1' then
        sine1_reg <= '0';
        sine2_reg <= '0';
        en_sine1 <= '0';
        en_sine2 <= '0';
        counter <= (others=>'0');
        
    elsif rising_edge(clk) then
        sine1_reg <= inc;
        sine2_reg <= dec;
        
        if (sine1_le = '1') then
        counter <= counter + 1;
        if counter rem 2 = 0 then
            en_sine1 <= '1';
            en_sine2 <= '0';
        elsif counter rem 2 /= 0 then
            en_sine2 <= '1';
            en_sine1 <= '0';
        elsif counter = 15 then   
            counter <= (others=>'0');
        --elsif counter = 2 then
        --    counter <= 0;
        --elsif (sine2_le = '1') then
        --    en_sine2 <= '1';
         --   en_sine1 <= '0';
         end if;
        end if;
    end if;
end process; 

end arch;