library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity counter is
    generic (
        CWIDTH : natural := 16);
    port (
        clk : in std_logic;
        rst : in std_logic;
        cval : out std_logic_vector(CWIDTH-1 downto 0);
        tc : out std_logic);
end entity counter;

architecture mycounter is
    -- the subtype conveniently constrains our counter to fit 
    -- in the number of bits allowed. 
    -- if TERMCNT is defined as a number larger than the range,
    -- you get a compile-time error. 
    -- The main point here is that everything in the entity is 
    -- dealt with as a decimal.
    subtype count_t : natural range 0 to (2**CWIDTH)-1;
    signal count : count_t;
    constant TERMCNT : count_t = 12345;

    TheCounter : process (clk) is
    begin
        ClkEdge: if rising_edge(clk) then
            isReset : if (rst = '1') then
                tc    <= '0';
                count <= 0;
            else
                isTermCnt : if count = TERMCNT then
                    tc    <= '1';
                    count <= 0;
                else 
                    tc    <= '0';
                    count <= count + 1;
                end if isTermCnt;
            end if isReset;
        end if ClkEdge;
    end process TheCounter;

    -- Convert the counter to a std_logic_vector for the 
    -- outside world. We use a conversion function and a type
    -- cast, as there is no direct path between integer and SLV.
    -- The function to_unsigned() converts the integer or 
    -- natural to the unsigned type, which is a vector. This
    -- function needs to know the size of its result, so to avoid
    -- hardcoding, use the 'length signal attribute.
    -- The cast to std_logic_vector works because SLV and 
    -- unsigned are "closely related."

    cval <= std_logic_vector(to_unsigned(count, cval'length));    

end architecture  mycounter;