IPカタログを使ってカウンターを自動生成する / 下位VHDLをcompnent宣言してから実体化する

(テキストとは無関係)

前回はテキストどおりにカウンターを一から記述したが、今度はIPカタログを使って自動生成した。モジュロ48 M、モジュロ10の2つのカウンターを生成して、あとは接続するだけでよい。非常にスッキリ書ける。自前のint_to_seven_seg()函数は引数がnaturalなので、ieee.numeric_std.allを利用してunsignedにキャストしてからto_integer()integerに変換した。動作は前回と同じ。
f:id:ti-nspire:20210710130220p:plain

トップレベル:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.seven_segment_pkg.all;

entity slow_counter is
    port(
        reset_n, clock: in  std_logic;
        seven_seg     : out std_logic_vector(6 downto 0)
    );
end;

architecture rtl of slow_counter is

    component counter_48M is
        PORT(
            aclr : IN  STD_LOGIC;
            clock: IN  STD_LOGIC;
            cout : OUT STD_LOGIC
        );
    end component;
    
    component counter_10 is
        PORT(
            aclr : IN STD_LOGIC ;
            cin  : IN STD_LOGIC ;
            clock: IN STD_LOGIC ;
            q    : OUT STD_LOGIC_VECTOR (3 DOWNTO 0)
        );
    end component;

    signal timer_1_sec: std_logic;
    signal digit      : std_logic_vector(3 downto 0);
    
begin

    c1: counter_48M port map(
        aclr  => not reset_n, -- リセットはLo有意にした。
        clock => clock,
        cout  => timer_1_sec
    );

    c2: counter_10 port map(
        aclr  => not reset_n, -- リセットはLo有意にした。
        cin   => timer_1_sec,
        clock => clock,
        q     => digit
    );
    
    seven_seg <= int_to_seven_seg(to_integer(unsigned(digit)));

end;

f:id:ti-nspire:20210710125927p:plain

genericでモジュールをパラメタライズする

pp.29-31

genericでパラメタライズしておけば、別のモジュールで実体化するときに、そのgenericに別に値を割り当てることができる。

下のコードはほぼテキストのままである。48 MHzクロックをモジュロ48 Mのカウンターでカウントし、それがオーバーフローするたびに(すなわち1秒ごとに)、7セグに表示する値を1インクリメントする。同じようなコードはこれまで何度か実行してきたので難しいところはない。

seven_segment_pkg

library ieee;
use ieee.std_logic_1164.all;

package seven_segment_pkg is
    function int_to_seven_seg(digit: natural range 0 to 9) return std_logic_vector;
end package;

package body seven_segment_pkg is
    function int_to_seven_seg(digit: natural range 0 to 9) return std_logic_vector is
    begin
        case digit is
           --               "gfedabc" アノードコモン
            when 0 => return "1000000";
            when 1 => return "1111100";
            when 2 => return "0100001";
            when 3 => return "0110000";
            when 4 => return "0011100";
            when 5 => return "0010010";
            when 6 => return "0000010";
            when 7 => return "1111000";
            when 8 => return "0000000";
            when 9 => return "0010000";
            when others => return "0111111"; -- ハイフン
        end case;
    end function;
end package body;

本体

library ieee;
use ieee.std_logic_1164.all;
use work.seven_segment_pkg.all;

entity slow_counter is
    generic(
        CLOCK_FREQ: natural := 48e6
    );
    port(
        clock, reset_n: in  std_logic;
        seven_seg     : out std_logic_vector(6 downto 0)
    );
end;

architecture rtl of slow_counter is
    signal digit: natural range 0 to 9;
begin
    process(clock, reset_n)
        constant COUNT_MAX: natural := CLOCK_FREQ - 1;
        variable count: natural range 0 to COUNT_MAX := 0;
    begin
        if reset_n = '0' then -- リセットはLo有意にした。
            count := 0;
            digit <= 0;
        elsif rising_edge(clock) then
            if count < COUNT_MAX then
                count := count + 1;
            else -- 48 MHzカウンターがオーバーフローしたら
                count := 0;
                if digit < 9 then
                    digit <= digit + 1; -- 7セグディスプレイを1インクリメントする。
                else
                    digit <= 0;
                end if;
            end if;
        end if;
    end process;
    seven_seg <= int_to_seven_seg(digit);
end;

属性

pp.28-29

オブジェクトの持つさまざまな属性が読み出せる。ここでは排列要素の最大値を求める。

entity sute_vhdl is
    port(
        num_out: out natural range 0 to 15
    );
end entity;

architecture rtl of sute_vhdl is
    type nat8_vect_t is array(natural range <>) of natural;
    constant SUTE_ARRAY: nat8_vect_t := (1,6,9,1,4,5,6,7,14,8,5,3);
begin

    process(all)
        variable max: natural;
    begin
       -- 排列の'leftは左端のインデックス(ここでは0)。
        max:= SUTE_ARRAY(SUTE_ARRAY'left);
        
       -- 排列の'rangeはインデックスの範囲(ここでは0 to 11)。
        for i in SUTE_ARRAY'range loop
       --for i in 1 to SUTE_ARRAY'right loop -- 先にインデックス0の値を取り出したのでループは1から始めたほうが無駄がない。排列の'rightは右端のインデックス。
       --for i in 1 to SUTE_ARRAY'length - 1 loop -- これも同じ。排列の'lengthは排列の要素数(ここでは12)。
            if SUTE_ARRAY(i) > max then
                max := SUTE_ARRAY(i);
            end if;
        end loop;
        num_out <= max;
    end process;

end architecture;

配列要素の最大値である14 (0b1110)が出力された。
f:id:ti-nspire:20210709064357j:plain:w600