記事一覧

野球ゲームをつくる ~ 10.進塁ベース・得点追加の作成

2015年06月03日(水)21時15分

ヒット、フォアボール、ホームランによる塁の状態の変化と得点の追加を作成します。

この野球ゲームの中で、重要なパーツの1つです。

項目が多いので、入力信号・出力信号と分けて考察します。

まず、入力信号です。

1.打者の結果:BATTING
打者の結果によって、塁の状態と得点は変化します。
例えば、ランナー2塁で1塁打が出れば、ランナー1、3塁となり、
2塁打がでれば、ランナー2塁となり1点追加になります。
ということで、状態遷移(ステートマシン)を使用します。
全ての塁の状態と打者の結果の組合せがあるので、組合せのもれがないようにしないといけません。

アウトカウントは 野球ゲームをつくる ~ 6.アウトカウントとチェンジ
でカウントしています。

2.イニングの表裏:SELECTOR
先攻・後攻どちらの攻撃なのか、得点時に必要となります。
得点が相手チームに追加されては困りますよね。

3.チェンジ:CHANGE
チェンジになれば、ランナーはいなくなり、イニングが進みます。
リセットととは違います。

次に出力信号です。

1.塁の状態:RUNNER
2.先攻・後攻の各得点:SCORE1 SCORE2
の2つで充分ですが、

7SegLEDの小数点を
3.どちらの攻撃:TEAM1 TEAM2
かの表示に使用します。

また、得点が入った時にわかりやすいように
4.得点時に点滅用信号:BLINK
を出力します。

野球ゲームをつくる ~ 9.得点表示の点滅 が点滅用モジュールです。

base.vhd

-- BASE
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity BASE is
    port(
        CLK     : in  std_logic;
        RESET   : in  std_logic;
        SELECTOR: in  std_logic;
        CHANGE  : in  std_logic;
        BATTING : in  std_logic_vector(2 downto 0);
        RUNNER  : out std_logic_vector(2 downto 0);
        SCORE1  : out std_logic_vector(3 downto 0);
        SCORE2  : out std_logic_vector(3 downto 0);
        TEAM1   : out std_logic;
        TEAM2   : out std_logic;
        BLINK   : out std_logic
    );
end BASE;

architecture RTL of BASE is
type STATE_TYPE is (S0,S1,S2,S3,S12,S13,S23,S123);
signal STATE    : STATE_TYPE;
signal SCORE1_TMP   : std_logic_vector(3 downto 0);
signal SCORE2_TMP   : std_logic_vector(3 downto 0);
signal RUNNER_TMP   : std_logic_vector(2 downto 0);

