mirror of
https://github.com/Gehstock/Mist_FPGA.git
synced 2026-04-26 20:36:47 +00:00
998 lines
34 KiB
VHDL
998 lines
34 KiB
VHDL
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.platform_variant_pkg.all;
|
|
--use work.project_pkg.all;
|
|
|
|
entity platform is
|
|
generic
|
|
(
|
|
NUM_INPUT_BYTES : integer
|
|
);
|
|
port
|
|
(
|
|
-- clocking and reset
|
|
clkrst_i : in from_CLKRST_t;
|
|
cpu_clk_en_i : in std_logic;
|
|
|
|
hwsel : in HWSEL_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_MAPPED_INPUTS_t(0 to NUM_INPUT_BYTES-1);
|
|
|
|
-- graphics
|
|
|
|
bitmap_i : in from_BITMAP_CTL_a(1 to PACE_VIDEO_NUM_BITMAPS);
|
|
bitmap_o : out to_BITMAP_CTL_a(1 to PACE_VIDEO_NUM_BITMAPS);
|
|
|
|
tilemap_i : in from_TILEMAP_CTL_a(1 to PACE_VIDEO_NUM_TILEMAPS);
|
|
tilemap_o : out to_TILEMAP_CTL_a(1 to PACE_VIDEO_NUM_TILEMAPS);
|
|
|
|
sprite_reg_o : out to_SPRITE_REG_t;
|
|
sprite_i : in from_SPRITE_CTL_t;
|
|
sprite_o : out to_SPRITE_CTL_t;
|
|
spr0_hit : in std_logic;
|
|
sprite_rgb : out RGB_t;
|
|
|
|
-- various graphics information
|
|
graphics_i : in from_GRAPHICS_t;
|
|
graphics_o : out to_GRAPHICS_t;
|
|
sound_data_o : out std_logic_vector(7 downto 0);
|
|
|
|
-- 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;
|
|
|
|
dl_addr : in std_logic_vector(11 downto 0);
|
|
dl_data : in std_logic_vector(7 downto 0);
|
|
dl_wr : in std_logic;
|
|
|
|
cpu_rom_addr : out std_logic_vector(16 downto 0);
|
|
cpu_rom_do : in std_logic_vector(7 downto 0);
|
|
gfx1_addr : out std_logic_vector(17 downto 2);
|
|
gfx1_do : in std_logic_vector(31 downto 0);
|
|
gfx2_addr : out std_logic_vector(17 downto 2);
|
|
gfx2_do : in std_logic_vector(31 downto 0);
|
|
gfx3_addr : out std_logic_vector(17 downto 2);
|
|
gfx3_do : in std_logic_vector(31 downto 0)
|
|
);
|
|
|
|
end platform;
|
|
|
|
architecture SYN of platform is
|
|
|
|
alias clk_sys : std_logic is clkrst_i.clk(0);
|
|
alias rst_sys : std_logic is clkrst_i.rst(0);
|
|
alias clk_video : std_logic is clkrst_i.clk(1);
|
|
|
|
-- cpu signals
|
|
signal cpu_clk_en : std_logic;
|
|
signal cpu_a : std_logic_vector(15 downto 0);
|
|
signal cpu_d_i : std_logic_vector(7 downto 0);
|
|
signal cpu_d_o : std_logic_vector(7 downto 0);
|
|
signal cpu_mem_wr : std_logic;
|
|
signal cpu_io_rd : std_logic;
|
|
signal cpu_io_wr : std_logic;
|
|
signal cpu_irq : std_logic;
|
|
signal cpu_intack : std_logic;
|
|
|
|
-- ROM signals
|
|
signal rom_cs : std_logic;
|
|
-- signal rom_d_o : std_logic_vector(7 downto 0);
|
|
|
|
-- keyboard signals
|
|
|
|
-- VRAM signals
|
|
signal vram_cs : std_logic;
|
|
signal vram_wr : std_logic;
|
|
signal vram_d_o : std_logic_vector(7 downto 0);
|
|
|
|
signal snd_cs : std_logic;
|
|
|
|
-- RAM signals
|
|
signal wram_cs : std_logic;
|
|
signal wram_wr : std_logic;
|
|
signal wram_d_o : std_logic_vector(7 downto 0);
|
|
|
|
-- CRAM/SPRITE signals
|
|
signal cram_cs : std_logic;
|
|
signal cram_wr : std_logic;
|
|
signal cram_d_o : std_logic_vector(7 downto 0);
|
|
signal sprite_cs : std_logic;
|
|
|
|
-- text RAM
|
|
signal textram_a : std_logic_vector(11 downto 0);
|
|
signal textram_cs : std_logic;
|
|
signal textram_wr : std_logic;
|
|
signal textram_d_o : std_logic_vector(7 downto 0);
|
|
signal textram_q : std_logic_vector(15 downto 0);
|
|
|
|
-- misc signals
|
|
signal in_cs : std_logic;
|
|
signal in_d_o : std_logic_vector(7 downto 0);
|
|
signal pal_r_wr : std_logic;
|
|
signal pal_g_wr : std_logic;
|
|
signal pal_b_wr : std_logic;
|
|
signal sp_pal_r_wr : std_logic;
|
|
signal sp_pal_g_wr : std_logic;
|
|
signal sp_pal_b_wr : std_logic;
|
|
signal sprite_pal_a : std_logic_vector(7 downto 0);
|
|
signal tilemap1_pal_a : std_logic_vector(7 downto 0);
|
|
signal pal_r_q : std_logic_vector(7 downto 0);
|
|
signal pal_g_q : std_logic_vector(7 downto 0);
|
|
signal pal_b_q : std_logic_vector(7 downto 0);
|
|
|
|
signal pal2_r_wr : std_logic;
|
|
signal pal2_g_wr : std_logic;
|
|
signal pal2_b_wr : std_logic;
|
|
signal pal2_r_q : std_logic_vector(7 downto 0);
|
|
signal pal2_g_q : std_logic_vector(7 downto 0);
|
|
signal pal2_b_q : std_logic_vector(7 downto 0);
|
|
signal tilemap2_pal_a : std_logic_vector(7 downto 0);
|
|
|
|
-- other signals
|
|
signal rst_platform : std_logic;
|
|
signal pause : std_logic;
|
|
signal rot_en : std_logic;
|
|
|
|
-- Lode Runner 2,4
|
|
signal ld2_bankr1 : std_logic_vector(5 downto 0);
|
|
signal ld2_bankr2 : std_logic_vector(7 downto 0);
|
|
signal ld24_bank : std_logic;
|
|
|
|
-- Lode Runner 3
|
|
signal ld3_prot5_cs : std_logic;
|
|
signal ld3_prot7_cs : std_logic;
|
|
|
|
-- Kidniki, Battle Road
|
|
signal kidniki_bank : std_logic_vector(3 downto 0);
|
|
signal kidniki_gfxbank: std_logic;
|
|
|
|
signal spelunk2_palbank : std_logic_vector(1 downto 0);
|
|
signal spelunkr_palbank : std_logic;
|
|
signal spelunk2_bank1 : std_logic_vector(1 downto 0);
|
|
|
|
begin
|
|
|
|
-- handle special keys
|
|
process (clk_sys, rst_sys)
|
|
variable spec_keys_r : std_logic_vector(7 downto 0);
|
|
alias spec_keys : std_logic_vector(7 downto 0) is inputs_i(PACE_INPUTS_NUM_BYTES-1).d;
|
|
variable layer_en : std_logic_vector(4 downto 0);
|
|
begin
|
|
if rst_sys = '1' then
|
|
rst_platform <= '0';
|
|
pause <= '0';
|
|
rot_en <= '0'; -- to default later
|
|
spec_keys_r := (others => '0');
|
|
layer_en := "11111";
|
|
elsif rising_edge(clk_sys) then
|
|
rst_platform <= spec_keys(0);
|
|
if spec_keys_r(1) = '0' and spec_keys(1) = '1' then
|
|
pause <= not pause;
|
|
end if;
|
|
if spec_keys_r(2) = '0' and spec_keys(2) = '1' then
|
|
rot_en <= not rot_en;
|
|
if layer_en = "11111" then
|
|
layer_en := "00001";
|
|
elsif layer_en = "10000" then
|
|
layer_en := "11111";
|
|
else
|
|
layer_en := layer_en(3 downto 0) & layer_en(4);
|
|
end if;
|
|
end if;
|
|
spec_keys_r := spec_keys;
|
|
end if;
|
|
graphics_o.bit8(0)(4 downto 0) <= layer_en;
|
|
end process;
|
|
|
|
--graphics_o.bit8(0)(0) <= rot_en;
|
|
|
|
-- chip select logic
|
|
-- ROM $0000-$7FFF
|
|
-- $0000-$9FFF - LDRUN2, KIDNIKI, SPELUNKR, SPELUNK2
|
|
-- $0000-$BFFF - LDRUN3,4, HORIZON, YOUJYUDN
|
|
-- $A000-$BFFF - BATTROAD
|
|
rom_cs <= '1' when STD_MATCH(cpu_a, "0---------------") else
|
|
'1' when (hwsel = HW_LDRUN2 or hwsel = HW_KIDNIKI or hwsel = HW_SPELUNKR or hwsel = HW_SPELUNK2) and cpu_a(15 downto 13) = "100" else
|
|
'1' when (hwsel = HW_LDRUN3 or hwsel = HW_LDRUN4 or hwsel = HW_HORIZON or hwsel = HW_YOUJYUDN) and cpu_a(15 downto 14) = "10" else
|
|
'1' when hwsel = HW_BATTROAD and cpu_a(15 downto 13) = "101" else
|
|
'0';
|
|
|
|
-- SPRITE $C000-$C0FF
|
|
-- $C000-$C1FF - HORIZON
|
|
sprite_cs <= '1' when cpu_a(15 downto 8) = x"C0" else
|
|
'1' when cpu_a(15 downto 9) = x"C"&"000" and hwsel = HW_HORIZON else
|
|
'0';
|
|
|
|
-- VRAM/CRAM $D000-$DFFF, $A000-$AFFF - KIDNIKI, $A000-$BFFF - SPELUNKR, SPELUNK2
|
|
vram_cs <= '1' when hwsel = HW_KUNGFUM and
|
|
STD_MATCH(cpu_a, X"D"&"0-----------") else
|
|
'1' when hwsel = HW_KIDNIKI and
|
|
STD_MATCH(cpu_a, X"A"&"-----------0") else
|
|
'1' when (hwsel = HW_SPELUNKR or hwsel = HW_SPELUNK2) and
|
|
STD_MATCH(cpu_a, "101------------0") else
|
|
'1' when hwsel /= HW_KUNGFUM and hwsel /= HW_KIDNIKI and
|
|
STD_MATCH(cpu_a, X"D"&"-----------0") else
|
|
'0';
|
|
cram_cs <= '1' when hwsel = HW_KUNGFUM and
|
|
STD_MATCH(cpu_a, X"D"&"1-----------") else
|
|
'1' when hwsel = HW_KIDNIKI and
|
|
STD_MATCH(cpu_a, X"A"&"-----------1") else
|
|
'1' when (hwsel = HW_SPELUNKR or hwsel = HW_SPELUNK2) and
|
|
STD_MATCH(cpu_a, "101------------1") else
|
|
'1' when hwsel /= HW_KUNGFUM and hwsel /= HW_KIDNIKI and
|
|
STD_MATCH(cpu_a, X"D"&"-----------1") else
|
|
'0';
|
|
|
|
-- Text RAM $C800-$CFFF - BATTROAD, SPELUNKR, SPELUNK2, YOUJYUDN $D000-$DFFF - KIDNIKI, $A000-$AFFF - LOTLOT
|
|
textram_cs <= '1' when (hwsel = HW_BATTROAD or hwsel = HW_SPELUNKR or hwsel = HW_SPELUNK2 or hwsel = HW_YOUJYUDN) and
|
|
cpu_a(15 downto 11) = x"C"&'1' else
|
|
'1' when hwsel = HW_KIDNIKI and
|
|
cpu_a(15 downto 12) = x"D" else
|
|
'1' when hwsel = HW_LOTLOT and
|
|
cpu_a(15 downto 12) = x"A" else
|
|
'0';
|
|
|
|
-- RAM $E000-$EFFF
|
|
wram_cs <= '1' when STD_MATCH(cpu_a, X"E"&"------------") else '0';
|
|
|
|
-- OUTPUT $XX00
|
|
snd_cs <= '1' when cpu_a(7 downto 0) = X"00" else '0';
|
|
|
|
-- INPUTS (I/O) $00-$04
|
|
in_cs <= '1' when STD_MATCH(cpu_a(7 downto 0), X"0"&"00--") else
|
|
'1' when STD_MATCH(cpu_a(7 downto 0), X"04") else
|
|
'0';
|
|
|
|
-- Lode Runner 3 protection
|
|
ld3_prot5_cs <= '1' when hwsel = HW_LDRUN3 and cpu_a = x"c800" else '0';
|
|
ld3_prot7_cs <= '1' when hwsel = HW_LDRUN3 and (cpu_a = x"cc00" or cpu_a = x"cfff") else '0';
|
|
|
|
process (clk_sys, rst_sys) begin
|
|
if rst_sys = '1' then
|
|
sound_data_o <= X"00";
|
|
elsif rising_edge(clk_sys) then
|
|
if cpu_clk_en = '1' and cpu_io_wr = '1' and snd_cs = '1' then
|
|
sound_data_o <= cpu_d_o;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-- memory read mux
|
|
cpu_d_i <= in_d_o when (cpu_io_rd = '1' and in_cs = '1') else
|
|
x"05" when ld3_prot5_cs = '1' else
|
|
x"07" when ld3_prot7_cs = '1' else
|
|
cpu_rom_do when rom_cs = '1' else
|
|
vram_d_o when vram_cs = '1' else
|
|
cram_d_o when cram_cs = '1' else
|
|
wram_d_o when wram_cs = '1' else
|
|
textram_d_o when textram_cs = '1' else
|
|
(others => '1');
|
|
|
|
-- memory block write signals
|
|
vram_wr <= vram_cs and cpu_mem_wr;
|
|
cram_wr <= cram_cs and cpu_mem_wr;
|
|
wram_wr <= wram_cs and cpu_mem_wr;
|
|
textram_wr <= textram_cs and cpu_mem_wr;
|
|
|
|
-- sprite registers
|
|
sprite_reg_o.clk <= clk_sys;
|
|
sprite_reg_o.clk_ena <= cpu_clk_en_i;
|
|
sprite_reg_o.a <= cpu_a(8 downto 0) when hwsel = HW_HORIZON else '0' & cpu_a(7 downto 0);
|
|
sprite_reg_o.d <= cpu_d_o;
|
|
sprite_reg_o.wr <= sprite_cs and cpu_mem_wr;
|
|
|
|
--
|
|
-- COMPONENT INSTANTIATION
|
|
--
|
|
|
|
BLK_CPU : block
|
|
signal cpu_rst : std_logic;
|
|
begin
|
|
-- gated CPU signals
|
|
cpu_clk_en <= cpu_clk_en_i and not pause;
|
|
cpu_rst <= rst_sys or rst_platform;
|
|
|
|
cpu_inst : entity work.Z80
|
|
port map
|
|
(
|
|
clk => clk_sys,
|
|
clk_en => cpu_clk_en,
|
|
reset => cpu_rst,
|
|
|
|
addr => cpu_a,
|
|
datai => cpu_d_i,
|
|
datao => cpu_d_o,
|
|
|
|
mem_rd => open,
|
|
mem_wr => cpu_mem_wr,
|
|
io_rd => cpu_io_rd,
|
|
io_wr => cpu_io_wr,
|
|
|
|
intreq => cpu_irq,
|
|
intvec => cpu_d_i,
|
|
intack => cpu_intack,
|
|
nmi => '0'
|
|
);
|
|
|
|
cpu_rom_addr <=
|
|
'0' & "10" & ld24_bank & cpu_a(12 downto 0) when hwsel = HW_LDRUN2 and cpu_a(15) = '1' else
|
|
'0' & '1' & ld24_bank & cpu_a(13 downto 0) when hwsel = HW_LDRUN4 and cpu_a(15) = '1' else
|
|
'1' & kidniki_bank(2 downto 0) & cpu_a(12 downto 0) when hwsel = HW_BATTROAD and cpu_a(15 downto 13) = "101" else
|
|
(kidniki_bank(3 downto 0) + "100") & cpu_a(12 downto 0) when hwsel = HW_KIDNIKI and cpu_a(15 downto 13) = "100" and kidniki_bank(3 downto 2) /= "11" else
|
|
"10" & kidniki_bank(1 downto 0) & cpu_a(12 downto 0) when hwsel = HW_SPELUNKR and cpu_a(15 downto 13) = "100" else
|
|
"010" & spelunk2_bank1 & cpu_a(11 downto 0) when hwsel = HW_SPELUNK2 and cpu_a(15 downto 12) = x"8" else
|
|
'1' & kidniki_bank & cpu_a(11 downto 0) when hwsel = HW_SPELUNK2 and cpu_a(15 downto 12) = x"9" else
|
|
"10" & kidniki_bank(0) & cpu_a(13 downto 0) when hwsel = HW_YOUJYUDN and cpu_a(15 downto 14) = "10" else
|
|
'0' & cpu_a(15 downto 0);
|
|
|
|
-- Lode Runner 2 bank switching - some kind of protection, only the level number is used to select bank 0 or 1 at $8000
|
|
-- writes to $80 (level number)
|
|
-- writes to $81 (unknown, from a table)
|
|
-- reads from $80 (number of times from a table)
|
|
process (clk_sys, rst_sys)
|
|
begin
|
|
if rst_sys = '1' then
|
|
ld2_bankr1 <= (others => '0');
|
|
ld2_bankr2 <= (others => '0');
|
|
ld24_bank <= '0';
|
|
kidniki_bank <= (others => '0');
|
|
kidniki_gfxbank <= '0';
|
|
spelunkr_palbank <= '0';
|
|
spelunk2_bank1 <= (others => '0');
|
|
elsif rising_edge(clk_sys) then
|
|
if cpu_clk_en = '1' and cpu_io_wr = '1' then
|
|
case cpu_a(7 downto 0) is
|
|
when X"80" => ld2_bankr1 <= cpu_d_o(5 downto 0);
|
|
when X"81" => ld2_bankr2 <= cpu_d_o;
|
|
when X"83" => if hwsel = HW_BATTROAD or hwsel = HW_YOUJYUDN then kidniki_bank <= cpu_d_o(3 downto 0); end if;
|
|
when X"84" => if hwsel = HW_KIDNIKI then kidniki_gfxbank <= cpu_d_o(0); end if;
|
|
-- Kidniki banks: 0-7, C-F, 8-B not used
|
|
when X"85" => if hwsel = HW_KIDNIKI then kidniki_bank <= cpu_d_o(3) & (not cpu_d_o(3) and cpu_d_o(2)) & cpu_d_o(1 downto 0); end if;
|
|
when others => null;
|
|
end case;
|
|
end if;
|
|
|
|
if cpu_clk_en = '1' and cpu_io_rd = '1' and cpu_a(7 downto 0) = x"80" then
|
|
if ld2_bankr1 = 6 or ld2_bankr1 = 8 or ld2_bankr1 = 12 or ld2_bankr1 = 13 or ld2_bankr1 = 14 or ld2_bankr1 = 15 or ld2_bankr1 = 16 or
|
|
ld2_bankr1 = 21 or ld2_bankr1 >= 23
|
|
then
|
|
ld24_bank <= '1';
|
|
else
|
|
ld24_bank <= '0';
|
|
end if;
|
|
end if;
|
|
|
|
if cpu_clk_en = '1' and cpu_mem_wr = '1' then
|
|
if cpu_a = x"c800" and hwsel = HW_LDRUN4 then
|
|
ld24_bank <= cpu_d_o(0);
|
|
end if;
|
|
if cpu_a = x"d003" and hwsel = HW_SPELUNK2 then
|
|
kidniki_bank <= cpu_d_o(5 downto 2);
|
|
spelunk2_bank1 <= cpu_d_o(7 downto 6);
|
|
end if;
|
|
if cpu_a = x"d004" and hwsel = HW_SPELUNKR then
|
|
kidniki_bank(1 downto 0) <= cpu_d_o(1 downto 0);
|
|
end if;
|
|
if cpu_a = x"d005" and hwsel = HW_SPELUNKR then
|
|
spelunkr_palbank <= cpu_d_o(0);
|
|
end if;
|
|
end if;
|
|
|
|
end if;
|
|
end process;
|
|
end block BLK_CPU;
|
|
|
|
BLK_INTERRUPTS : block
|
|
|
|
signal vblank_r : std_logic;
|
|
|
|
begin
|
|
|
|
-- generate INT
|
|
process (clk_sys, rst_sys)
|
|
begin
|
|
if rst_sys = '1' then
|
|
cpu_irq <= '0';
|
|
elsif rising_edge(clk_sys) then
|
|
vblank_r <= graphics_i.vblank;
|
|
if vblank_r = '0' and graphics_i.vblank = '1' then
|
|
cpu_irq <= '1';
|
|
end if;
|
|
if cpu_intack = '1' then
|
|
cpu_irq <= '0';
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
end block BLK_INTERRUPTS;
|
|
|
|
BLK_INPUTS : block
|
|
begin
|
|
in_d_o <= inputs_i(0).d when cpu_a(2 downto 0) = "000" else
|
|
inputs_i(1).d when cpu_a(2 downto 0) = "001" else
|
|
inputs_i(2).d when cpu_a(2 downto 0) = "010" else
|
|
inputs_i(3).d when cpu_a(2 downto 0) = "011" else
|
|
inputs_i(4).d;
|
|
end block BLK_INPUTS;
|
|
|
|
BLK_SCROLL : block
|
|
signal m62_hscroll : std_logic_vector(15 downto 0);
|
|
signal m62_vscroll : std_logic_vector(15 downto 0);
|
|
signal m62_vscroll2 : std_logic_vector(15 downto 0);
|
|
signal m62_topbottom_mask: std_logic;
|
|
signal scrollram_d_o : std_logic_vector(15 downto 0);
|
|
signal scrollram_wr : std_logic;
|
|
begin
|
|
horizon_scrollram_inst : entity work.dpram
|
|
generic map
|
|
(
|
|
init_file => "",
|
|
widthad_a => 5,
|
|
width_a => 16,
|
|
widthad_b => 6,
|
|
width_b => 8
|
|
)
|
|
port map
|
|
(
|
|
clock_b => clk_sys,
|
|
address_b => cpu_a(5 downto 0),
|
|
wren_b => scrollram_wr,
|
|
data_b => cpu_d_o,
|
|
q_b => open,
|
|
|
|
clock_a => clk_video,
|
|
address_a => tilemap_i(1).map_a(10 downto 6),
|
|
wren_a => '0',
|
|
data_a => (others => 'X'),
|
|
q_a => scrollram_d_o
|
|
);
|
|
|
|
scrollram_wr <= '1' when cpu_mem_wr = '1' and cpu_a(15 downto 6) = X"C8"&"00" else '0';
|
|
|
|
process (clk_sys, rst_sys)
|
|
begin
|
|
if rst_sys = '1' then
|
|
m62_hscroll <= (others => '0');
|
|
m62_vscroll <= (others => '0');
|
|
m62_vscroll2 <= (others => '0');
|
|
m62_topbottom_mask <= '0';
|
|
spelunk2_palbank <= "00";
|
|
elsif rising_edge(clk_sys) then
|
|
if hwsel = HW_LOTLOT then
|
|
m62_hscroll <= std_logic_vector(to_signed(-64, m62_hscroll'length));
|
|
m62_vscroll <= std_logic_vector(to_unsigned(32, m62_vscroll'length));
|
|
end if;
|
|
if cpu_clk_en = '1' and cpu_mem_wr = '1' then
|
|
case cpu_a is
|
|
when X"A000" =>
|
|
if hwsel = HW_KUNGFUM then
|
|
m62_hscroll(7 downto 0) <= cpu_d_o;
|
|
end if;
|
|
when X"B000" =>
|
|
if hwsel = HW_KUNGFUM then
|
|
m62_hscroll(15 downto 8) <= cpu_d_o;
|
|
end if;
|
|
when x"D000" =>
|
|
if hwsel = HW_SPELUNKR or hwsel = HW_SPELUNK2 then
|
|
m62_vscroll(7 downto 0) <= cpu_d_o;
|
|
end if;
|
|
when x"D001" =>
|
|
if hwsel = HW_SPELUNKR then
|
|
m62_vscroll(15 downto 8) <= cpu_d_o;
|
|
end if;
|
|
if hwsel = HW_SPELUNK2 then
|
|
m62_hscroll(7 downto 0) <= cpu_d_o;
|
|
end if;
|
|
when x"D002" =>
|
|
if hwsel = HW_SPELUNKR then
|
|
m62_hscroll(7 downto 0) <= cpu_d_o;
|
|
end if;
|
|
if hwsel = HW_SPELUNK2 then
|
|
m62_vscroll(8) <= cpu_d_o(0);
|
|
m62_hscroll(8) <= cpu_d_o(1);
|
|
spelunk2_palbank <= cpu_d_o(3 downto 2);
|
|
end if;
|
|
when x"D003" =>
|
|
if hwsel = HW_SPELUNKR then
|
|
m62_hscroll(15 downto 8) <= cpu_d_o;
|
|
end if;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if; -- cpu_wr
|
|
|
|
if cpu_clk_en = '1' and cpu_io_wr = '1' then
|
|
-- background 1 vscroll
|
|
if (hwsel = HW_LDRUN3 or hwsel = HW_BATTROAD) and cpu_a(7 downto 0) = x"80" then
|
|
m62_vscroll(7 downto 0) <= cpu_d_o;
|
|
end if;
|
|
-- background 1 hscroll
|
|
if (hwsel = HW_LDRUN4 and cpu_a(7 downto 0) = x"82") or
|
|
((hwsel = HW_BATTROAD or hwsel = HW_KIDNIKI) and cpu_a(7 downto 0) = x"81") or
|
|
(hwsel = HW_YOUJYUDN and cpu_a(7 downto 0) = x"80") then
|
|
m62_hscroll(15 downto 8) <= cpu_d_o;
|
|
end if;
|
|
if (hwsel = HW_LDRUN4 and cpu_a(7 downto 0) = x"83") or
|
|
(hwsel = HW_BATTROAD and cpu_a(7 downto 0) = x"82") or
|
|
(hwsel = HW_KIDNIKI and cpu_a(7 downto 0) = x"80") or
|
|
(hwsel = HW_YOUJYUDN and cpu_a(7 downto 0) = x"81") then
|
|
m62_hscroll(7 downto 0) <= cpu_d_o;
|
|
end if;
|
|
if hwsel = HW_LDRUN3 and cpu_a(7 downto 0) = x"81" then
|
|
m62_topbottom_mask <= cpu_d_o(0);
|
|
end if;
|
|
-- backrground 2 vscroll
|
|
if hwsel = HW_KIDNIKI and cpu_a(7 downto 0) = x"82" then
|
|
m62_vscroll2(7 downto 0) <= cpu_d_o;
|
|
end if;
|
|
if hwsel = HW_KIDNIKI and cpu_a(7 downto 0) = x"83" then
|
|
m62_vscroll2(15 downto 8) <= cpu_d_o;
|
|
end if;
|
|
|
|
end if;
|
|
end if; -- rising_edge(clk_sys)
|
|
end process;
|
|
graphics_o.bit16(0) <= scrollram_d_o when hwsel = HW_HORIZON else m62_hscroll;
|
|
graphics_o.bit16(1) <= m62_vscroll;
|
|
graphics_o.bit16(2) <= m62_vscroll2;
|
|
end block BLK_SCROLL;
|
|
|
|
|
|
BLK_GFX_ROMS : block
|
|
|
|
type gfx_rom_d_a is array(M62_CHAR_ROM'range) of std_logic_vector(7 downto 0);
|
|
signal chr_rom_d : gfx_rom_d_a;
|
|
type spr_rom_d_a is array(0 to 11) of std_logic_vector(7 downto 0);
|
|
signal spr_rom : spr_rom_d_a;
|
|
|
|
begin
|
|
|
|
-- external background ROMs
|
|
gfx1_addr <=
|
|
'0' & tilemap_i(1).tile_a(14 downto 0) when hwsel = HW_SPELUNKR or hwsel = HW_SPELUNK2 or hwsel = HW_YOUJYUDN else
|
|
'0' & kidniki_gfxbank & tilemap_i(1).tile_a(13 downto 0);
|
|
|
|
tilemap_o(1).tile_d(23 downto 0) <= gfx1_do(7 downto 0) & gfx1_do(15 downto 8) & gfx1_do(23 downto 16);
|
|
|
|
gfx3_addr <= '0' & tilemap_i(2).tile_a(14 downto 0);
|
|
|
|
tilemap_o(2).tile_d(23 downto 0) <= gfx3_do(7 downto 0) & gfx3_do(15 downto 8) & gfx3_do(23 downto 16);
|
|
|
|
-- internal background ROMs
|
|
-- GEN_CHAR_ROMS : for i in M62_CHAR_ROM'range generate
|
|
-- char_rom_inst : entity work.sprom
|
|
-- generic map
|
|
-- (
|
|
-- init_file => "./roms/" &
|
|
-- M62_CHAR_ROM(i) & ".hex",
|
|
-- widthad_a => 13
|
|
-- )
|
|
-- port map
|
|
-- (
|
|
-- clock => clk_video,
|
|
-- address => tilemap_i(1).tile_a(12 downto 0),
|
|
-- q => chr_rom_d(i)
|
|
-- );
|
|
-- end generate GEN_CHAR_ROMS;
|
|
--
|
|
-- tilemap_o(1).tile_d(23 downto 0) <= chr_rom_d(0) & chr_rom_d(1) & chr_rom_d(2);
|
|
|
|
-- external sprite ROMs
|
|
gfx2_addr <= sprite_i.a(15 downto 0);
|
|
sprite_o.d(23 downto 0) <= gfx2_do(7 downto 0) & gfx2_do(15 downto 8) & gfx2_do(23 downto 16);
|
|
|
|
-- internal sprite ROMs
|
|
-- GEN_SPRITE_ROMS : for i in M62_SPRITE_ROM'range generate
|
|
-- sprite_rom_inst : entity work.sprom
|
|
-- generic map
|
|
-- (
|
|
-- init_file => "./roms/" &
|
|
-- M62_SPRITE_ROM(i) & ".hex",
|
|
-- widthad_a => 13
|
|
-- )
|
|
-- port map
|
|
-- (
|
|
-- clock => clk_video,
|
|
-- address(12 downto 5) => sprite_i.a(12 downto 5),
|
|
-- address(4 downto 0) => sprite_i.a(4 downto 0),
|
|
-- q => spr_rom(i)
|
|
-- );
|
|
-- end generate GEN_SPRITE_ROMS;
|
|
--
|
|
-- sprite_o.d(sprite_o.d'left downto 24) <= (others => '0');
|
|
-- sprite_o.d(23 downto 0) <= spr_rom(0) &
|
|
-- spr_rom(1) &
|
|
-- spr_rom(2)
|
|
-- when sprite_i.a(14 downto 13) = "00" else
|
|
-- spr_rom(3) &
|
|
-- spr_rom(4) &
|
|
-- spr_rom(5)
|
|
-- when sprite_i.a(14 downto 13) = "01" else
|
|
-- spr_rom(6) &
|
|
-- spr_rom(7) &
|
|
-- spr_rom(8)
|
|
-- when sprite_i.a(14 downto 13) = "10" else
|
|
-- spr_rom(9) &
|
|
-- spr_rom(10) &
|
|
-- spr_rom(11);
|
|
|
|
end block BLK_GFX_ROMS;
|
|
|
|
BLK_VRAM : block
|
|
signal vram_a : std_logic_vector(11 downto 0);
|
|
alias cram_a : std_logic_vector(11 downto 0) is vram_a;
|
|
begin
|
|
|
|
textram_a <= '0' & cpu_a(10 downto 0) when hwsel = HW_BATTROAD or hwsel = HW_SPELUNKR or hwsel = HW_SPELUNK2 or hwsel = HW_YOUJYUDN else cpu_a(11 downto 0);
|
|
|
|
vram_a <= '0' & cpu_a(10 downto 0) when hwsel = HW_KUNGFUM else
|
|
cpu_a(12 downto 1) when hwsel = HW_SPELUNKR or hwsel = HW_SPELUNK2 else
|
|
'0' & cpu_a(11 downto 1);
|
|
|
|
vram_inst : entity work.dpram
|
|
generic map
|
|
(
|
|
init_file => "",
|
|
widthad_a => 12,
|
|
widthad_b => 12
|
|
)
|
|
port map
|
|
(
|
|
clock_b => clk_sys,
|
|
address_b => vram_a,
|
|
wren_b => vram_wr,
|
|
data_b => cpu_d_o,
|
|
q_b => vram_d_o,
|
|
|
|
clock_a => clk_video,
|
|
address_a => tilemap_i(1).map_a(11 downto 0),
|
|
wren_a => '0',
|
|
data_a => (others => 'X'),
|
|
q_a => tilemap_o(1).map_d(7 downto 0)
|
|
);
|
|
tilemap_o(1).map_d(15 downto 8) <= (others => '0');
|
|
|
|
cram_inst : entity work.dpram
|
|
generic map
|
|
(
|
|
init_file => "",
|
|
widthad_a => 12,
|
|
widthad_b => 12
|
|
)
|
|
port map
|
|
(
|
|
clock_b => clk_sys,
|
|
address_b => cram_a,
|
|
wren_b => cram_wr,
|
|
data_b => cpu_d_o,
|
|
q_b => cram_d_o,
|
|
|
|
clock_a => clk_video,
|
|
address_a => tilemap_i(1).attr_a(11 downto 0),
|
|
wren_a => '0',
|
|
data_a => (others => 'X'),
|
|
q_a => tilemap_o(1).attr_d(7 downto 0)
|
|
);
|
|
tilemap_o(1).attr_d(15 downto 8) <= (others => '0');
|
|
|
|
textram_inst : entity work.dpram
|
|
generic map
|
|
(
|
|
init_file => "",
|
|
widthad_a => 11,
|
|
width_a => 16,
|
|
widthad_b => 12,
|
|
width_b => 8
|
|
)
|
|
port map
|
|
(
|
|
clock_b => clk_sys,
|
|
address_b => textram_a,
|
|
wren_b => textram_wr,
|
|
data_b => cpu_d_o,
|
|
q_b => textram_d_o,
|
|
|
|
clock_a => clk_video,
|
|
address_a => tilemap_i(2).map_a(10 downto 0),
|
|
wren_a => '0',
|
|
data_a => (others => 'X'),
|
|
q_a => textram_q
|
|
);
|
|
|
|
tilemap_o(2).attr_d(7 downto 0) <= textram_q(15 downto 8);
|
|
tilemap_o(2).map_d(7 downto 0) <= textram_q(7 downto 0);
|
|
|
|
end block BLK_VRAM;
|
|
|
|
wram_inst : entity work.spram
|
|
generic map
|
|
(
|
|
widthad_a => 12
|
|
)
|
|
port map
|
|
(
|
|
clock => clk_sys,
|
|
address => cpu_a(11 downto 0),
|
|
data => cpu_d_o,
|
|
wren => wram_wr,
|
|
q => wram_d_o
|
|
);
|
|
|
|
-- tilemap 1 palette address
|
|
tilemap1_pal_a <= spelunkr_palbank & tilemap_i(1).pal_a(6 downto 0) when hwsel = HW_SPELUNKR else
|
|
spelunk2_palbank(0) & tilemap_i(1).pal_a(6 downto 0) when hwsel = HW_SPELUNK2 and tilemap_i(2).set = '0' else
|
|
spelunk2_palbank(0) & tilemap_i(2).pal_a(6 downto 0) when hwsel = HW_SPELUNK2 and tilemap_i(2).set = '1' else
|
|
'0' & tilemap_i(1).pal_a(6 downto 0) when hwsel = HW_BATTROAD else
|
|
tilemap_i(1).pal_a(7 downto 0);
|
|
|
|
-- Spelunk2 uses 512 entries/palette in an odd way:
|
|
-- - red and green are stored in the first two ROMs, using the first and second half bytes
|
|
-- - blue is stored in the third and fourth ROMs, using the second half byte
|
|
|
|
tilemap_o(1).rgb.r(9 downto 2) <= pal_g_q(3 downto 0) & pal_g_q(3 downto 0) when hwsel = HW_SPELUNK2 and spelunk2_palbank(1) = '1' else
|
|
pal_r_q(3 downto 0) & pal_r_q(3 downto 0);
|
|
tilemap_o(1).rgb.g(9 downto 2) <= pal_r_q(7 downto 4) & pal_r_q(7 downto 4) when hwsel = HW_SPELUNK2 and spelunk2_palbank(1) = '0' else
|
|
pal_g_q(7 downto 4) & pal_g_q(7 downto 4) when hwsel = HW_SPELUNK2 and spelunk2_palbank(1) = '1' else
|
|
pal_g_q(3 downto 0) & pal_g_q(3 downto 0);
|
|
tilemap_o(1).rgb.b(9 downto 2) <= pal2_r_q(3 downto 0) & pal2_r_q(3 downto 0) when hwsel = HW_SPELUNK2 and spelunk2_palbank(1) = '1' else
|
|
pal_b_q(3 downto 0) & pal_b_q(3 downto 0);
|
|
|
|
-- tilemap 1 palettes
|
|
pal_r : entity work.dpram
|
|
generic map
|
|
(
|
|
init_file => "",
|
|
widthad_a => 8,
|
|
widthad_b => 8
|
|
)
|
|
port map
|
|
(
|
|
clock_b => clk_sys,
|
|
address_b => dl_addr(7 downto 0),
|
|
wren_b => pal_r_wr,
|
|
data_b => dl_data,
|
|
q_b => open,
|
|
|
|
clock_a => not clk_video,
|
|
address_a => tilemap1_pal_a,
|
|
wren_a => '0',
|
|
data_a => (others => 'X'),
|
|
q_a => pal_r_q
|
|
);
|
|
pal_r_wr <= '1' when dl_wr = '1' and dl_addr(11 downto 8) = x"3" else '0'; -- 300-3FF
|
|
|
|
pal_g : entity work.dpram
|
|
generic map
|
|
(
|
|
init_file => "",
|
|
widthad_a => 8,
|
|
widthad_b => 8
|
|
)
|
|
port map
|
|
(
|
|
clock_b => clk_sys,
|
|
address_b => dl_addr(7 downto 0),
|
|
wren_b => pal_g_wr,
|
|
data_b => dl_data,
|
|
q_b => open,
|
|
|
|
clock_a => not clk_video,
|
|
address_a => tilemap1_pal_a,
|
|
wren_a => '0',
|
|
data_a => (others => 'X'),
|
|
q_a => pal_g_q
|
|
);
|
|
pal_g_wr <= '1' when dl_wr = '1' and dl_addr(11 downto 8) = x"4" else '0'; -- 400-4FF
|
|
|
|
pal_b : entity work.dpram
|
|
generic map
|
|
(
|
|
init_file => "",
|
|
widthad_a => 8,
|
|
widthad_b => 8
|
|
)
|
|
port map
|
|
(
|
|
clock_b => clk_sys,
|
|
address_b => dl_addr(7 downto 0),
|
|
wren_b => pal_b_wr,
|
|
data_b => dl_data,
|
|
q_b => open,
|
|
|
|
clock_a => not clk_video,
|
|
address_a => tilemap1_pal_a,
|
|
wren_a => '0',
|
|
data_a => (others => 'X'),
|
|
q_a => pal_b_q
|
|
);
|
|
pal_b_wr <= '1' when dl_wr = '1' and dl_addr(11 downto 8) = x"5" else '0'; -- 500-5FF
|
|
|
|
-- tilemap 2 palette address
|
|
-- Use this for Spelunk2's second blue ROM, too
|
|
tilemap2_pal_a <= spelunk2_palbank(0) & tilemap_i(1).pal_a(6 downto 0) when hwsel = HW_SPELUNK2 else
|
|
'1' & tilemap_i(2).pal_a(6 downto 0) when hwsel = HW_YOUJYUDN else
|
|
tilemap_i(2).pal_a(7 downto 0);
|
|
|
|
tilemap_o(2).rgb.r(9 downto 2) <= pal2_r_q(7 downto 6) & pal2_r_q(7 downto 6) & pal2_r_q(7 downto 6) & pal2_r_q(7 downto 6) when hwsel = HW_BATTROAD else
|
|
tilemap_o(1).rgb.r(9 downto 2) when hwsel = HW_SPELUNK2 else
|
|
pal2_r_q(3 downto 0) & pal2_r_q(3 downto 0);
|
|
tilemap_o(2).rgb.g(9 downto 2) <= pal2_r_q(5 downto 3) & pal2_r_q(5 downto 3) & pal2_r_q(5 downto 4) when hwsel = HW_BATTROAD else
|
|
tilemap_o(1).rgb.g(9 downto 2) when hwsel = HW_SPELUNK2 else
|
|
pal2_g_q(3 downto 0) & pal2_g_q(3 downto 0);
|
|
tilemap_o(2).rgb.b(9 downto 2) <= pal2_r_q(2 downto 0) & pal2_r_q(2 downto 0) & pal2_r_q(2 downto 1) when hwsel = HW_BATTROAD else
|
|
tilemap_o(1).rgb.b(9 downto 2) when hwsel = HW_SPELUNK2 else
|
|
pal2_b_q(3 downto 0) & pal2_b_q(3 downto 0);
|
|
|
|
-- tilemap 2 palettes
|
|
pal2_r : entity work.dpram
|
|
generic map
|
|
(
|
|
init_file => "",
|
|
widthad_a => 8,
|
|
widthad_b => 8
|
|
)
|
|
port map
|
|
(
|
|
clock_b => clk_sys,
|
|
address_b => dl_addr(7 downto 0),
|
|
wren_b => pal2_r_wr,
|
|
data_b => dl_data,
|
|
q_b => open,
|
|
|
|
clock_a => not clk_video,
|
|
address_a => tilemap2_pal_a,
|
|
wren_a => '0',
|
|
data_a => (others => 'X'),
|
|
q_a => pal2_r_q
|
|
);
|
|
pal2_r_wr <= '1' when dl_wr = '1' and dl_addr(11 downto 8) = x"6" else '0'; -- 600-6FF
|
|
|
|
pal2_g : entity work.dpram
|
|
generic map
|
|
(
|
|
init_file => "",
|
|
widthad_a => 8,
|
|
widthad_b => 8
|
|
)
|
|
port map
|
|
(
|
|
clock_b => clk_sys,
|
|
address_b => dl_addr(7 downto 0),
|
|
wren_b => pal2_g_wr,
|
|
data_b => dl_data,
|
|
q_b => open,
|
|
|
|
clock_a => not clk_video,
|
|
address_a => tilemap2_pal_a,
|
|
wren_a => '0',
|
|
data_a => (others => 'X'),
|
|
q_a => pal2_g_q
|
|
);
|
|
pal2_g_wr <= '1' when dl_wr = '1' and dl_addr(11 downto 8) = x"7" else '0'; -- 700-7FF
|
|
|
|
pal2_b : entity work.dpram
|
|
generic map
|
|
(
|
|
init_file => "",
|
|
widthad_a => 8,
|
|
widthad_b => 8
|
|
)
|
|
port map
|
|
(
|
|
clock_b => clk_sys,
|
|
address_b => dl_addr(7 downto 0),
|
|
wren_b => pal2_b_wr,
|
|
data_b => dl_data,
|
|
q_b => open,
|
|
|
|
clock_a => not clk_video,
|
|
address_a => tilemap2_pal_a,
|
|
wren_a => '0',
|
|
data_a => (others => 'X'),
|
|
q_a => pal2_b_q
|
|
);
|
|
pal2_b_wr <= '1' when dl_wr = '1' and dl_addr(11 downto 8) = x"8" else '0'; -- 800-8FF
|
|
|
|
-- sprite palette address
|
|
sprite_pal_a <= '0' & sprite_i.pal_a(6 downto 0) when
|
|
hwsel = HW_LDRUN or
|
|
hwsel = HW_LDRUN2 or
|
|
hwsel = HW_LDRUN3 or
|
|
hwsel = HW_LDRUN4 or
|
|
hwsel = HW_BATTROAD
|
|
else sprite_i.pal_a;
|
|
|
|
-- sprite palettes
|
|
sp_pal_r : entity work.dpram
|
|
generic map
|
|
(
|
|
init_file => "",
|
|
widthad_a => 8,
|
|
widthad_b => 8
|
|
)
|
|
port map
|
|
(
|
|
clock_b => clk_sys,
|
|
address_b => dl_addr(7 downto 0),
|
|
wren_b => sp_pal_r_wr,
|
|
data_b => dl_data(3 downto 0) & dl_data(3 downto 0),
|
|
q_b => open,
|
|
|
|
clock_a => not clk_video,
|
|
address_a => sprite_pal_a,
|
|
wren_a => '0',
|
|
data_a => (others => '0'),
|
|
q_a => sprite_rgb.r(9 downto 2)
|
|
);
|
|
sp_pal_r_wr <= '1' when dl_wr = '1' and dl_addr(11 downto 8) = x"0" else '0'; -- 000-0FF
|
|
|
|
sp_pal_g : entity work.dpram
|
|
generic map
|
|
(
|
|
init_file => "",
|
|
widthad_a => 8,
|
|
widthad_b => 8
|
|
)
|
|
port map
|
|
(
|
|
clock_b => clk_sys,
|
|
address_b => dl_addr(7 downto 0),
|
|
wren_b => sp_pal_g_wr,
|
|
data_b => dl_data(3 downto 0) & dl_data(3 downto 0),
|
|
q_b => open,
|
|
|
|
clock_a => not clk_video,
|
|
address_a => sprite_pal_a,
|
|
wren_a => '0',
|
|
data_a => (others => '0'),
|
|
q_a => sprite_rgb.g(9 downto 2)
|
|
);
|
|
sp_pal_g_wr <= '1' when dl_wr = '1' and dl_addr(11 downto 8) = x"1" else '0'; -- 100-1FF
|
|
|
|
sp_pal_b : entity work.dpram
|
|
generic map
|
|
(
|
|
init_file => "",
|
|
widthad_a => 8,
|
|
widthad_b => 8
|
|
)
|
|
port map
|
|
(
|
|
clock_b => clk_sys,
|
|
address_b => dl_addr(7 downto 0),
|
|
wren_b => sp_pal_b_wr,
|
|
data_b => dl_data(3 downto 0) & dl_data(3 downto 0),
|
|
q_b => open,
|
|
|
|
clock_a => not clk_video,
|
|
address_a => sprite_pal_a,
|
|
wren_a => '0',
|
|
data_a => (others => '0'),
|
|
q_a => sprite_rgb.b(9 downto 2)
|
|
);
|
|
sp_pal_b_wr <= '1' when dl_wr = '1' and dl_addr(11 downto 8) = x"2" else '0'; -- 200-2FF
|
|
|
|
-- unused outputs
|
|
|
|
sprite_o.ld <= '0';
|
|
--graphics_o <= NULL_TO_GRAPHICS;
|
|
leds_o <= (others => '0');
|
|
|
|
end SYN;
|