記事一覧

野球ゲームをつくる ~ 1.仕様の作成

基板に付属*1する書籍に、野球ゲームのプログラムがありますが、
イマイチわかりずらいので、参考にしつつ、野球ゲームを制作していきます。

で、まずは仕様ですが、基板のポテンシャルをできる限り利用したものにしようと思います。

基本動作は、以下のようにします。

1.ルーレットを回し、アウト、1塁打、2塁打、3塁打、ホームラン、フォアボールの出目を出す。
2.ヒットはそれぞれ進塁する。
例えば、ランナー2塁で、1塁打が出た場合、1、3塁とし、1、2塁とはしない。
3.スリーアウトでチェンジする。

追加仕様(できればという意味です *2 )として、

1.ノーマルモードとチャレンジモードの切り替えをできるようにする。
ノーマルモード:ヒットの確率は高いが、シングルヒットが多い。
チャレンジモード:ヒットの確率は低いが、出れば長打になる。
2.ラッキーセブンのイニングでルーレットアシスト
ヒットが出るタイミングでLEDが点灯する。いわゆる目押しができない人のためのズルです。

で、ボードの割り当てを次のようにします。

ファイル 96-1.jpg

1.チーム1(先攻)の得点スコア:0~F(15)
2.バッティングルーレット、イニング表示
3.チーム2(後攻)の得点スコア:0~F(15)
4.チーム1(先攻)が攻撃中に点灯
5.モード表示、ノーマルモード:消灯 チャレンジモード:点灯
6.チーム2(後攻)が攻撃中に点灯
7.1塁ランナー
8.2塁ランナー
9.3塁ランナー
10.1アウト
11.2アウト
12.ルーレットアシスト:ヒットが出るタイミングで点灯
13.ルーレットのスタート、ストップ
14.ルーレット、イニング数の表示切り替え:押した状態でイニング表示
15.モード切り替え:トグル動作
16.リセット

*1:書籍に基板が付属していると言うべきか
*2:単に私が作れるかどうかということですね

ルーレットをつくる ~ ルーレットの完成

今まで作ったパーツを元にルーレットを組み立てていきます。

まず、いままでのパーツの復習は以下のとおりです。

divider.vhd

oneshot.vhd

slot.vhd

roullet.vhd

reach.vhd

reach_ctl.vhd

bingo_ctl.vhd

ring.vhd

bingo_ast.vhd

dec_7segled.vhd

何やらいっぱいある感じですが、機能に分割しているからです。

で、トップエンティティは次になります。

slot_game.vhd

-- SLOT TOP Entity
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity SLOT_GAME is
    port(
        CLK         : in  std_logic;
        RESET       : in  std_logic;
        SW          : in  std_logic_vector(2 downto 0);
        LED1        : out std_logic_vector(7 downto 1);
        LED2        : out std_logic_vector(7 downto 1);
        LED3        : out std_logic_vector(7 downto 1);
        DOUT        : out std_logic_vector(3 downto 0);
        ASSIST_LED  : out std_logic
    );
end SLOT_GAME;

architecture RTL of SLOT_GAME is

component DIVIDER
    port(
        CLK         : in  std_logic;
        DIV_CLK_2HZ : out std_logic;
        DIV_CLK_8HZ : out std_logic;
        DIV_CLK_16HZ: out std_logic
    );
end component;

component SLOT
    port(
        DIV_CLK     : in  std_logic;
        RESET       : in  std_logic;
        SW          : in  std_logic;
        STOP_OUT    : out std_logic;
        HIT         : out std_logic_vector(3 downto 0)
    );
end component;

component REACH_CTL
    port(
        REACH_CLK: in  std_logic;    -- リーチ状態の点滅用クロック
        STOP1       : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP2       : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP3       : in  std_logic;    -- ルーレットが 0:動 1:止
        HIT1        : in  std_logic_vector(3 downto 0);
        HIT2        : in  std_logic_vector(3 downto 0);
        HIT3        : in  std_logic_vector(3 downto 0);
        LED_CLK1    : out std_logic;    -- 7SegLEDの点滅クロック
        LED_CLK2    : out std_logic;    -- 7SegLEDの点滅クロック
        LED_CLK3    : out std_logic    -- 7SegLEDの点滅クロック
    );
end component;

component BINGO_CTL
    port(
        RESET       : in  std_logic;
        STOP1       : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP2       : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP3       : in  std_logic;    -- ルーレットが 0:動 1:止
        HIT1        : in  std_logic_vector(3 downto 0);
        HIT2        : in  std_logic_vector(3 downto 0);
        HIT3        : in  std_logic_vector(3 downto 0);
        BINGO_STATUS: out std_logic    -- BINGO 0:× 1:○
    );
end component;

