任意桁数のBCDカウンターを作る

https://github.com/ti-nspire/VHDL_for_Quartus_Prime/tree/main/counter_bcd

下位VHDLとして10進カウンターを1個だけ作っておいてそれを上位VHDLで何個か実体化して同期連結する。10進カウンター自体はIPカタログで自動生成した。連結数はパラメタライズした。

f:id:ti-nspire:20210715082407p:plain:w400

これが、自動生成された10進カウンターcounter_10.vhd。entityのportだけ見ればよい。

LIBRARY ieee;
USE ieee.std_logic_1164.all;

LIBRARY lpm;
USE lpm.all;

ENTITY counter_10 IS
    PORT
    (
        aclr        : IN STD_LOGIC ;
        cin     : IN STD_LOGIC ;
        clock       : IN STD_LOGIC ;
        cout        : OUT STD_LOGIC ;
        q       : OUT STD_LOGIC_VECTOR (3 DOWNTO 0)
    );
END counter_10;


ARCHITECTURE SYN OF counter_10 IS

    SIGNAL sub_wire0  : STD_LOGIC ;
    SIGNAL sub_wire1  : STD_LOGIC_VECTOR (3 DOWNTO 0);



    COMPONENT lpm_counter
    GENERIC (
        lpm_direction       : STRING;
        lpm_modulus     : NATURAL;
        lpm_port_updown     : STRING;
        lpm_type        : STRING;
        lpm_width       : NATURAL
    );
    PORT (
            aclr    : IN STD_LOGIC ;
            cin : IN STD_LOGIC ;
            clock   : IN STD_LOGIC ;
            cout    : OUT STD_LOGIC ;
            q   : OUT STD_LOGIC_VECTOR (3 DOWNTO 0)
    );
    END COMPONENT;

BEGIN
    cout    <= sub_wire0;
    q    <= sub_wire1(3 DOWNTO 0);

    LPM_COUNTER_component : LPM_COUNTER
    GENERIC MAP (
        lpm_direction => "UP",
        lpm_modulus => 10,
        lpm_port_updown => "PORT_UNUSED",
        lpm_type => "LPM_COUNTER",
        lpm_width => 4
    )
    PORT MAP (
        aclr => aclr,
        cin => cin,
        clock => clock,
        cout => sub_wire0,
        q => sub_wire1
    );



END SYN;

これが、上の10進カウンターを任意の個数だけ同期連結するためのcounter_bcd.vhdl。シンボルの場合は連結数が多いと配線が大変だがVHDLgenerateを使えば実体化、配線が一気にできる。ここでは4桁にした。

library ieee;
use ieee.std_logic_1164.all;

entity counter_bcd is
    generic(
        NUM_BCD: natural := 4 -- BCDカウンターの連結数
    );
    port(
        clr_n: in  std_logic;
        clk  : in  std_logic;
        bcd  : out std_logic_vector(NUM_BCD*4-1 downto 0)
    );
end entity;

architecture rtl of counter_bcd is
    component counter_10 is
        port(
            aclr    : IN STD_LOGIC ;
            cin : IN STD_LOGIC ;
            clock   : IN STD_LOGIC ;
            cout    : OUT STD_LOGIC ;
            q   : OUT STD_LOGIC_VECTOR (3 DOWNTO 0)
        );
    end component;
    
    signal carry_temp: std_logic_vector(NUM_BCD downto 0);
    
begin
    carry_temp(0) <= '1';

    gen: for i in 0 to NUM_BCD-1 generate
        c: counter_10 port map(
            aclr  => not clr_n, -- Lo有意にした。
            cin   => carry_temp(i),
            clock => clk,
            cout  => carry_temp(i+1), 
            q     => bcd(i*4+3 downto i*4)
        );
    end generate;

end architecture;

右端から4ビット単位で一の位、十の位、百の位、千の位: