Professional Documents
Culture Documents
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity graphics is
port(
clk, not_reset: in std_logic;
nes1_up, nes1_down: in std_logic;
nes2_up, nes2_down: in std_logic;
nes_start: in std_logic;
px_x, px_y: in std_logic_vector(9 downto 0);
video_on: in std_logic;
rgb_stream: out std_logic_vector(2 downto 0);
ball_bounced: out std_logic;
ball_missed: out std_logic
);
end graphics;
architecture dispatcher of graphics is
constant SCREEN_WIDTH: integer := 640;
constant SCREEN_HEIGHT: integer := 480;
type game_states is (start, waiting, playing, game_over);
signal state, state_next: game_states;
type counter_storage is array(0 to 3) of std_logic_vector(17 downto 0);
constant COUNTER_VALUES: counter_storage :=
(
"110010110111001101", -- 208333
"101000101100001011", -- 166667
"100001111010001001", -- 138889
"011101000100001000" -- 119048
);
-- counters to determine ball control frequency
signal ball_control_counter,
ball_control_counter_next: std_logic_vector(17 downto 0);
signal ball_control_value: integer;
-- counts how many times the ball hits the bar
-- used to determine ball speed
signal bounce_counter, bounce_counter_next: std_logic_vector(7 downto 0);
constant MIDDLE_LINE_POS: integer := SCREEN_WIDTH / 2;
signal middle_line_on: std_logic;
signal middle_line_rgb: std_logic_vector(2 downto 0);
signal score_1, score_1_next: std_logic_vector(5 downto 0);
signal score_2, score_2_next: std_logic_vector(5 downto 0);
signal score_on: std_logic;
signal current_score: std_logic_vector(5 downto 0);
signal score_font_addr: std_logic_vector(8 downto 0);
-- message format is "PLAYER p WINS!"
-- where p is replaced by player_id
signal message_on, player_id_on: std_logic;
signal message_font_addr, player_id_font_addr: std_logic_vector(8 downto 0);
signal
signal
signal
signal
bar_pos: integer;
bar_addr: std_logic_vector(5 downto 0);
bar_data: std_logic_vector(0 to BAR_WIDTH - 1);
bar_pixel: std_logic;
bar_rgb: std_logic_vector(2 downto 0);
bar_1_y, bar_1_y_next,
bar_2_y, bar_2_y_next: std_logic_vector(9 downto 0);
--------
P
L
A
Y
E
R
not visibl
-----
W
O
N
!
e
"110111000"
"101111000"
"101110000"
"000001000"
"000000000"
when
when
when
when
when
"0111101"|"0010101",
"0111110"|"0010110",
"0111111"|"0010111",
"1000000"|"0011000",
others;
0 then
+ BAR_WIDTH and
> bar_1_y and
BAR_HEIGHT then
>= ball_x
< (ball_x
>= ball_y
< (ball_y
and
+ BALL_SIZE) and
and
+ BALL_SIZE) else
px_y
(px_x
px_x
px_y
px_y
'0';
ball_addr <= px_y(3 downto 0) - ball_y(3 downto 0);
ball_px_addr <= px_x(3 downto 0) - ball_x(3 downto 0);
ball_pixel <= ball_data(conv_integer(ball_px_addr));
ball_rgb <= "000" when ball_pixel = '1' else "111";
bar_addr <= (px_y(5 downto 0) - bar_1_y(5 downto 0)) when px_x < 320 else
(px_y(5 downto 0) - bar_2_y(5 downto 0));
bar_pos <= BAR_1_POS when px_x < 320 else BAR_2_POS;
bar_pixel <= bar_data(conv_integer(px_x - bar_pos));
bar_rgb <= "000" when bar_pixel = '1' else "111";
process(
ball_on, bar_on,
ball_rgb, bar_rgb,
score_on, message_on, font_rgb,
middle_line_on, middle_line_rgb,
video_on
)
begin
if video_on = '1' then
if bar_on = '1' then
rgb_stream <= bar_rgb;
elsif ball_on = '1' then
rgb_stream <= ball_rgb;
elsif middle_line_on = '1' then
rgb_stream <= middle_line_rgb;
-- scores and messages share rgb stream
elsif score_on = '1' or message_on = '1' then
rgb_stream <= font_rgb;
else
-- background is white
rgb_stream <= "111";
end if;
else
-- blank screen
rgb_stream <= "000";
end if;
end process;
ball_unit:
entity work.ball_rom(content)
port map(addr => ball_addr, data => ball_data);
bar_unit:
entity work.bar_rom(content)
port map(clk => clk, addr => bar_addr, data => bar_data);
font_unit:
entity work.codepage_rom(content)
port map(addr => font_addr, data => font_data);
ball_bounced <= ball_bounce;