ヒット、フォアボール、ホームランによる塁の状態の変化と得点の追加を作成します。
この野球ゲームの中で、重要なパーツの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
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:しつこいですが、電子回路では重要です。