-- EXAMPLE: D-FF ————————————————————————————————————————

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity d_flip_flop is
    Port (
        clk : in  STD_LOGIC;
        d   : in  STD_LOGIC;
        q   : out STD_LOGIC
    );
end d_flip_flop;

architecture Behavioral of d_flip_flop is

begin
    process(clk) 
    	-- the statements within process are executed every time there is a change in the logic level of clk
    begin
        if rising_edge(clk) then
        	-- "rising_edge() is a VHDL function
            -- changes in the circuit happen only on the rising egde of the clk input
            
            -- THIS WAY OF WRITING THE CODE IS WHAT MAKES THE D-FF OUTPUT SYNCHRONOUS TO THE CLOCK INPUT!!! ---
            
            q <= d;
        end if;
        -- a condition that indicates what should happen if the listed if condition is not met, is not provided
        -- if the if condition is not met, the D-FF does not chnage the value of q
		-- the D-FF must remember the current value
        -- THIS IS THE WAY TO INDUCE MEMORY IN VHDL!!!
    end process;

end Behavioral;

-- EXAMPLE: TEST BENCH OF D-FF ————————————————————————————————————————
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity d_flip_flop_tb is
end d_flip_flop_tb;

architecture Behavioral of d_flip_flop_tb is

	-- Component declaration
    component d_flip_flop
        Port (
            clk : in  STD_LOGIC;
            d   : in  STD_LOGIC;
            q   : out STD_LOGIC
        );
    end component;

    -- Testbench signals
    signal clk_tb        : STD_LOGIC := '0';
    signal d_tb          : STD_LOGIC := '0';
    signal q_tb          : STD_LOGIC;
    signal stop_clock_tb : BOOLEAN := false; -- note BOOLEAN type, not seen before
    
    -- Clock period constant
    constant CLK_PERIOD : time := 10 ns;
    -- synthax for constant declaration 
        	-- constant <name> : type := <initial value>;
        -- "time" is a data type used in simulations
        	-- FPGA does not have the concept of time
        -- the constant is given a value at declaration that cannot be changed afterwards

begin

    -- DUT instantiation
    uut: d_flip_flop
        port map (
            clk => clk_tb,
            d   => d_tb,
            q   => q_tb
        );

    -- Clock generation
    clk_process : process
    begin
        while not stop_clock_tb loop 	-- we do not discuss the while loop construct in this course
        								-- refer to the suggested book
            clk_tb <= '0';
            wait for CLK_PERIOD/2;
            clk_tb <= '1';
            wait for CLK_PERIOD/2;
        end loop;
        wait;
    end process;

    -- Stimulus process
    stim_proc : process
    begin
        
        wait for 12 ns;
        d_tb <= '1';

        wait for 10 ns;
        d_tb <= '0';

        wait for 10 ns;
        d_tb <= '1';

        wait for 10 ns;
        d_tb <= '0';

        wait for 20 ns;
        stop_clock_tb <= true;  -- stop the clock

        wait;
    end process;

end Behavioral;