記事一覧

野球ゲームをつくる ~ 5.バッティングルーレットの作成

2013年07月06日(土)20時38分

バッティングルーレットを作ります。

数字が0から9に回るのなら簡単ですが、
野球ゲーム用のルーレットなので、
単純にアウト、ヒット、ホームランの出目を循環させるわけにはいきません。
なぜなら、ヒットの確率が高くなり、ゲーム性が失われてしまいます。

そこで、下図*1のようなルーレットをつくります。

ファイル 100-1.jpg

このようにすれば、ヒットの確率を調整することができます。

では、これをどのようにプログラムするのかというと、
クロックのタイミング*2で、アウト→フォアボール→アウト→アウト→アウト...
と状態を変化させ、ストップがかかったタイミングで出目を確定させればよいのです。

この状態を変化させるには、ステートマシンを使用します。

今回、ノーマルモード*3とチャレンジモード*4用にステートマシンを2つ作って、ヒットの確率を変えてみます。

また、目押し用*5にホームランのタイミングで信号(ASSIST<= '1')が出るようにします。

batting_roullet.vhd

-- Batting Roullet
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity BATTING_ROULLET is
    port(
        CLK         : in  std_logic;
        RESET       : in  std_logic;
        STARTSTOP   : in  std_logic;
        MODE        : in  std_logic;
        BATTING     : out std_logic_vector(2 downto 0);
        ASSIST      : out std_logic
    );
end BATTING_ROULLET;

architecture RTL of BATTING_ROULLET is

type STATE_TYPE is (
    ONEBASE0,ONEBASE1,ONEBASE2,ONEBASE3,ONEBASE4,
    TWOBASE0,TWOBASE1,
    THREEBASE0,THREEBASE1,
    HOMERUN0,HOMERUN1,HOMERUN2,
    FOUR0,FOUR1,FOUR2,FOUR3,FOUR4,
    OUT0,OUT1,OUT2,OUT3,OUT4,OUT5,OUT6,OUT7,OUT8,OUT9,
    OUT10,OUT11,OUT12,OUT13,OUT14,OUT15,OUT16,OUT17,OUT18,OUT19,
    OUT20,OUT21,OUT22,OUT23,
    CHANGE
    );

signal STATE    : STATE_TYPE;