component BINGO_AST
    port(
        STOP1       : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP2       : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP3       : in  std_logic;    -- ルーレットが 0:動 1:止
        HIT1        : in  std_logic_vector(3 downto 0);
        HIT2        : in  std_logic_vector(3 downto 0);
        HIT3        : in  std_logic_vector(3 downto 0);
        BINGO_ASSIST: out std_logic    -- BINGO_ASSIST の点滅
    );
end component;

component RING
    port(
        DIV_CLK     : in  std_logic;
        ENABLE      : in  std_logic;
        DOUT        : out std_logic_vector(3 downto 0)
    );
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_8HZ      : std_logic;
signal CLK_16HZ     : std_logic;
signal STOP         : std_logic_vector(2 downto 0);
signal HIT1_TMP     : std_logic_vector(3 downto 0);
signal HIT2_TMP     : std_logic_vector(3 downto 0);
signal HIT3_TMP     : std_logic_vector(3 downto 0);
signal BINGO_STATUS : std_logic;
signal LED_TMP      : std_logic_vector(2 downto 0);

begin

    U1:DIVIDER      port map (CLK,CLK_2HZ,CLK_8HZ,CLK_16HZ);
    S1:SLOT         port map (CLK_16HZ,RESET,SW(0),STOP(0),HIT1_TMP);
    S2:SLOT         port map (CLK_16HZ,RESET,SW(1),STOP(1),HIT2_TMP);
    S3:SLOT         port map (CLK_16HZ,RESET,SW(2),STOP(2),HIT3_TMP);
    U2:REACH_CTL    port map (CLK_2HZ,STOP(0), STOP(1), STOP(2), HIT1_TMP,HIT2_TMP, HIT3_TMP,LED_TMP(0), LED_TMP(1), LED_TMP(2));
    U3:BINGO_CTL    port map (RESET,STOP(0), STOP(1), STOP(2), HIT1_TMP,HIT2_TMP, HIT3_TMP,BINGO_STATUS);
    U4:BINGO_AST    port map (STOP(0),STOP(1), STOP(2), HIT1_TMP,HIT2_TMP, HIT3_TMP,ASSIST_LED);
    U5:RING         port map (CLK_16HZ,BINGO_STATUS,DOUT);
    D1:DEC_7SegLED  port map (LED_TMP(0),'1',HIT1_TMP,LED1);
    D2:DEC_7SegLED  port map (LED_TMP(1),'1',HIT2_TMP,LED2);
    D3:DEC_7SegLED  port map (LED_TMP(2),'1',HIT3_TMP,LED3);

end RTL;

ここで、次のように

    D1:DEC_7SegLED  port map (LED_TMP(0),'1',HIT1_TMP,LED1);
    D2:DEC_7SegLED  port map (LED_TMP(1),'1',HIT2_TMP,LED2);
    D3:DEC_7SegLED  port map (LED_TMP(2),'1',HIT3_TMP,LED3);

RESETに'1'をつなげているのは、
リセットを押した時に7セグが消えずに0を表示させるためです。

チャタリングカットを入れていないのは、
スイッチを一度押せばカウンタは止まってしまうので、
チャタリングを考慮する必要がないからです。

コンパイルした結果が下図です。
ファイル 95-1.jpg

回路図(RTL_VIWER)は下図です。
ファイル 95-2.jpg

ピン配置は下記です。
ファイル 95-3.jpg

ルーレットをつくる ~ ビンゴアシストの作成

リーチの時にビンゴのタイミングでLEDが点灯するようにします。
目押しができないので、つくってみました。ズルと言われれば、それまでですが(^_^;)

reach.vhd を利用しています。

bingo_ast.vhd

-- BINGO ASSIST
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity BINGO_AST is
    port(
        STOP1       : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP2       : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP3       : in  std_logic;    -- ルーレットが 0:動 1:止
        HIT1        : in  std_logic_vector(3 downto 0);
        HIT2        : in  std_logic_vector(3 downto 0);
        HIT3        : in  std_logic_vector(3 downto 0);
        BINGO_ASSIST: out std_logic    -- BINGO_ASSIST
    );
end BINGO_AST;

architecture RTL of BINGO_AST is

component REACH
    port(
        STOP1       : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP2       : in  std_logic;    -- ルーレットが 0:動 1:止
        HIT1        : in  std_logic_vector(3 downto 0);
        HIT2        : in  std_logic_vector(3 downto 0);
        REACH_STATUS: out std_logic    -- リーチ状態 0:× 1:○
    );
end component;

signal REACH_TMP        : std_logic; -- リーチ 0:× 1:○
signal BINGO_TMP        : std_logic; -- ビンゴ 0:× 1:○
signal BINGO_ASSIST_TMP : std_logic;
signal REACH_STATUS     : std_logic_vector(2 downto 0);

