1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-05-01 14:16:34 +00:00
Files
Gehstock.Mist_FPGA/Arcade_MiST/Atari Vector/Asteroids/rtl/pace.vhd
2020-05-13 16:01:47 +02:00

306 lines
8.2 KiB
VHDL

--
-- This file is a *derivative* work of MikeJ's Asteroids Deluxe implementation.
-- The original source can be downloaded from <http://www.fpgaarcade.com>
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
library work;
use work.pace_pkg.all;
use work.video_controller_pkg.all;
use work.sprite_pkg.all;
use work.platform_pkg.all;
use work.project_pkg.all;
entity PACE is
port
(
-- clocks and resets
BUTTON : in std_logic_vector(7 downto 0);
clkrst_i : in from_CLKRST_t;
-- misc I/O
buttons_i : in from_BUTTONS_t;
switches_i : in from_SWITCHES_t;
leds_o : out to_LEDS_t;
-- controller inputs
inputs_i : in from_INPUTS_t;
-- video
video_i : in from_VIDEO_t;
video_o : out to_VIDEO_t;
-- audio
audio_i : in from_AUDIO_t;
audio_o : out to_AUDIO_t;
-- custom i/o
project_i : in from_PROJECT_IO_t;
project_o : out to_PROJECT_IO_t;
platform_i : in from_PLATFORM_IO_t;
platform_o : out to_PLATFORM_IO_t
);
end entity PACE;
architecture SYN of PACE is
alias clk_24M : std_logic is clkrst_i.clk(0);
alias clk_video : std_logic is clkrst_i.clk(1);
signal reset_n : std_logic;
alias reset_6_l : std_logic is reset_n;
signal clk_6 : std_logic := '0';
signal audio_s : std_logic_vector(7 downto 0);
signal x_vector : std_logic_vector(9 downto 0);
signal y_vector : std_logic_vector(9 downto 0);
signal z_vector : std_logic_vector(3 downto 0);
signal beam_on : std_logic;
signal beam_ena : std_logic;
-- video generator signals
signal vid_addr : std_logic_vector(15 downto 0);
signal vid_q : std_logic_vector(15 downto 0);
-- video ram signals
signal vram_addr : std_logic_vector(14 downto 0);
signal vram_data : std_logic_vector(7 downto 0);
signal vram_wren : std_logic;
signal vram_q : std_logic_vector(7 downto 0);
signal pixel_data : std_logic_vector(7 downto 0);
signal mapped_inputs : from_MAPPED_INPUTS_t(0 to 1);
alias game_reset : std_logic is mapped_inputs(1).d(0);
alias toggle_erase : std_logic is mapped_inputs(1).d(1);
signal cpu_reset : std_logic;
signal erase : std_logic;
signal to_osd : to_OSD_t;
begin
-- map inputs
reset_n <= not clkrst_i.arst;
-- PLL can't produce a 6M clock
process (clk_24M, clkrst_i.arst)
variable count : std_logic_vector(1 downto 0) := (others => '0');
begin
if clkrst_i.arst = '1' then
count := (others => '0');
clk_6 <= '0';
elsif rising_edge(clk_24M) then
count := count + 1;
clk_6 <= count(1);
end if;
end process;
-- process to toggle erase with <F4>
process (clk_24M, clkrst_i.arst)
variable f4_r : std_logic := '0';
begin
if clkrst_i.arst = '1' then
erase <= '1';
elsif rising_edge(clk_24M) then
if f4_r = '0' and toggle_erase = '1' then
erase <= not erase;
end if;
-- latch for rising_edge detect
f4_r := toggle_erase;
end if;
end process;
-- process to update video ram and do a _crude_ decay
-- decay just wipes one byte of video ram
-- each time a set number of points is displayed
-- given by (count'length - vram_addr'length)
process (clk_24M, reset_6_l)
variable state : integer range 0 to 4;
variable beam_ena_r : std_logic := '0';
variable count : std_logic_vector(15 downto 0);
begin
if reset_6_l = '0' then
state := 0;
beam_ena_r := '0';
count := (others => '0');
elsif rising_edge(clk_24M) then
-- default case
vram_wren <= '0' after 2 ns;
case state is
when 0 =>
-- prepare to draw a pixel if it's on
if beam_on = '1' and beam_ena_r = '0' and beam_ena = '1' then
vram_addr(5 downto 0) <= x_vector(9 downto 4);
vram_addr(14 downto 6) <= not y_vector(9 downto 1);
case x_vector(3 downto 1) is
when "000" => pixel_data <= "00000001";
when "001" => pixel_data <= "00000010";
when "010" => pixel_data <= "00000100";
when "011" => pixel_data <= "00001000";
when "100" => pixel_data <= "00010000";
when "101" => pixel_data <= "00100000";
when "110" => pixel_data <= "01000000";
when others => pixel_data <= "10000000";
end case;
-- only draw if beam intensity is non-zero
if z_vector /= "0000" then
state := 1;
else
state := 3;
end if;
end if;
when 1 =>
state := 2;
when 2 =>
-- do the write-back
vram_data <= pixel_data or vram_q after 2 ns;
vram_wren <= '1' after 2 ns;
state := 3;
when 3 =>
state := 4;
when 4 =>
-- only erase if it's activated
if erase = '1' then
-- latch the 'erase' counter value for vram_addr
vram_addr <= count(count'left downto count'length-vram_addr'length);
-- only erase once per address
if count(count'length-vram_addr'length-1 downto 0) = 0 then
-- erase the whole byte
vram_data <= (others => '0') after 2 ns;
vram_wren <= '1' after 2 ns;
end if;
end if;
count := count + 1;
state := 0;
when others =>
state := 0;
end case;
-- latch for rising-edge detect
beam_ena_r := beam_ena;
end if;
end process;
-- construct the pixel address and data value
--vram_addr(5 downto 0) <= x_vector(9 downto 4);
--vram_addr(14 downto 6) <= not y_vector(9 downto 1);
asteroids_inst : entity work.ASTEROIDS
port map
(
BUTTON => BUTTON,--mapped_inputs(0).d,
--
AUDIO_OUT => audio_s,
--
X_VECTOR => x_vector,
Y_VECTOR => y_vector,
Z_VECTOR => z_vector,
BEAM_ON => beam_on,
BEAM_ENA => beam_ena,
--
RESET_6_L => reset_6_l,
CLK_6 => clk_6
);
vram_inst : entity work.dpram
generic map
(
numwords_a => 32768,
widthad_a => 15
-- pragma translate_off
,init_file => "null32k.hex"
-- pragma translate_on
)
port map
(
-- video interface
clock_a => clk_video,
address_a => vid_addr(14 downto 0),
wren_a => '0',
data_a => (others => 'X'),
q_a => vid_q(7 downto 0),
-- vector-generator interface
clock_b => clk_24M,
address_b => vram_addr(14 downto 0),
wren_b => vram_wren,
data_b => vram_data,
q_b => vram_q
);
BLK_GRAPHICS : block
signal to_tilemap_ctl : to_TILEMAP_CTL_a(1 to PACE_VIDEO_NUM_TILEMAPS);
signal from_tilemap_ctl : from_TILEMAP_CTL_a(1 to PACE_VIDEO_NUM_TILEMAPS);
signal to_bitmap_ctl : to_BITMAP_CTL_a(1 to PACE_VIDEO_NUM_BITMAPS);
signal from_bitmap_ctl : from_BITMAP_CTL_a(1 to PACE_VIDEO_NUM_BITMAPS);
signal to_sprite_reg : to_SPRITE_REG_t;
signal to_sprite_ctl : to_SPRITE_CTL_t;
signal from_sprite_ctl : from_SPRITE_CTL_t;
signal spr0_hit : std_logic;
signal to_graphics : to_GRAPHICS_t;
signal from_graphics : from_GRAPHICS_t;
signal to_osd : to_OSD_t;
signal from_osd : from_OSD_t;
begin
vid_addr <= from_bitmap_ctl(1).a;
to_bitmap_ctl(1).d(15 downto 0) <= vid_q;
graphics_inst : entity work.Graphics
Port Map
(
bitmap_ctl_i => to_bitmap_ctl,
bitmap_ctl_o => from_bitmap_ctl,
tilemap_ctl_i => to_tilemap_ctl,
tilemap_ctl_o => from_tilemap_ctl,
sprite_reg_i => to_sprite_reg,
sprite_ctl_i => to_sprite_ctl,
sprite_ctl_o => from_sprite_ctl,
spr0_hit => spr0_hit,
graphics_i => to_graphics,
graphics_o => from_graphics,
-- OSD
to_osd => to_osd,
from_osd => from_osd,
-- video (incl. clk)
video_i => video_i,
video_o => video_o
);
end block BLK_GRAPHICS;
-- hook up sound
audio_o.ldata(15 downto 8) <= audio_s;
audio_o.ldata(7 downto 0) <= (others => '0');
audio_o.rdata(15 downto 8) <= audio_s;
audio_o.rdata(7 downto 0) <= (others => '0');
end SYN;