begin
    
    process(CLK,RESET)
    begin
        if (RESET = '0') then
            STATE <= CHANGE;
        elsif(CLK'event and CLK = '0') then
            if (STARTSTOP = '1') then
                if (MODE = '0') then
                    case(STATE) is        -- Normal MODE
                        when CHANGE      => STATE <= OUT0;
                        when OUT0        => STATE <= FOUR0;
                        when FOUR0       => STATE <= OUT1;
                        when OUT1        => STATE <= TWOBASE0;
                        when TWOBASE0    => STATE <= OUT2;
                        when OUT2        => STATE <= OUT3;
                        when OUT3        => STATE <= OUT4;
                        when OUT4        => STATE <= THREEBASE0;
                        when THREEBASE0  => STATE <= OUT5;
                        when OUT5        => STATE <= ONEBASE0;
                        when ONEBASE0    => STATE <= OUT6;
                        when OUT6        => STATE <= FOUR1;
                        when FOUR1       => STATE <= OUT7;
                        when OUT7        => STATE <= ONEBASE1;
                        when ONEBASE1    => STATE <= OUT8;
                        when OUT8        => STATE <= FOUR2;
                        when FOUR2       => STATE <= OUT9;
                        when OUT9        => STATE <= ONEBASE2;
                        when ONEBASE2    => STATE <= OUT10;
                        when OUT10       => STATE <= TWOBASE1;
                        when TWOBASE1    => STATE <= OUT11;
                        when OUT11       => STATE <= OUT12;
                        when OUT12       => STATE <= OUT13;
                        when OUT13       => STATE <= HOMERUN0;
                        when HOMERUN0    => STATE <= OUT14;
                        when OUT14       => STATE <= FOUR3;
                        when FOUR3       => STATE <= OUT15;
                        when OUT15       => STATE <= ONEBASE3;
                        when ONEBASE3    => STATE <= OUT16;
                        when OUT16       => STATE <= FOUR4;
                        when FOUR4       => STATE <= OUT17;
                        when OUT17       => STATE <= ONEBASE4;
                        when ONEBASE4    => STATE <= OUT0;
                        when others      => STATE <= CHANGE;
                    end case;
                else
                    case(STATE) is        -- Challenge MODE
                        when CHANGE      => STATE <= OUT0;
                        when OUT0        => STATE <= OUT1;
                        when OUT1        => STATE <= OUT2;
                        when OUT2        => STATE <= HOMERUN0;
                        when HOMERUN0    => STATE <= OUT3;
                        when OUT3        => STATE <= OUT4;
                        when OUT4        => STATE <= ONEBASE0;
                        when ONEBASE0    => STATE <= OUT5;
                        when OUT5        => STATE <= OUT6;
                        when OUT6        => STATE <= TWOBASE0;
                        when TWOBASE0    => STATE <= OUT7;
                        when OUT7        => STATE <= OUT8;
                        when OUT8        => STATE <= OUT9;
                        when OUT9        => STATE <= THREEBASE0;
                        when THREEBASE0  => STATE <= OUT10;
                        when OUT10       => STATE <= OUT11;
                        when OUT11       => STATE <= OUT12;
                        when OUT12       => STATE <= OUT13;
                        when OUT13       => STATE <= OUT14;
                        when OUT14       => STATE <= HOMERUN1;
                        when HOMERUN1    => STATE <= OUT15;
                        when OUT15       => STATE <= OUT16;
                        when OUT16       => STATE <= FOUR0;
                        when FOUR0       => STATE <= OUT17;
                        when OUT17       => STATE <= OUT18;
                        when OUT18       => STATE <= HOMERUN2;
                        when HOMERUN2    => STATE <= OUT19;
                        when OUT19       => STATE <= OUT20;
                        when OUT20       => STATE <= OUT21;                                                when OUT21       => STATE <= THREEBASE1;
                        when THREEBASE1  => STATE <= OUT22;                                                when OUT22       => STATE <= OUT23;                                                when OUT23       => STATE <= OUT0;
                        when others      => STATE <= CHANGE;
                    end case;
                end if;
            end if;
        end if;
    end process;
    
    process(STATE)
    begin
        case(STATE) is
            when CHANGE        =>
                BATTING <= "110";
                ASSIST <= '0';
            when OUT0        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT1        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT2        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT3        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT4        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT5        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT6        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT7        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT8        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT9        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT10        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT11        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT12        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT13        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT14        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT15        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT16         =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT17        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT18        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT19        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT20        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT21        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT22        =>
                BATTING <= "000";
                ASSIST <= '0';
            when OUT23        =>
                BATTING <= "000";
                ASSIST <= '0';
            when ONEBASE0    =>
                BATTING <= "001";
                ASSIST <= '0';
            when ONEBASE1    =>
                BATTING <= "001";
                ASSIST <= '0';
            when ONEBASE2    =>
                BATTING <= "001";
                ASSIST <= '0';
            when ONEBASE3    =>
                BATTING <= "001";
                ASSIST <= '0';
            when ONEBASE4    =>
                BATTING <= "001";
                ASSIST <= '0';
            when TWOBASE0    =>
                BATTING <= "010";
                ASSIST <= '0';
            when TWOBASE1    =>
                BATTING <= "010";
                ASSIST <= '0';
            when THREEBASE0 =>
                BATTING <= "011";
                ASSIST <= '0';
            when THREEBASE1    =>
                BATTING <= "011";
                ASSIST <= '0';
            when HOMERUN0    =>
                BATTING <= "100";
                ASSIST <= '1';
            when HOMERUN1    =>
                BATTING <= "100";
                ASSIST <= '1';
            when HOMERUN2    =>
                BATTING <= "100";
                ASSIST <= '1';
            when FOUR0        =>
                BATTING <= "101";
                ASSIST <= '0';
            when FOUR1        => 
                BATTING <= "101";
                ASSIST <= '0';
            when FOUR2        =>
                BATTING <= "101";
                ASSIST <= '0';
            when FOUR3        =>
                BATTING <= "101";
                ASSIST <= '0';
            when FOUR4        =>
                BATTING <= "101";
                ASSIST <= '0';
            when others        =>
                BATTING <= "000";
                ASSIST <= '0';
        end case;
    end process;
    
end RTL;

*1:何で作図したらよいかわからなかったので、大げさにもCADで作図しました。
*2:ということは、クロックの速度を変えれば、ルーレットが回る速度が変わります。
*3:ヒットの確率は高いが、シングルヒットが多い
*4:ヒットの確率は低いが、出れば長打になる
*5:ズル用とも

野球ゲームをつくる ~ 4.バッティングルーレットの表示

2013年07月06日(土)11時26分

ルーレットを回し、出目によって、アウトやヒットを決めます。

出目:内容
0:アウト
1:1塁打
2:2塁打
3:3塁打
H:ホームラン
F:フォアボール

また、チェンジも表示する必要があるので、
-:チェンジ
とします。

負論理なので、LEDの出力を反転しています。*1

batting_decorder.vhd

entity BATTING_DECODER is
    port(
        RESET   : in  std_logic;
        COUNTER : in  std_logic_vector(2 downto 0);
        LED     : out std_logic_vector(7 downto 1)
    );
end BATTING_DECODER;

architecture RTL of BATTING_DECODER is
signal LED_TMP  : std_logic_vector(7 downto 1);

begin

    process(RESET,COUNTER)
    begin
        if (RESET = '0') then
            LED_TMP <= "0000000";
        else
            case COUNTER is
                when "000" => LED_TMP <= "1111110"; -- 0
                when "001" => LED_TMP <= "0110000"; -- 1
                when "010" => LED_TMP <= "1101101"; -- 2
                when "011" => LED_TMP <= "1111001"; -- 3
                when "100" => LED_TMP <= "0110111"; -- H
                when "101" => LED_TMP <= "1000111"; -- F
                when "110" => LED_TMP <= "0000001"; -- '-'
                when others => LED_TMP <= "1001111"; -- E
            end case;
        end if;
    end process;

    LED <= not LED_TMP;

end RTL;

この

when others => LED_TMP <= "1001111"; -- E

は、すべての条件を網羅*2していないときは、必須の記述です。

*1:2015.06.09修正しました。
*2:この場合におけるすべての条件とは、000-111ではありません。というのも、VHDLなどの電子回路では、0 1の他に L H Z などが存在するからです。

野球ゲームをつくる ~ 3.スイッチのトグル

2013年07月06日(土)11時04分

ノーマルモードとチャレンジモードの切り替え用に
Tフリップフロップを使用して、スイッチのON OFF をトグルします。

togle.vhd

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

野球ゲームをつくる ~ 2.分周、チャタリング除去

2013年07月04日(木)22時18分

動作の基本となるクロックから分周回路をつくります。

元のクロックは33MHzです。
これから2Hz 8Hz 16Hz 32Hzを作成します。

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_8Hz : out std_logic;
        DIV_CLK_16Hz: 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_8HZ  <= not DIV_COUNTER(CLK_BIT-4);
    DIV_CLK_16HZ <= not DIV_COUNTER(CLK_BIT-5);
    DIV_CLK_32HZ <= not DIV_COUNTER(CLK_BIT-6);

end RTL;

チャタリングは64Hz = 15.625msのサイクルで除去します。
chattering_cut.vhd

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

64Hzのクロックは分周からひっぱってきても良いですが、
遅延を考えると元クロックから作成したほうが良いでしょう。*1

*1:その場合、消費電力の問題が発生します。

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

2013年06月30日(日)19時17分

基板に付属*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:単に私が作れるかどうかということですね

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

2013年06月21日(金)21時51分

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

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

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

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

2013年06月21日(金)19時13分

リーチの時にビンゴのタイミングで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;

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

2013年06月21日(金)17時00分

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

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の出力は負論理なので、最後でデータを反転しています。

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

2013年06月21日(金)10時48分

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

リーチである条件は
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;

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

2013年06月16日(日)20時05分

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

大雑把に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;