begin
    -- どれかの組合せがリーチの時 = リーチ
    REACH_TMP <= REACH_STATUS(0) or REACH_STATUS(1) or REACH_STATUS(2);

    -- 全ての組合せがリーチの時 = ビンゴ
    BINGO_TMP <= REACH_STATUS(0) and REACH_STATUS(1) and REACH_STATUS(2);

    process(BINGO_TMP,REACH_TMP,HIT1,HIT2,HIT3)
    begin
        if(BINGO_TMP = '1') then --ビンゴの時はビンゴアシストのLEDは消す
            BINGO_ASSIST_TMP <= '0';
        else
            if (REACH_TMP = '1' and HIT1 = HIT2 and HIT2 = HIT3) then
                BINGO_ASSIST_TMP <= '1';
            else
                BINGO_ASSIST_TMP <= '0';
            end if;
        end if;
    end process;
    
    -- LEDは負論理なので、反転
    BINGO_ASSIST <= not BINGO_ASSIST_TMP;
    
    U1 : REACH    port map (STOP1, STOP2, HIT1, HIT2, REACH_STATUS(0)); 
    U2 : REACH    port map (STOP2, STOP3, HIT2, HIT3, REACH_STATUS(1)); 
    U3 : REACH    port map (STOP3, STOP1, HIT3, HIT1, REACH_STATUS(2));     
    
end RTL;

ルーレットをつくる ~ ビンゴの判定、動作

ビンゴの判定は簡単です。
全て止まった状態のルーレットが一致していることですね。

bingo_ctl.vhd

-- Bingo Control
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity BINGO_CTL is
    port(
        RESET       : in  std_logic;
        STOP1       : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP2       : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP3       : in  std_logic;    -- ルーレットが 0:動 1:止
        HIT1        : in  std_logic_vector(3 downto 0);
        HIT2        : in  std_logic_vector(3 downto 0);
        HIT3        : in  std_logic_vector(3 downto 0);
        BINGO_STATUS: out std_logic    -- BINGO 0:× 1:○
    );
end BINGO_CTL;

architecture RTL of BINGO_CTL is

signal ALL_STOP     : std_logic;

begin

    ALL_STOP <= STOP1 and STOP2 and STOP3;

    process(RESET,ALL_STOP,HIT1,HIT2,HIT3)
    begin
        if (RESET = '0') then
            BINGO_STATUS <= '0';
        else
            if (ALL_STOP = '1') then
                if (HIT1 = HIT2 and HIT2 = HIT3) then
                    BINGO_STATUS <= '1';
                else
                    BINGO_STATUS <= '0';
                end if;
            else
                BINGO_STATUS <= '0';
            end if;
        end if;
    end process;
    
end RTL;

ビンゴした時の動作ですが、
LEDがくるくる光るようにしてみます。

ファイル 93-1.jpg

ring.vhd

-- Ring Counter
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity RING is
    port(
        DIV_CLK : in  std_logic;
        ENABLE  : in  std_logic;
        DOUT    : out std_logic_vector(3 downto 0)
    );
end RING;

architecture RTL of RING is
    signal DATA : std_logic_vector(3 downto 0);    

