記事一覧

階層設計で24進カウンタをつくる

2013年06月15日(土)12時30分

24進カウンタをつくる
を階層設計で書き直してみます。

機能を分割して、部品に分けていきます。
その上で部品を組み合わせていけば、他のプログラムにも利用でき、メンテナンスしやすくなり、見通しもよくなります。

同じようなコードを何度も書くなんて嫌ですよね。

で、24進カウンタをつくる
を見ると、
1.クロックの分周
2.カウンタ
3.7セグに表示(デコード)
の3つの機能があります。

また、分けたものをつなぎ合わせる必要がありますが、
4.つなぎ合わせるものが親、階層の上、トップエンティティとなります。

1.クロックの分周 Divider.vhd

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

entity  DIVIDER is
    port(
        CLK         : in  std_logic;
        RESET       : in  std_logic;    
        DIV_CLK_2HZ : out std_logic;
        DIV_CLK_32HZ: out std_logic
    );
end DIVIDER;

architecture RTL of DIVIDER is
    constant CLK_BIT   : integer := 25;    --Osc 33MHz: 25bit
    signal DIV_COUNTER : std_logic_vector(CLK_BIT-1 downto 0);

begin

    process(CLK,RESET)
    begin
        if (RESET = '0') then
            DIV_COUNTER <= (others => '0');
        elsif (CLK'event and CLK = '0') then
            DIV_COUNTER <= DIV_COUNTER + 1;
        end if;
    end process;
    
    DIV_CLK_2HZ <= not DIV_COUNTER(CLK_BIT-2);
    DIV_CLK_32HZ <= not DIV_COUNTER(CLK_BIT-5);

end RTL;

constant文で定数を定義しています。
上の階層、トップエンティティで定義する場合はgeneric文で定義します。*1

2.カウンタ Counter24.vhd

-- 24 Counter with CARRYOUT, Async RESET, and Enable
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity COUNTER24 is
    port(
        DIV_CLK     : in  std_logic;
        RESET       : in  std_logic;
        ENABLE      : in  std_logic;
        COUNT_1DIGIT: out std_logic_vector(3 downto 0);
        COUNT_2DIGIT: out std_logic_vector(3 downto 0);
        CARRYOUT    : out std_logic
    );
end COUNTER24;

architecture RTL of COUNTER24 is
signal COUNT1 : std_logic_vector(3 downto 0);
signal COUNT2 : std_logic_vector(3 downto 0);
signal CARRY1 : std_logic;
signal CARRY2 : std_logic;

begin
    -- 24Counter
    -- Count 1digit : COUNT1
    process(DIV_CLK,RESET)
    begin
        if (RESET = '0') then
            COUNT1 <= (others => '0');
        elsif (DIV_CLK'event and DIV_CLK = '0') then
            if (ENABLE = '1') then
                if (CARRY1 = '1') then
                    COUNT1 <= (others => '0');
                else
                    COUNT1 <= COUNT1 + 1;
                end if;
            end if;
        end if;
    end process;
    
    COUNT_1DIGIT <= COUNT1;
    
    -- Count 2digit : COUNT2
    process(DIV_CLK,RESET)
    begin
        if (RESET = '0') then
            COUNT2 <= (others => '0');
        elsif (DIV_CLK'event and DIV_CLK = '0') then
            if (ENABLE = '1') then    
                if (CARRY1 = '1') then
                    if (COUNT2 = "0010") then
                        COUNT2 <= (others => '0');
                    else
                        COUNT2 <= COUNT2 + 1;
                    end if;
                end if;
            end if;
        end if;
    end process;

    COUNT_2DIGIT <= COUNT2;
    
    -- Carry from 1digit : CARRY1
    process(COUNT1,CARRY2)
    begin
        if (COUNT1 = "1001" or CARRY2 = '1') then
            CARRY1 <= '1';
        else
            CARRY1 <= '0';
        end if;
    end process;

    -- Carry from 2digit : CARRY2
    process(COUNT1, COUNT2)
    begin
        if (COUNT1 = "0011" and COUNT2 = "0010") then
            CARRY2 <= '1';
        else
            CARRY2 <= '0';
        end if;
    end process;
    
    CARRYOUT <= CARRY2;
    
    -- End 24Counter

end RTL;

3.7セグに表示(デコード) Dec_7SegLED.vhd

-- 7Seg Decoder without dp
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity DEC_7SegLED is
    port(
        ENABLE  : in  std_logic;
        RESET   : in  std_logic;
        COUNTER : in  std_logic_vector(3 downto 0);
        LED_7SEG: out std_logic_vector(7 downto 1)
    );
end DEC_7SegLED;

architecture RTL of DEC_7SegLED is
begin

    process (RESET, ENABLE, COUNTER)
    begin
        if (RESET = '0') then
            LED_7SEG <= "1111111";
        elsif (ENABLE = '1') then
            case COUNTER is
                when "0000" => LED_7SEG <= "0000001"; -- 0
                when "0001" => LED_7SEG <= "1001111"; -- 1
                when "0010" => LED_7SEG <= "0010010"; -- 2
                when "0011" => LED_7SEG <= "0000110"; -- 3
                when "0100" => LED_7SEG <= "1001100"; -- 4
                when "0101" => LED_7SEG <= "0100100"; -- 5
                when "0110" => LED_7SEG <= "0100000"; -- 6
                when "0111" => LED_7SEG <= "0001101"; -- 7
                when "1000" => LED_7SEG <= "0000000"; -- 8
                when "1001" => LED_7SEG <= "0000100"; -- 9
                when "1010" => LED_7SEG <= "0001000"; -- A
                when "1011" => LED_7SEG <= "1100000"; -- b
                when "1100" => LED_7SEG <= "0110001"; -- C
                when "1101" => LED_7SEG <= "1000010"; -- d
                when "1110" => LED_7SEG <= "0110000"; -- E
                when "1111" => LED_7SEG <= "0111000"; -- F
                when others => LED_7SEG <= "1111110"; -- '-'
            end case;
        else
            LED_7SEG <= "1111111";
        end if;
    end process;

end RTL;

7Segのbit数がstd_logic_vector(7 downto 1)になっているのは、最下位ビットのdb(小数点)を除いているためです。

4.トップエンティティ Counter24TOP.vhd

-- TOP VHDL of 24 Counter with CARRYOUT, Async RESET, and Enable
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity COUNTER24TOP is
    port(
        CLK      : in  std_logic;
        RESET    : in  std_logic;
        ENABLE   : in  std_logic;
        LED_7SEG1: out std_logic_vector(7 downto 1);
        LED_7SEG2: out std_logic_vector(7 downto 1);
        CARRYOUT : out std_logic
    );
end COUNTER24TOP;

architecture RTL of COUNTER24TOP is

component DIVIDER
    port(
        CLK         : in  std_logic;
        RESET       : in  std_logic;    
        DIV_CLK_2HZ : out std_logic;
        DIV_CLK_32HZ: out std_logic
    );
end component;

component COUNTER24
    port(
        DIV_CLK     : in  std_logic;
        RESET       : in  std_logic;
        ENABLE      : in  std_logic;
        COUNT_1DIGIT: out std_logic_vector(3 downto 0);
        COUNT_2DIGIT: out std_logic_vector(3 downto 0);
        CARRYOUT    : out std_logic
    );
end component;

component DEC_7SegLED
    port(
        ENABLE  : in  std_logic;
        RESET   : in  std_logic;
        COUNTER : in  std_logic_vector(3 downto 0);
        LED_7SEG: out std_logic_vector(7 downto 1)
    );
end component;

signal CLK_2Hz   : std_logic;
signal CLK_32Hz  : std_logic;
signal COUNT_TMP1: std_logic_vector(3 downto 0);
signal COUNT_TMP2: std_logic_vector(3 downto 0);

begin

U1 :DIVIDER      port map (CLK, RESET, CLK_2Hz, open);
U2 :COUNTER24    port map (CLK_2Hz, RESET, ENABLE, COUNT_TMP1, COUNT_TMP2, CARRYOUT);
U3 :DEC_7SegLED  port map (ENABLE, RESET, COUNT_TMP1,LED_7SEG1);
U4 :DEC_7SegLED  port map (ENABLE, RESET, COUNT_TMP2,LED_7SEG2);

end RTL;

信号をつないでいるだけです。
もちろんこのトップエンティティに処理内容を記載してもOKです。

port map の使用していないoutはopenにしています。
使用していない signal文につなげてもかまいません。
port map の in は、不定にできません。*2
port signal '0' '1' などにつなげます。

*1:またのちほど(^_^;)
*2:というか、コンパイルできないはずです。