begin
    process (CLK,RESET,CHANGE)
    begin
        if (RESET = '0') then
            STATE <= S0;
            SCORE1_TMP <= "0000";
            SCORE2_TMP <= "0000";
        elsif (CHANGE = '0') then    --- 0:3OUTChange
            STATE <= S0;
        elsif (CLK'event and CLK = '0') then
            case (STATE) is
                when S0 =>
                    case (BATTING) is
                        when "001" =>
                            STATE <= S1;
                            BLINK <= '0';
                        when "010" =>
                            STATE <= S2;
                            BLINK <= '0';
                        when "011" =>
                            STATE <= S3;
                            BLINK <= '0';
                        when "100" =>
                            STATE <= S0;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when "101" =>
                            STATE <= S1;
                            BLINK <= '0';
                        when others =>
                            STATE <= S0;
                            BLINK <= '0';
                    end case;
                when S1 =>
                    case (BATTING) is
                        when "001" =>
                            STATE <= S12;
                            BLINK <= '0';
                        when "010" =>
                            STATE <= S23;
                            BLINK <= '0';
                        when "011" =>
                            STATE <= S3;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when "100" =>
                            STATE <= S0;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 2;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 2;
                            end if;
                            BLINK <= '1';
                        when "101" =>
                            STATE <= S12;
                            BLINK <= '0';
                        when others =>
                            STATE <= S1;
                            BLINK <= '0';
                    end case;
                when S2 =>
                    case (BATTING) is
                        when "001" => 
                            STATE <= S13;
                            BLINK <= '0';
                        when "010" =>
                            STATE <= S2;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when "011" =>
                            STATE <= S3;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when "100" =>
                            STATE <= S0;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 2;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 2;
                            end if;
                            BLINK <= '1';
                        when "101" =>
                            STATE <= S12;
                            BLINK <= '0';
                        when others =>
                            STATE <= S2;
                            BLINK <= '0';
                    end case;
                when S3 =>
                    case (BATTING) is
                        when "001" =>
                            STATE <= S1;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when "010" =>
                            STATE <= S2;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when "011" =>
                            STATE <= S3;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when "100" =>
                            STATE <= S0;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 2;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 2;
                            end if;
                            BLINK <= '1';
                        when "101" =>
                            STATE <= S13;
                            BLINK <= '0';
                        when others =>
                            STATE <= S3;
                            BLINK <= '0';
                    end case;
                when S12 =>
                    case (BATTING) is
                        when "001" =>
                            STATE <= S123;
                            BLINK <= '0';
                        when "010" =>
                            STATE <= S23;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when "011" =>
                            STATE <= S3;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when "100" =>
                            STATE <= S0;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 3;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 3;
                            end if;
                            BLINK <= '1';
                        when "101" =>
                            STATE <= S123;
                            BLINK <= '0';
                        when others =>
                            STATE <= S12;
                            BLINK <= '0';
                    end case;
                when S13 =>
                    case (BATTING) is
                        when "001" =>
                            STATE <= S12;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when "010" =>
                            STATE <= S23;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when "011" =>
                            STATE <= S3;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 2;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 2;
                            end if;
                            BLINK <= '1';
                        when "100" =>
                            STATE <= S0;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 3;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 3;
                            end if;
                            BLINK <= '1';
                        when "101" =>
                            STATE <= S123;
                            BLINK <= '0';
                        when others =>
                            STATE <= S13;
                            BLINK <= '0';
                    end case;
                when S23 =>
                    case (BATTING) is
                        when "001" =>
                            STATE <= S13;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when "010" =>
                            STATE <= S2;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 2;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 2;
                            end if;
                            BLINK <= '1';
                        when "011" =>
                            STATE <= S3;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 2;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 2;
                            end if;
                            BLINK <= '1';
                        when "100" =>
                            STATE <= S0;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 3;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 3;
                            end if;
                            BLINK <= '1';
                        when "101" =>
                            STATE <= S123;
                            BLINK <= '0';
                        when others =>
                            STATE <= S23;
                            BLINK <= '0';
                    end case;
                when S123 =>
                    case (BATTING) is
                        when "001" =>
                            STATE <= S123;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when "010" =>
                            STATE <= S23;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 2;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 2;
                            end if;
                            BLINK <= '1';
                        when "011" =>
                            STATE <= S3;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 3;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 3;
                            end if;
                            BLINK <= '1';
                        when "100" =>
                            STATE <= S0;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 4;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 4;
                            end if;
                            BLINK <= '1';
                        when "101" =>
                            STATE <= S123;
                            if (SELECTOR = '0') then
                                SCORE1_TMP <= SCORE1_TMP + 1;
                            else
                                SCORE2_TMP <= SCORE2_TMP + 1;
                            end if;
                            BLINK <= '1';
                        when others =>
                            STATE <= S123;
                            BLINK <= '0';
                    end case;
                when others =>
                    STATE <= S0;
                    BLINK <= '0';
            end case;
        else
        null;
        end if;
    end process;
        
    SCORE1 <= SCORE1_TMP;
    SCORE2 <= SCORE2_TMP;
        
    process(STATE)
    begin
        case (STATE) is
            when S0   => RUNNER_TMP <= "000";
            when S1   => RUNNER_TMP <= "001";
            when S2   => RUNNER_TMP <= "010";
            when S3   => RUNNER_TMP <= "100";
            when S12  => RUNNER_TMP <= "011";
            when S13  => RUNNER_TMP <= "101";
            when S23  => RUNNER_TMP <= "110";
            when S123 => RUNNER_TMP <= "111";
            when others => RUNNER_TMP <= "000";
        end case;
    end process;
    
    RUNNER <= not RUNNER_TMP

    process(RESET,SELECTOR)
    begin
        if (RESET = '0') then
            TEAM1 <= '1';
            TEAM2 <= '1';
        elsif (SELECTOR = '0') then
            TEAM1 <= '0';
            TEAM2 <= '1';
        else
            TEAM1 <= '1';
            TEAM2 <= '0';
        end if;
    end process;
    
    end RTL;

補足説明ですが、

type STATE_TYPE is (S0,S1,S2,S3,S12,S13,S23,S123);

が塁の状態で、
S0:ランナーなし
S1:ランナー1塁
S2:ランナー2塁
・・・・・・
S123:ランナー満塁
です。
省略したものは何になるか想像できますよね。

で、出力信号は下記にしています。
負論理なので、0:点灯 1:消灯です。*1
最上位ビットから3塁、2塁、1塁です。

    process(STATE)
    begin
        case (STATE) is
            when S0   => RUNNER_TMP <= "000";
            when S1   => RUNNER_TMP <= "001";
            when S2   => RUNNER_TMP <= "010";
            when S3   => RUNNER_TMP <= "100";
            when S12  => RUNNER_TMP <= "011";
            when S13  => RUNNER_TMP <= "101";
            when S23  => RUNNER_TMP <= "110";
            when S123 => RUNNER_TMP <= "111";
            when others => RUNNER_TMP <= "000";
        end case;
    end process;
    
    RUNNER <= not RUNNER_TMP

また、

        elsif (CHANGE = '0') then    --- 0:3OUTChange
            STATE <= S0;

チェンジの出力信号は、リセット同様負論理にしています。
野球ゲームをつくる ~ 6.アウトカウントとチェンジ と関連しています。

*1:しつこいですが、電子回路では重要です。