begin
    -- Ring Counter
    process(DIV_CLK,ENABLE)
    begin
        if (DIV_CLK'event and DIV_CLK='1') then
            if(ENABLE = '1') then
                DATA(0) <= not (DATA(0) or DATA(1) or DATA(2));
                DATA(1) <= DATA(0);
                DATA(2) <= DATA(1);
                DATA(3) <= DATA(2);
            else
                DATA <= "0000";
            end if;
        end if;
    end process;
    -- Ring Counter end

    DOUT <= not DATA;
    
end RTL;

LEDの出力は負論理なので、最後でデータを反転しています。

ルーレットをつくる ~ リーチの判定、動作

リーチかどうか判定します。

リーチである条件は
1.3個のルーレットの内、止まっている2個が一致
2.3個とも止まっていればリーチではない
で、

リーチの動作は7セグを点滅させます。

1.の判定を reach.vhd で行います。
2.の判定及び点滅を reach_ctl.vhd で行います。

reach.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity REACH is
    port(
        STOP1       : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP2       : in  std_logic;    -- ルーレットが 0:動 1:止
        HIT1        : in  std_logic_vector(3 downto 0);
        HIT2        : in  std_logic_vector(3 downto 0);
        REACH_STATUS: out std_logic     -- リーチ状態 0:× 1:○
    );
end REACH;

architecture RTL of REACH is
    signal STOP_TMP    : std_logic;
    
begin
    
    STOP_TMP <= STOP1 and STOP2;

    process(STOP_TMP,HIT1,HIT2)
    begin
        if (STOP_TMP = '1') then
            if (HIT1 = HIT2) then
                REACH_STATUS <= '1';
            else
                REACH_STATUS <= '0';
            end if;
        else
            REACH_STATUS <= '0';
        end if;
    end process;
    
end RTL;

reach_ctl.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity REACH_CTL is
    port(
        REACH_CLK: in  std_logic;    -- リーチ状態の点滅用クロック
        STOP1    : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP2    : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP3    : in  std_logic;    -- ルーレットが 0:動 1:止
        HIT1     : in  std_logic_vector(3 downto 0);
        HIT2     : in  std_logic_vector(3 downto 0);
        HIT3     : in  std_logic_vector(3 downto 0);
        LED_CLK1 : out std_logic;    -- 7SegLEDの点滅クロック
        LED_CLK2 : out std_logic;    -- 7SegLEDの点滅クロック
        LED_CLK3 : out std_logic     -- 7SegLEDの点滅クロック
    );
end REACH_CTL;

architecture RTL of REACH_CTL is

component REACH
    port(
        STOP1       : in  std_logic;    -- ルーレットが 0:動 1:止
        STOP2       : in  std_logic;    -- ルーレットが 0:動 1:止
        HIT1        : in  std_logic_vector(3 downto 0);
        HIT2        : in  std_logic_vector(3 downto 0);
        REACH_STATUS: out std_logic    -- リーチ状態 0:× 1:○
    );
end component;

signal REACH_STOP   : std_logic_vector(2 downto 0);
signal REACH_STATUS : std_logic_vector(2 downto 0);

begin

    REACH_STOP(0) <= REACH_STATUS(0) and not STOP3;
    REACH_STOP(1) <= REACH_STATUS(1) and not STOP1;
    REACH_STOP(2) <= REACH_STATUS(2) and not STOP2;
    

    process(REACH_STOP)
    begin
        if (REACH_STOP(0) = '1') then
            LED_CLK1 <= REACH_CLK;
            LED_CLK2 <= REACH_CLK;
            LED_CLK3 <= '1';
        elsif (REACH_STOP(1) = '1') then
            LED_CLK2 <= REACH_CLK;
            LED_CLK3 <= REACH_CLK;
            LED_CLK1 <= '1';
        elsif (REACH_STOP(2) = '1') then
            LED_CLK3 <= REACH_CLK;
            LED_CLK1 <= REACH_CLK;
            LED_CLK2 <= '1';
        else
            LED_CLK1 <= '1';
            LED_CLK2 <= '1';
            LED_CLK3 <= '1';
        end if;
    end process;
    
    U1 : REACH    port map (STOP1, STOP2, HIT1, HIT2, REACH_STATUS(0)); 
    U2 : REACH    port map (STOP2, STOP3, HIT2, HIT3, REACH_STATUS(1)); 
    U3 : REACH    port map (STOP3, STOP1, HIT3, HIT1, REACH_STATUS(2));     
    
end RTL;

ルーレットをつくる ~ クロックの分周

ルーレット用の分周をつくります。

大雑把に1Hzをクロックするを利用しました。

クロックがあまり早いと、目押しが難しいので、(私は全然ダメ)、16Hz=62.5ms位にしておきます。リーチとビンゴ用に、2Hz 8Hzも用意しました。

divider.vhd

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

entity  DIVIDER is
    port(
        CLK          : in  std_logic;
        DIV_CLK_2HZ  : out std_logic;
        DIV_CLK_8HZ  : out std_logic;
        DIV_CLK_16HZ : out std_logic
    );
end DIVIDER;

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

begin

    process(CLK)
    begin
        if (CLK'event and CLK = '0') then
            DIV_COUNTER <= DIV_COUNTER + 1;
        end if;
    end process;
    
    DIV_CLK_2HZ  <= not DIV_COUNTER(OSC_BIT-2);
    DIV_CLK_8HZ  <= not DIV_COUNTER(OSC_BIT-4);
    DIV_CLK_16HZ <= not DIV_COUNTER(OSC_BIT-5);
    
end RTL;

ルーレットをつくる ~ ルーレットを止める

ルーレットを止めます。
一旦止まるとリセットが入るまで、動きません。(動いたらルーレットじゃないですね)

oneshot.vhd

-- oneshot
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity ONESHOT is
    port(
        RESET   : in  std_logic;
        SW      : in  std_logic;
        STOP_OUT: out std_logic    -- ストップしているかどうか
    );
end ONESHOT;

architecture RTL of ONESHOT is
    
begin

    process(RESET,SW)
    begin
        if (RESET = '0') then
            STOP_OUT <= '0';
        elsif (SW'event and SW = '0') then
            STOP_OUT <= '1';
        end if;
    end process;

end RTL;

SW'event and SW = '0' で一度STOP_OUT <= '1'になると、
リセットがかかるまで、STOP_OUT <= '0'になりません。
つまり、ルーレットは止まったままになります。

oneshot.vhd とroullet.vhd を組み合わせて、
slot.vhd にします。

slot.vhd

-- slot
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity SLOT is
    port(
        DIV_CLK : in  std_logic;
        RESET   : in  std_logic;
        SW      : in  std_logic;
        STOP_OUT: out std_logic;
        HIT     : out std_logic_vector(3 downto 0)
    );
end SLOT;

architecture RTL of SLOT is

component ONESHOT
    port(
        RESET   : in  std_logic;
        SW      : in  std_logic;
        STOP_OUT: out std_logic
    );
end component;

component ROULLET
    port(
        DIV_CLK : in  std_logic;
        RESET   : in  std_logic;
        STOP_IN : in  std_logic;
        STOP_OUT: out std_logic;
        HIT     : out std_logic_vector(3 downto 0)
    );
end component;

signal STOP_TMP : std_logic;

begin

    U1 :ONESHOT    port map(RESET,SW,STOP_TMP);
    U2 :ROULLET    port map (DIV_CLK,RESET,STOP_TMP,STOP_OUT,HIT);

end RTL;

slot.vhd の回路図です。
ファイル 90-1.jpg

ルーレットを作る ~ 10進カウンタ

ルーレットで使用する10進カウンタをつくります。
roullet.vhd

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

entity ROULLET is
    port(
        DIV_CLK    : in  std_logic;
        RESET      : in  std_logic;
        STOP_IN    : in  std_logic;    -- ルーレットのストップ信号(入力)
        STOP_OUT   : out std_logic;    -- ルーレットが止まっているかどうか
        HIT        : out std_logic_vector(3 downto 0)    -- ルーレットで出た数字
    );
end ROULLET;

architecture RTL of ROULLET is

signal HIT_TMP    : std_logic_vector(3 downto 0);    

begin
    process(DIV_CLK, RESET)
    begin
        if (RESET = '0') then
            HIT_TMP <= (others => '0');
        elsif (DIV_CLK'event and DIV_CLK = '0') then
            if (STOP_IN = '0') then    -- STOP_IN(=ENABLE)
                if (HIT_TMP = "1001") then
                    HIT_TMP <= (others => '0');
                else
                    HIT_TMP <= HIT_TMP + 1;
                end if;
            end if;
        end if;
    end process;
    
    HIT <= HIT_TMP;
    STOP_OUT <= STOP_IN;

end RTL;

動作の概要
DIV_CLKの周期で0-9までカウントアップ
STOP_INに1が入った時のカウント数字をHITとして出力

STOP_OUTはルーレットが止まっているかどうかの状態出力です。リーチ、ビンゴの判定に使用します。

階層設計で24進カウンタをつくる (その2)


階層設計において定義をトップエンティティで行う

場合、generic文を使用します。

クロックの分周 Divider.vhd

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

entity  DIVIDER is
    generic(
        CLK_BIT     : integer
    );

    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

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;

トップエンティティ Counter24top.vhd の違う部分のみ

---
component DIVIDER
    generic(
        CLK_BIT     : integer
    );

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

---
U1    :DIVIDER        
                generic map (25)
                port map (CLK, RESET, CLK_2Hz, open);
---

この方法だと、定数はトップエンティティで指定することになります。

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

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:というか、コンパイルできないはずです。

24進カウンタをつくる

24進カウンタをつくってみます。

厄介なのは1桁目の動作ですね。

すなわち、
2桁目が0,1の場合、9までカウントアップして繰り上がり
2桁目が2の場合、3までカウントアップして繰り上がり
です。

この見方を逆にして、
1桁目は、
1桁目の繰り上がりがある場合、0になり、
1桁目の繰り上がりがない場合、カウントアップする

1桁目の繰り上がりは、
1桁目が9の場合と、
2桁目の繰り上がりがある場合
です。

つまり、繰り上がりをうまく利用すれば、簡単になりそうです。

こんなことができるのは、同時処理*1だからです。

Aの定義の中にBがあり、
Bの定義の中にAがある。

こんな禅問答のような処理ができるのです。

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

entity COUNTER24 is
    port(
        CLK      : in  std_logic;    -- 33MHz
        RESET    : in  std_logic;
        ENABLE   : in  std_logic;
        LED_7SEG1: out std_logic_vector(7 downto 0);
        LED_7SEG2: out std_logic_vector(7 downto 0);
        CARRYOUT : out std_logic
    );
end COUNTER24;

architecture RTL of COUNTER24 is
signal DIV_COUNTER : std_logic_vector(24 downto 0);
signal DIV_CLK     : std_logic;
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
    -- CLK
    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 <= not DIV_COUNTER(23);    -- 2Hz:(23)
                                      -- 1Hz:(24) 4Hz:(22) 8Hz:(21)...

    -- 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 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;

    -- 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

    -- 7seg LED Decoder
   process(COUNT1)
   begin
      case COUNT1 is
         when "0000" => LED_7SEG1 <= "00000011"; -- 0
         when "0001" => LED_7SEG1 <= "10011111"; -- 1
         when "0010" => LED_7SEG1 <= "00100101"; -- 2
         when "0011" => LED_7SEG1 <= "00001101"; -- 3
         when "0100" => LED_7SEG1 <= "10011001"; -- 4
         when "0101" => LED_7SEG1 <= "01001001"; -- 5
         when "0110" => LED_7SEG1 <= "01000001"; -- 6
         when "0111" => LED_7SEG1 <= "00011111"; -- 7
         when "1000" => LED_7SEG1 <= "00000001"; -- 8
         when "1001" => LED_7SEG1 <= "00001001"; -- 9
         when others => LED_7SEG1 <= "01100001"; -- E
      end case;
   end process;

   process(COUNT2)
   begin
      case COUNT2 is
         when "0000" => LED_7SEG2 <= "00000011"; -- 0
         when "0001" => LED_7SEG2 <= "10011111"; -- 1
         when "0010" => LED_7SEG2 <= "00100101"; -- 2
         when "0011" => LED_7SEG2 <= "00001101"; -- 3
         when "0100" => LED_7SEG2 <= "10011001"; -- 4
         when "0101" => LED_7SEG2 <= "01001001"; -- 5
         when "0110" => LED_7SEG2 <= "01000001"; -- 6
         when "0111" => LED_7SEG2 <= "00011111"; -- 7
         when "1000" => LED_7SEG2 <= "00000001"; -- 8
         when "1001" => LED_7SEG2 <= "00001001"; -- 9
         when others => LED_7SEG2 <= "01100001"; -- E
      end case;
   end process;
    -- End 7seg LED Decoder

end RTL;

*1:今まで何気にコードを書いてましたが、説明してないですね。(^_^;)そのうち、書きます。書こうかな。たぶん。いつか。そのうち

60進カウンタをつくる

60進カウンタをつくってみます。

少し工夫が必要なのは、10の桁が 0 1 2 3 4 5 0 1 2... となることと、そのタイミングです。

単純に

if (DIV_CLK'event and DIV_CLK = '0') then
    if (COUNT2 = "0101") then
        COUNT2 <= (others => '0');
    else
        COUNT2 <= COUNT2 + 1;
    end if;
end if;

ではダメで、
1.1桁目が9の時、つまり繰り上がりが発生したときにカウントアップし、
2.5の次を0にする
必要があります。

Enable信号(入力)を入れました。Enable信号が入っているときのみ、カウントします。
つまり、カウントしたり、止めたりできます。

また、拡張性の為、60カウントした時の繰り上がりも入れています。

似たようなコードを何回も書くのも、いい加減疲れて来ました。
そろそろ、階層設計*1で書いた方がいいですね。

-- 60 Counter with Sync RESET
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

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

architecture RTL of COUNTER60 is
signal DIV_COUNTER : std_logic_vector(24 downto 0);
signal DIV_CLK     : std_logic;
signal COUNT1 : std_logic_vector(3 downto 0);
signal COUNT2 : std_logic_vector(3 downto 0);
signal CARRY  : std_logic;

begin

    -- CLK
    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 <= not DIV_COUNTER(23);    -- 2Hz:(23)
                                      -- 1Hz:(24) 4Hz:(22) 8Hz:(21)...
    
    -- 10Counter with AsyncReset
    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 (COUNT1 = "1001") then
                    COUNT1 <= (others => '0');
                else
                    COUNT1 <= COUNT1 + 1;
                end if;
            end if;
        end if;
    end process;

    -- Carry from 1digit
    process(COUNT1)
    begin
        if (COUNT1 = "1001" and ENABLE = '1') then
            CARRY <= '1';
        else
            CARRY <= '0';
        end if;
    end process;
    
    -- 6Counter with AsyncReset
    process(DIV_CLK,RESET)
    begin
        if (RESET = '0') then
            COUNT2 <= (others => '0');
        elsif (DIV_CLK'event and DIV_CLK = '0') then
            if (CARRY = '1' and ENABLE = '1') then
                if (COUNT2 = "0101") then
                    COUNT2 <= (others => '0');
                else
                    COUNT2 <= COUNT2 + 1;
                end if;
            end if;
        end if;
    end process;
    
    -- Carry from 2digit
    process(COUNT1,COUNT2)
    begin
        if (COUNT1 = "1001" and COUNT2 = "0101" and ENABLE = '1') then
            CARRYOUT <= '1';
        else
            CARRYOUT <= '0';
        end if;
    end process;
    
    -- 7seg LED Decoder
    process(COUNT1)
    begin
        case COUNT1 is
            when "0000" => LED_7SEG1 <= "00000011"; -- 0
            when "0001" => LED_7SEG1 <= "10011111"; -- 1
            when "0010" => LED_7SEG1 <= "00100101"; -- 2
            when "0011" => LED_7SEG1 <= "00001101"; -- 3
            when "0100" => LED_7SEG1 <= "10011001"; -- 4
            when "0101" => LED_7SEG1 <= "01001001"; -- 5
            when "0110" => LED_7SEG1 <= "01000001"; -- 6
            when "0111" => LED_7SEG1 <= "00011111"; -- 7
            when "1000" => LED_7SEG1 <= "00000001"; -- 8
            when "1001" => LED_7SEG1 <= "00001001"; -- 9
            when others => LED_7SEG1 <= "01100001"; -- E
        end case;
    end process;

    process(COUNT2)
    begin
        case COUNT2 is
            when "0000" => LED_7SEG2 <= "00000011"; -- 0
            when "0001" => LED_7SEG2 <= "10011111"; -- 1
            when "0010" => LED_7SEG2 <= "00100101"; -- 2
            when "0011" => LED_7SEG2 <= "00001101"; -- 3
            when "0100" => LED_7SEG2 <= "10011001"; -- 4
            when "0101" => LED_7SEG2 <= "01001001"; -- 5
            when "0110" => LED_7SEG2 <= "01000001"; -- 6
            when "0111" => LED_7SEG2 <= "00011111"; -- 7
            when "1000" => LED_7SEG2 <= "00000001"; -- 8
            when "1001" => LED_7SEG2 <= "00001001"; -- 9
            when others => LED_7SEG2 <= "01100001"; -- E
        end case;
    end process;

end RTL;

*1:なんの前触れもなく、階層設計で書くかもしれません(^_^;)

10進カウンタをつくる

10進カウンタです。
7セグLEDで表示します。
33MHz / 2^24 Hz ≒ 1.97Hz でカウントします。
非同期リセットも入れてます。*1

-- 10 Counter with AsyncReset
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Counter10 is
    port(
        CLK      : in std_logic;    -- Osc: 33MHz
        RESET    : in std_logic;
        LED_7SEG : out std_logic_vector(7 downto 0)
    );
end Counter10;

architecture RTL of Counter10 is
signal DIV_COUNTER : std_logic_vector(24 downto 0);
signal DIV_CLK     : std_logic;
signal COUNTER     : std_logic_vector(3 downto 0);

begin
    -- CLK
    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 <= not DIV_COUNTER(23);    -- 2Hz:(23)
                                       -- 1Hz:(24) 4Hz:(22) 8Hz:(21)...
    
    -- 10Counter with AsyncReset
    process(DIV_CLK,RESET)
    begin
        if (RESET = '0') then
            COUNTER <= (others => '0');
        elsif (DIV_CLK'event and DIV_CLK='0') then
            if (COUNTER = "1001") then
                COUNTER <= (others => '0');
            else
                COUNTER <= COUNTER + 1;
            end if;
        end if;
    end process;
    
    -- 7seg LED Decoder
    process(COUNTER)
    begin
        case COUNTER is
            when "0000" => LED_7SEG <= "00000011"; -- 0
            when "0001" => LED_7SEG <= "10011111"; -- 1
            when "0010" => LED_7SEG <= "00100101"; -- 2
            when "0011" => LED_7SEG <= "00001101"; -- 3
            when "0100" => LED_7SEG <= "10011001"; -- 4
            when "0101" => LED_7SEG <= "01001001"; -- 5
            when "0110" => LED_7SEG <= "01000001"; -- 6
            when "0111" => LED_7SEG <= "00011111"; -- 7
            when "1000" => LED_7SEG <= "00000001"; -- 8
            when "1001" => LED_7SEG <= "00001001"; -- 9
            when others => LED_7SEG <= "01100001"; -- E
        end case;
    end process;
    -- 7seg LED Decoder end
    
end RTL;

*1:しつこく書いていますが、リセット入力を回路に入れておくのは非常に重要です。

スイッチをトグルする

スイッチを押すたびに、出力が H L を繰り返す動作(トグル)はよくありますが、
T-Flip Flopを使用します。

回路は非常に単純です。

-- Togle using T-FF
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity TOGLE is
    port(
        TIN     : in  std_logic;
        RESET   : in  std_logic;
        TOUT    : out std_logic
    );
end TOGLE;

architecture RTL of TOGLE is
signal TOUT_TMP   : std_logic;

begin

    -- T-FF
    process(TIN,RESET)
    begin
        if (RESET = '0') then
            TOUT_TMP <= '0';
        elsif (TIN'event and TIN = '0') then
            TOUT_TMP <= not TOUT_TMP;
        end if;
    end process;
    
    TOUT <= TOUT_TMP;

end RTL;

チャタリングカット

「改訂版 FPGAボードで学ぶ論理回路設計」の付属基盤は、チャタリング防止回路(RC回路)がありますが、

ファイル 82-1.jpg

ソフト的にチャタリングを防止してみます。

簡単な方法は、チャタリングがおさまる時間以上のクロックでサンプリングすれば良いのですが、
サンプリングは10ms前後でいいようです。

そこで、33MHz -> 約64Hz 15.625ms の分周をつくってみます。
非同期リセットも入れてます。
負論理です。

-- Chattering CUT rate about 64Hz 15.625ms
-- InPutClock 33MHz
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity CHATTERING_CUT is
    port(
        SW   : in  std_logic;
        CLK  : in  std_logic;
        RESET: in  std_logic;
        COUT : out std_logic
    );
end CHATTERING_CUT;

architecture RTL of CHATTERING_CUT is
    signal DIV_COUNTER : std_logic_vector(24 downto 0);
    signal DIV_CLK_64HZ : std_logic;

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_64HZ <= not DIV_COUNTER(18);
    
    process(DIV_CLK_64HZ)
    begin
        if (DIV_CLK_64HZ'event and DIV_CLK_64HZ ='0') then
            COUT <=  SW;
        end if;
    end process;
    
end RTL;

大雑把に1Hzをクロックする

33MHzのクロックから約1Hzをつくります。

(33,000,000)10 *1 = (1 1111 0111 1000 1010 0100 0000) *2
なので 33MHzは25bit
そこで、33,000,000 / 2^25 *3 を計算すると 0.9834766Hz
1 / 0.9834766Hz ≒ 1.0168秒
まぁ、これくらいなら、よしとしましょうか(^_^;)

ここで、2進数のおさらい

例えば4bitは

0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
---

1bit目に注目すると、0 1 0 1 0 1 0 1...
2bit目に注目すると、0 0 1 1 0 0 1 1...
3bit目に注目すると、0 0 0 0 1 1 1 1...

そうです、パルス、クロックですね。

最上位bitは1/2のサイクルで0,1を繰り返しているので、
25bitの最上位bitが0.9834766Hz、大雑把に1Hzのクロックということです。

また、下に1bitずらしていけば、2Hz 4Hz 8Hz...をつくることができます。

なお、非同期リセットを入れときました。
負論理になっています。

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_1HZ     : out std_logic;
        DIV_CLK_2HZ     : out std_logic;
        DIV_CLK_64HZ    : out std_logic
    );
end DIVIDER;

architecture RTL of DIVIDER is
    signal DIV_COUNTER : std_logic_vector(24 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_1HZ <= not DIV_COUNTER(24);
    DIV_CLK_2HZ <= not DIV_COUNTER(23);
    DIV_CLK_64HZ <= not DIV_COUNTER(18);

end RTL;

*1:10進法の33,000,000という意味です
*2:同様に 2進数の 1 1111 0111 1000 1010 0100 0000 です
*3:2の25乗

正確に1Hzをクロックする

33MHzのクロックから正確に1Hzをつくります。(分周)

クロックは負論理なので、立下りエッジをとっています。

クロックが33MHzということなので、33,000,000 / 2 = 16,500,000回ごとに0,1を交互に出力します。

したがって、立下りエッジが 16,500,000 - 1 = 16,499,999 になったときに出力を反転すればよいことになります。

ちなみに、(16499999)10*1 = (111110111100010100011111)2*2 で24bitです。

-- Divider 33MHz -> 1Hz
-- CLOCK: falling_edge 

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

entity DIVIDER1HZ is
    port(
        CLK : in  std_logic;
        DIV_CLK : out std_logic
    );
end DIVIDER1HZ;

architecture RTL of DIVIDER1HZ is
    signal DIV_COUNTER : std_logic_vector(23 downto 0);
    signal DIV_CLK_TMP : std_logic;

begin

    process(CLK)
    begin
    if (CLK'event and CLK = '0') then
        if (DIV_COUNTER = "111110111100010100011111") then -- 33M/2 - 1
            DIV_COUNTER <= (others => '0');
            DIV_CLK_TMP <= not DIV_CLK_TMP;
        else
            DIV_COUNTER <= DIV_COUNTER + 1;
        end if;
    end if;
    end process;
    
    DIV_CLK <= DIV_CLK_TMP;
    
end RTL;

*1:10進法の16499999という意味です。
*2:同様に2進法の111110111100010100011111です。