記事一覧

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

2013年06月16日(日)15時00分

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

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進カウンタ

2013年06月15日(土)21時29分

ルーレットで使用する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)

2013年06月15日(土)15時24分


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

場合、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進カウンタをつくる

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

24進カウンタをつくる

2013年06月14日(金)14時53分

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進カウンタをつくる

2013年06月14日(金)11時59分

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進カウンタをつくる

2013年06月13日(木)23時19分

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:しつこく書いていますが、リセット入力を回路に入れておくのは非常に重要です。

スイッチをトグルする

2013年06月12日(水)16時21分

スイッチを押すたびに、出力が 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;

チャタリングカット

2013年06月12日(水)14時22分

「改訂版 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をクロックする

2013年06月12日(水)00時26分

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乗