Wednesday, February 5, 2014

update counter vhdl code with package

origianl counter vhdl code without package: http://scott2595.blogspot.com/2014/02/write-counter-with-vhdl.html

The following is the package which include some functions and procedures used in original counter vhdl code:
#############################################################################
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

package user_pkg is
function to_stdulogic(V: Boolean) return std_ulogic;
function to_bcd (bin: std_logic_vector(7 downto 0)) return std_logic_vector;
procedure segment_dec_without_dp (signal bcd: in std_logic_vector(3 downto 0); signal segment : out std_logic_vector(6 downto 0));
procedure segment_dec_with_dp (signal bcd: in std_logic_vector(3 downto 0); signal segment : out std_logic_vector(7 downto 0));
end;

package body user_pkg is
--function to convert boolean to std_logic
function to_stdulogic(V: Boolean) return std_ulogic is
begin
    if V then
        return '1';
    else
        return '0';
    end if;
end to_stdulogic;

--function to convert std_logic_vector to bcd
function to_bcd (bin: std_logic_vector(7 downto 0)) return std_logic_vector is
variable i       : integer := 0;
variable bcd     : std_logic_vector(11 downto 0) := (others => '0');
variable bin_tmp : std_logic_vector(7 downto 0)  := bin;
begin
    -- repeating 8 times.
    for i in 0 to 6 loop
        --shifting the bits.
        bcd(11 downto 1)    := bcd(10 downto 0);
        bcd(0)              := bin_tmp(7);
        bin_tmp(7 downto 1) := bin_tmp(6 downto 0);
        bin_tmp(0)          := '0';
       
        --add 3 if BCD digit is greater than 4.
        if(bcd(3 downto 0) > "0100") then
            bcd(3 downto 0) := bcd(3 downto 0) + "0011";
        end if;
       
        --add 3 if BCD digit is greater than 4.
        if(bcd(7 downto 4) > "0100") then
            bcd(7 downto 4) := bcd(7 downto 4) + "0011";
        end if;
       
        --add 3 if BCD digit is greater than 4.
        if(bcd(11 downto 8) > "0100") then
            bcd(11 downto 8) := bcd(11 downto 8) + "0011";
        end if;
   
    end loop;

    bcd(11 downto 1) := bcd(10 downto 0);
    bcd(0)           := bin_tmp(7);

    return bcd;
end to_bcd;

procedure segment_dec_without_dp (
    signal bcd: in std_logic_vector(3 downto 0);
    signal segment : out std_logic_vector(6 downto 0)
) is
begin
    case bcd is
        --decode from bcd to segment
        when x"0" => segment <= b"1000000";
        when x"1" => segment <= b"1111001";
        when x"2" => segment <= b"0100100";
        when x"3" => segment <= b"0110000";
        when x"4" => segment <= b"0011001";
        when x"5" => segment <= b"0010010";
        when x"6" => segment <= b"0000010";
        when x"7" => segment <= b"1111000";
        when x"8" => segment <= b"0000000";
        when x"9" => segment <= b"0010000";
        --when in selector 1, counter should add 1 after each half second
        --for other unknown selectors, set counter to 0
        when others => segment <= b"1000000";
    end case;
end procedure segment_dec_without_dp;

procedure segment_dec_with_dp (
    signal bcd: in std_logic_vector(3 downto 0);
    signal segment : out std_logic_vector(7 downto 0)
) is
begin
    case bcd is
        --decode from bcd to segment
        when x"0" => segment <= b"11000000";
        when x"1" => segment <= b"11111001";
        when x"2" => segment <= b"10100100";
        when x"3" => segment <= b"10110000";
        when x"4" => segment <= b"10011001";
        when x"5" => segment <= b"10010010";
        when x"6" => segment <= b"10000010";
        when x"7" => segment <= b"11111000";
        when x"8" => segment <= b"10000000";
        when x"9" => segment <= b"10010000";
        --when in selector 1, counter should add 1 after each half second
        --for other unknown selectors, set counter to 0
        when others => segment <= b"11000000";
    end case;
end procedure segment_dec_with_dp;

end package body;
#############################################################################

Rewrite the code with package used. The package is compiled into work library by default.
#############################################################################
-----------------------------------------------------------------
--clk dividor
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;

entity clk_div is
generic (
    N: integer := 12499999
);
port (
    clk     : in  std_logic;
    rst_n   : in  std_logic;
    clk_out : out std_logic
);
end entity clk_div;

architecture behavioral of clk_div is
signal clk_cnt     : integer range 0 to N;
signal clk_out_tmp : std_logic;
begin
--counter for half second
process(clk, rst_n)
begin
    if(rst_n = '0')then
        clk_cnt <= 0;
        clk_out_tmp <= '0';
    elsif(clk'event and clk = '1')  then
        --when counter reaches to half second,
        --need to reset the counter to 0
        if(clk_cnt = N) then
            clk_cnt <= 0;
            clk_out_tmp <= not (clk_out_tmp);
        else
            clk_cnt <= clk_cnt + 1;
            clk_out_tmp <= clk_out_tmp;
        end if;
    end if;
end process;

clk_out <= clk_out_tmp;

end behavioral;

-----------------------------------------------------------------
--counter
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.user_pkg.all;

entity counter is
port (
    clk_in   : in  std_logic;
    rst_n    : in  std_logic;
    selector : in  std_logic_vector(1 downto 0);
    data     : out std_logic_vector(7 downto 0)
);
end entity counter;

architecture behavioral of counter is
--signal declaration in architecture
signal cnt             : integer range 0 to 255;
signal cnt_nxt         : integer range 0 to 255;
signal selector_ff1    : std_logic_vector(1 downto 0);
signal selector_ff2    : std_logic_vector(1 downto 0);
signal selector_ff3    : std_logic_vector(1 downto 0);
signal selector_trig   : std_logic_vector(3 downto 0);
signal selector_status : std_logic_vector(3 downto 0);
signal reverse         : std_logic;
signal reverse_nxt     : std_logic;

--begin of architecture
begin

--solve metastability issue, so 2 flip-flops are needed
--sample the change of selector, so 3 flip-flops are needed
--so add 3 flip-flops
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        selector_ff1 <= b"00";
        selector_ff2 <= b"00";
        selector_ff3 <= b"00";
    elsif(clk_in'event and clk_in = '1') then
        selector_ff1 <= selector;
        selector_ff2 <= selector_ff1;
        selector_ff3 <= selector_ff2;
    end if;
end process;

--sample the change of selector
--use each bit to represent one selector
selector_trig(0)   <= to_stdulogic((selector_ff2 = b"00") and (selector_ff3 /= b"00"));
selector_trig(1)   <= to_stdulogic((selector_ff2 = b"01") and (selector_ff3 /= b"01"));
selector_trig(2)   <= to_stdulogic((selector_ff2 = b"10") and (selector_ff3 /= b"10"));
selector_trig(3)   <= to_stdulogic((selector_ff2 = b"11") and (selector_ff3 /= b"11"));
selector_status(0) <= to_stdulogic(selector_ff2 = b"00");
selector_status(1) <= to_stdulogic(selector_ff2 = b"01");
selector_status(2) <= to_stdulogic(selector_ff2 = b"10");
selector_status(3) <= to_stdulogic(selector_ff2 = b"11");

--counter state machine
--counter to count how many half seconds
process(selector_trig, selector_status, cnt, reverse)
begin
    --when selector change, this counter need to reset
    --set counter data to 0 when in selector 1 and selector 3
    --set coutner to 1 when in selector 2
    if(selector_trig(1) = '1' or selector_trig(3) = '1') then
        cnt_nxt <= 0;
    elsif(selector_trig(2) = '1') then
        cnt_nxt <= 255;
    else
        case selector_status is
            --when in selector 0, counter should be 0
            when b"0001" =>
                cnt_nxt <= 0;
            --when in selector 1, counter should add 1 after each half second
            when b"0010" =>
                if(cnt = 255) then
                    --if need to repeat from 0 to 255
                    --set cnt_nxt to 0
                    --else keep it as 255
                    --cnt_nxt <= 0;
                    cnt_nxt <= cnt;
                else
                    cnt_nxt <= cnt + 1;
                end if;
            --when in selector 2, counter should decrease 1 after each half second
            when b"0100" =>
                if(cnt = 0) then
                    --if need to repeat from 255 to 0
                    --set cnt_nxt to 255
                    --else keep it as 0
                    --cnt_nxt <= 255;
                    cnt_nxt <= cnt;
                else
                    cnt_nxt <= cnt - 1;
                end if;
            --when in selector 3, counter should add 1 after each half second
            --and after reaches 255, counter will decrease 2 after each half second
            when b"1000" =>
                if(reverse = '0') then
                    if(cnt = 255) then
                        cnt_nxt <= cnt - 2;
                    else
                        cnt_nxt <= cnt + 1;
                    end if;
                else
                    if(cnt = 1) then
                        --if need to repeat from 0 to 255 and then 255 to 1
                        --set cnt_nxt to 0
                        --else keep it as 1
                        --cnt_nxt <= 0;
                        cnt_nxt <= cnt;
                    else
                        cnt_nxt <= cnt - 2;
                    end if;
                end if;
            --for other unknown selectors, set counter to 0
            when others =>
                cnt_nxt <= 0;
        end case;
    end if;
end process;

process(selector_trig, selector_status, cnt, reverse)
begin
    --when selector change, this counter need to reset
    --set counter data to 0 when in selector 1 and selector 3
    --set coutner to 1 when in selector 2
    if(selector_trig(3) = '1') then
        reverse_nxt <= '0';
    elsif(selector_status = b"1000") then
        if(reverse = '0') then
            if(cnt = 255) then
                reverse_nxt <= '1';
            else
                reverse_nxt <= reverse;
            end if;
        else
            if(cnt = 1) then
                --if need to repeat from 0 to 255 and then 255 to 1
                --set reverse_nxt to 0
                --else keep it as 1
                --reverse_nxt <= '0';
                reverse_nxt <= reverse;
            else
                reverse_nxt <= reverse;
            end if;
        end if;
    else
        reverse_nxt <= '0';
    end if;
end process;

--in selector 3, check if counter reaches 255
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        reverse <= '0';
    elsif(clk_in'event and clk_in = '1') then
        reverse <= reverse_nxt;
    end if;
end process;

--flip-flop the counter
process(clk_in, rst_n)
begin
    if(rst_n = '0') then
        cnt <= 0;
    elsif(clk_in'event and clk_in = '1') then
        cnt <= cnt_nxt;
    end if;
end process;

--send the counter data out
data <= std_logic_vector(to_unsigned(cnt, 8));

end behavioral;
--end of architecture

-----------------------------------------------------------------
--bin to bcd
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
use work.user_pkg.all;

entity bin2bcd is
port (
    --clk   : in std_logic;
    --rst_n : in std_logic;
    bin   : in std_logic_vector(7 downto 0);
    bcd   : out std_logic_vector(11 downto 0)
);
end entity bin2bcd;

architecture behavioral of bin2bcd is
--signal bin_ff1    : std_logic_vector(7 downto 0);
--signal bin_ff2    : std_logic_vector(7 downto 0);

begin
--process(clk, rst_n)
--begin
--    if(rst_n = '0') then
--        bin_ff1 <= x"00";
--        bin_ff2 <= x"00";
--    elsif(clk'event and clk = '1') then
--        bin_ff1 <= bin;
--        bin_ff2 <= bin_ff1;
--    end if;
--end process;

--bcd <= to_bcd(bin_ff2);
bcd <= to_bcd(bin);

end behavioral;

-----------------------------------------------------------------
--bcd to segment
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use work.user_pkg.all;

entity bcd2segment is
generic (
    M: integer := 7
);
port (
    bcd     : in std_logic_vector(3 downto 0);
    segment : out std_logic_vector(M-1 downto 0)
);
end entity bcd2segment;

architecture behavioral of bcd2segment is

begin

SEGMENT_WITHOUT_DP: if M=7 generate
process(bcd)
begin
    segment_dec_without_dp(bcd, segment);
end process;
end generate SEGMENT_WITHOUT_DP;

SEGMENT_WITH_DP: if M=8 generate
process(bcd)
begin
    segment_dec_with_dp(bcd, segment);
end process;

end generate SEGMENT_WITH_DP;

end behavioral;

-----------------------------------------------------------------
--top
-----------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;

entity top is
generic (
    M: integer := 7;
    N: integer := 12499999
);
port (
    clk      : in  std_logic;
    rst_n    : in  std_logic;
    selector : in  std_logic_vector(1 downto 0);
    data     : out std_logic_vector(7 downto 0);
    segment0 : out std_logic_vector(M-1 downto 0);
    segment1 : out std_logic_vector(M-1 downto 0);
    segment2 : out std_logic_vector(M-1 downto 0)
);
end entity top;

architecture behavioral of top is
--signal declaration in architecture
signal clk_out  : std_logic;
signal data_tmp : std_logic_vector(7 downto 0);
signal bcd      : std_logic_vector(11 downto 0);

component clk_div is
generic (
    N: integer := 12499999
);
port (
    clk     : in  std_logic;
    rst_n   : in  std_logic;
    clk_out : out std_logic
);
end component;

component counter is
port (
    clk_in   : in  std_logic;
    rst_n    : in  std_logic;
    selector : in  std_logic_vector(1 downto 0);
    data     : out std_logic_vector(7 downto 0)
);
end component;

component bin2bcd is
port (
    --clk   : in std_logic;
    --rst_n : in std_logic;
    bin   : in std_logic_vector(7 downto 0);
    bcd   : out std_logic_vector(11 downto 0)
);
end component;

component bcd2segment is
generic (
    M: integer := 7
);
port (
    bcd     : in std_logic_vector(3 downto 0);
    segment : out std_logic_vector(M-1 downto 0)
);
end component;

--begin of architecture
begin

--instance clock dividor
u_clk_div: clk_div generic map (
    N => N
) PORT MAP (
    clk     => clk     ,
    rst_n   => rst_n   ,
    clk_out => clk_out
);

--instance counter
u_counter: counter PORT MAP (
    clk_in   => clk_out  ,
    rst_n    => rst_n    ,
    selector => selector ,
    data     => data_tmp    
);

data <= data_tmp;

--instance bin2bcd
u_bin2bcd: bin2bcd PORT MAP (
    --clk   => clk,
    --rst_n => rst_n,
    bin   => data_tmp,
    bcd   => bcd
);

--instance segment0
u_bcd2segment_0: bcd2segment generic map (
    M => M
) PORT MAP (
    bcd     => bcd(3 downto 0),
    segment => segment0
);

--instance segment1
u_bcd2segment_1: bcd2segment generic map (
    M => M
) PORT MAP (
    bcd     => bcd(7 downto 4),
    segment => segment1
);

--instance segment2
u_bcd2segment_2: bcd2segment generic map (
    M => M
) PORT MAP (
    bcd     => bcd(11 downto 8),
    segment => segment2
);

end behavioral;
--end of architecture
#############################################################################

No comments:

Post a Comment