1
0
mirror of https://github.com/Gehstock/Mist_FPGA.git synced 2026-01-13 15:17:55 +00:00

Universal Cosmic HW: add Devil Zone and No Mans Land

This commit is contained in:
Gyorgy Szombathelyi 2022-07-03 22:21:54 +02:00
parent a66454a196
commit 95565f66d0
7 changed files with 54339 additions and 66 deletions

View File

@ -1,7 +1,7 @@
# [Arcade: Universal Cosmic](https://www.arcade-museum.com/game_detail.php?game_id=7398) games (Z80-based) originally for [MiSTer](https://github.com/MiSTer-devel/Main_MiSTer/wiki)
By [Mike Coates](https://github.com/macrofpga)
Current Version - 0.9 - 08/07/2021
By [Mike Coates](https://github.com/macrofpga)
Current Version - 1.00 - 03/07/2022
## Description
@ -16,7 +16,9 @@ Up, Down, Left, Right, Fire 1, Fire 2 (not all games use all buttons)
## Games currently supported
* [Cosmic Alien](https://www.arcade-museum.com/game_detail.php?game_id=7398)
* [Devil Zone](https://www.arcade-museum.com/game_detail.php?game_id=7576)
* [Magical Spot](https://www.arcade-museum.com/game_detail.php?game_id=8505)
* [No Mans Land](https://www.arcade-museum.com/game_detail.php?game_id=19281)
* [Space Panic](https://www.arcade-museum.com/game_detail.php?game_id=9676)
## Known differences/problems
@ -25,10 +27,6 @@ Sound effects are all implemented using samples (other than the DAC).
I have added a screen flip option to the sprite code, sprites are flipped by the software on the real hardware, but everything else does have a flip signal. It is implemented as a fake dip switch.
No Man's Land needs the background video lined up properly in all flip modes.
Devil Zone and No Man's Land need sound samples sourced and connected up.
## ROM Files Instructions
- Create ROM and ARC files from the MRA files in the meta directory using the MRA utility.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,7 @@ port
O_SoundStop : out std_logic_vector(15 downto 0);
O_Sound_EN : out std_logic;
O_AUDIO : out std_logic;
O_NML_Speed : out std_logic_vector(1 downto 0);
--
dipsw1 : in std_logic_vector(7 downto 0);
dipsw2 : in std_logic_vector(7 downto 0);
@ -132,6 +133,7 @@ architecture RTL of cosmic is
-- Sound
signal Sound_EN : std_logic := '0';
signal Bomb_Select : std_logic_vector(2 downto 0);
signal BGM : std_logic_vector(1 downto 0) := "00";
-- Hiscore system
signal vid_a_addr : std_logic_vector(12 downto 0);
@ -471,8 +473,14 @@ MMR_Write : process (CLK)
variable address : natural range 0 to 2**15 - 1;
begin
if rising_edge(CLK) then
if (CPU_ENA='1' and mmr_wr='1') then
-- If game resets then software flip can be left incorrectly set
if reset='1' then
Screen_Flip <= '0';
end if;
if (CPU_ENA='1' and mmr_wr='1') then
address := to_integer(unsigned(cpu_addr));
case address is
@ -560,7 +568,7 @@ begin
when 16#7801# => O_SoundPort(3) <= SoundBit;
when others => null;
end case;
elsif (GAME = 2 or GAME = 4 or GAME = 5) then
elsif (GAME = 2) then
-- Magic Spot sound registers
case address is
when 16#4800# => O_AUDIO <= cpu_data_out(7); -- 1 bit DAC
@ -622,6 +630,50 @@ begin
end if;
when others => null;
end case;
elsif (GAME = 4) then
-- Devil Zone sound registers
case address is
when 16#4800# => O_AUDIO <= cpu_data_out(7); -- 1 bit DAC
when 16#4801# => O_SoundPort(1) <= SoundBit; -- High Score
when 16#4803# => O_SoundPort(2) <= SoundBit; -- Explosion
when 16#4804# => O_SoundPort(3) <= SoundBit; -- Fire
when 16#4805# => O_SoundPort(4) <= SoundBit; -- Hit
when 16#4806# => O_SoundPort(5) <= SoundBit; -- Holding noise
when 16#4809# => O_SoundPort(6) <= SoundBit; -- Swoop
when 16#480A# => O_SoundPort(7) <= SoundBit; -- Appear
when 16#480B# => Sound_EN <= cpu_data_out(7);
if (cpu_data_out(7)='0' and Sound_EN='1') then
-- Stop all sounds as well if turning off
O_SoundPort <= "0000000000000000";
O_AUDIO <= '0';
O_SoundStop <= "1111111111111110";
end if;
-- sort rest
when others => null;
end case;
elsif (GAME = 5) then
-- No Mans Land sound registers
case address is
when 16#4800# => O_SoundPort(15) <= SoundBit; -- March (Special support in Samples module)
when 16#4801# => BGM(0) <= SoundBit; -- March Speed Low
when 16#4802# => BGM(1) <= SoundBit; -- March Speed High
when 16#4803# => O_SoundPort(1) <= SoundBit; -- Tank Drive
when 16#4804# => O_SoundPort(2) <= SoundBit; -- Enemy Supplement
when 16#4805# => O_SoundPort(3) <= SoundBit; -- Round Clear
when 16#4806# => O_SoundPort(4) <= SoundBit; -- Fire
when 16#4808# => O_SoundPort(5) <= SoundBit; -- Hit
when 16#4809# => O_SoundPort(6) <= SoundBit; -- Dead
when 16#480A# => O_AUDIO <= cpu_data_out(7); -- 1 bit DAC
when 16#480B# => Sound_EN <= cpu_data_out(7);
if (cpu_data_out(7)='0' and Sound_EN='1') then
-- Stop all sounds as well if turning off
O_SoundPort <= "0000000000000000";
O_AUDIO <= '0';
O_SoundStop <= "1111111111111110";
end if;
-- sort rest
when others => null;
end case;
end if;
end if;
end if;
@ -629,8 +681,8 @@ begin
end if;
end process;
O_Sound_EN <= Sound_EN;
O_Sound_EN <= Sound_EN;
O_NML_Speed <= BGM;
--
-- video subsystem
--

View File

@ -134,10 +134,13 @@ wire [7:0] MagSpot_P4 = {~m_one_player,~m_two_players,dip[5:0]};
wire [7:0] Alien_P1 = {5'd31,~m_left,~m_right,~m_fireA};
wire [7:0] Alien_P2 = {5'd31,~m_left2,~m_right2,~m_fire2A};
wire [7:0] Alien_P3 = {2'd0,VCount[7:2]};
// No Mans Land
wire [7:0] NML_P1 = m_fireA ? 8'hFF : (m_up && m_left ) ? 8'hFE : (m_down && m_left ) ? 8'hFB : (m_down && m_right ) ? 8'hEF : (m_up && m_right ) ? 8'hBF : {~m_up ,1'd1,~m_right ,1'd1,~m_down ,1'd1,~m_left ,1'd1};
wire [7:0] NML_P2 = m_fire2A ? 8'hFF : (m_up2 && m_left2) ? 8'hFE : (m_down2 && m_left2) ? 8'hFB : (m_down2 && m_right2) ? 8'hEF : (m_up2 && m_right2) ? 8'hBF : {~m_up2,1'd1,~m_right2,1'd1,~m_down2,1'd1,~m_left2,1'd1};
// Select correct inputs
wire [7:0] IN0 = (core_mod==1)? Panic_P1 : (core_mod==2 || core_mod==4 || core_mod==5)? MagSpot_P1 : Alien_P1;
wire [7:0] IN1 = (core_mod==1)? Panic_P2 : (core_mod==2 || core_mod==4 || core_mod==5)? MagSpot_P2 : Alien_P2;
wire [7:0] IN0 = (core_mod==1)? Panic_P1 : (core_mod==2 || core_mod==4) ? MagSpot_P1 : (core_mod==5) ? NML_P1 : Alien_P1;
wire [7:0] IN1 = (core_mod==1)? Panic_P2 : (core_mod==2 || core_mod==4) ? MagSpot_P2 : (core_mod==5) ? NML_P2 : Alien_P2;
wire [7:0] IN2 = (core_mod==1)? Panic_P3 : (core_mod==2 || core_mod==4 || core_mod==5)? MagSpot_P3 : Alien_P3;
wire [7:0] DIP = (core_mod==1)? dip[7:0] : MagSpot_P4;
@ -227,6 +230,7 @@ wire hs, vs;
wire [3:0] r,g,b;
wire [8:0] VCount;
wire blank = hblank | vblank;
reg [1:0] BackSpeed;
COSMIC COSMIC
(
@ -251,6 +255,7 @@ COSMIC COSMIC
.O_SoundStop(SoundStop),
.O_AUDIO(audio),
.O_Sound_EN(),
.O_NML_Speed(BackSpeed),
.dipsw1(DIP),
.dipsw2(dip[15:8]),
@ -300,8 +305,8 @@ mist_video #(.COLOR_DEPTH(4), .SD_HCNT_WIDTH(11)) mist_video(
// Samples
wire [24:0] table_offset = core_mod == 3 ? 24'd29696 : 24'd26656;
wire [24:0] wav_offset = table_offset + 8'd128;
wire [24:0] table_offset = core_mod == 5 ? 24'd30720 : core_mod == 4 ? 24'd30752 : core_mod == 3 ? 24'd29696 : 24'd26656;
wire [24:0] wav_offset = table_offset + (core_mod == 5 ? 8'd192 : 8'd128);
wire wav_download = ioctl_downl && (ioctl_index == 0) && ioctl_addr >= wav_offset;
reg [24:0] wav_addr;
@ -351,11 +356,13 @@ samples samples
.dl_data(ioctl_dout),
.dl_download(samples_download),
.NML_Speed(BackSpeed),
.CLK_SYS(clk_sys),
.clock(clk_vid),
.reset(reset),
.audio_in({2'b00, audio, 13'd0}),
.audio_in({1'b0, {11{audio}}, 3'd0}),
.audio_out_L(samples_left),
.audio_out_R(samples_right)
);

View File

@ -64,8 +64,13 @@ signal op_ad2 : std_logic_vector(10 downto 0);
signal op_addr : std_logic_vector(10 downto 0);
-- Sprites
type LBA is array (0 to 1,0 to 255) of std_logic_vector(2 downto 0);
signal linebuffer : LBA;
signal linebuffer_wraddr : std_logic_vector(8 downto 0);
signal linebuffer_wr : std_logic;
signal linebuffer_wr_data : std_logic_vector(2 downto 0);
signal linebuffer_clr : std_logic;
signal linebuffer_rdaddr : std_logic_vector(8 downto 0);
signal SP : std_logic_vector(2 downto 0);
type SA is array (0 to 7) of std_logic_vector(7 downto 0);
signal Sprite_N : SA;
@ -172,7 +177,25 @@ begin
address_b => op_ad2,
q_b => op_pix2
);
linebuffer : entity work.dpram
generic map (
addr_width => 9,
data_width => 3
)
port map (
q_a => SP,
data_a => "000",
address_a => linebuffer_rdaddr,
wren_a => linebuffer_clr,
clock => not CLK,
address_b => linebuffer_wraddr,
data_b => linebuffer_wr_data,
wren_b => linebuffer_wr,
q_b => open
);
-- Load pallette array
pallette : process
variable Entry, Color : integer;
@ -526,13 +549,25 @@ begin
if (I_VCNT(8)='1' and (I_HCNT(8)='1' or I_HCNT="011111110"or I_HCNT="011111111")) then
-- Get corrected Horizontal and Vertical counters (H in 2 pixels time)
if I_FLIP='0' then
X1 := "0000000010" + unsigned(I_HCNT(7 downto 0));
X2(8 downto 0) := unsigned(I_VCNT);
-- Hardware flip needs offset each mode (real hardware doesn't have it, just cocktail flip)
if I_H_FLIP='0' then
-- Get corrected Horizontal and Vertical counters (H in 2 pixels time)
if I_S_FLIP='0' then
X1 := "0000000010" + unsigned(I_HCNT(7 downto 0));
X2(8 downto 0) := unsigned(I_VCNT);
else
X1 := 511 - ("0000000000" + unsigned(I_HCNT(7 downto 0)));
X2(8 downto 0) := 511 - unsigned(I_VCNT);
end if;
else
X1 := 511 - ("0000000010" + unsigned(I_HCNT(7 downto 0)));
X2(8 downto 0) := 511 - unsigned(I_VCNT);
-- Hardware Flip On - so software flip does the opposite
if I_S_FLIP='1' then
X1 := "0000000010" + unsigned(I_HCNT(7 downto 0)) + 2;
X2(8 downto 0) := unsigned(I_VCNT);
else
X1 := 511 - ("0000000010" + unsigned(I_HCNT(7 downto 0)));
X2(8 downto 0) := 511 - unsigned(I_VCNT);
end if;
end if;
@ -551,7 +586,7 @@ begin
-- Water
if X1(7 downto 4)="1010" then
op_addr <= "01" & std_logic_vector(Riverframe) & X1(7);
op_addr <= "01" & std_logic_vector(Riverframe) & X1(3);
River <= '1' & std_logic_vector(X1(2 downto 0));
end if;
@ -574,7 +609,7 @@ begin
if plane1='1' and plane2='1' then back_red <= "1111"; end if;
if plane1='1' or Plane2='1' then back_green <= "1111"; end if;
if plane1='0' then back_blue <= "1111"; end if;
if plane1='0' and op_addr(0)='1' then back_blue <= "1111"; end if;
end if;
@ -600,13 +635,21 @@ end process;
-- hardware supports 8 sprites in 16x16 or 32x32
sprite_draw : process
variable V_OFF,H_OFF : integer;
variable SP : std_logic_vector(2 downto 0);
variable pixel : std_logic_vector(1 downto 0);
variable Entry : integer;
variable Color : integer;
begin
wait until rising_edge(CLK);
linebuffer_wr <= '0';
linebuffer_clr <= '0';
if I_H_FLIP='0' then
H_OFF := to_integer(unsigned(I_HCNT(7 downto 0))) + 1;
else
H_OFF := 254-to_integer(unsigned(I_HCNT(7 downto 0))); -- Was 255
end if;
linebuffer_rdaddr <= std_logic_vector((not sprite_buffer)&""&to_unsigned(H_OFF,8));
if (PIX_CLK = '1') then
if (I_HCNT = "011111110") then
@ -698,33 +741,18 @@ begin
Entry := to_integer(unsigned(not Sprite_C(sprite)(2 downto 0)));
Color := to_integer(unsigned(pixel));
if (sprite_buffer='0') then
linebuffer(0,sprite_pos) <= Colour_P(Entry,Color)(2 downto 0);
else
linebuffer(1,sprite_pos) <= Colour_P(Entry,Color)(2 downto 0);
end if;
linebuffer_wraddr <= std_logic_vector(sprite_buffer&""&to_unsigned(sprite_pos,8));
linebuffer_wr_data <= Colour_P(Entry,Color)(2 downto 0);
linebuffer_wr <= '1';
end if;
end if;
-- Read and clear other buffer for drawing
if (I_HCNT(8)='1' or I_HCNT = "011111111") then
if I_H_FLIP='0' then
H_OFF := to_integer(unsigned(I_HCNT(7 downto 0))) + 1;
else
H_OFF := 254-to_integer(unsigned(I_HCNT(7 downto 0))); -- Was 255
end if;
if (sprite_buffer='0') then
SP := linebuffer(1,H_OFF);
linebuffer(1,H_OFF) <= "000";
else
SP := linebuffer(0,H_OFF);
linebuffer(0,H_OFF) <= "000";
end if;
sprite_blue <= SP(2) & SP(2) & SP(2) & SP(2);
sprite_blue <= SP(2) & SP(2) & SP(2) & SP(2);
sprite_green <= SP(1) & SP(1) & SP(1) & SP(1);
sprite_red <= SP(0) & SP(0) & SP(0) & SP(0);
linebuffer_clr <= '1';
end if;
end if;

View File

@ -27,6 +27,9 @@ port(
dl_download : in std_logic;
samples_ok : out std_logic;
-- No Mans Land special
NML_Speed : in std_logic_vector( 1 downto 0);
-- Clocks and things
CLK_SYS : in std_logic; -- (for loading table)
clock : in std_logic; -- 43.264 Mhz (this drives the rest)
@ -42,8 +45,8 @@ architecture struct of samples is
signal wav_freq_lst : std_logic_vector(1 downto 0); -- for rising edge checks
-- wave info (aka Table)
type addr_t is array (0 to 15) of std_logic_vector(23 downto 0);
type mode_t is array (0 to 15) of std_logic_vector(15 downto 0);
type addr_t is array (0 to 23) of std_logic_vector(23 downto 0);
type mode_t is array (0 to 23) of std_logic_vector(15 downto 0);
signal wav_addr_start : addr_t;
signal wav_addr_end : addr_t;
@ -63,6 +66,7 @@ architecture struct of samples is
signal next_ports : std_logic_vector(15 downto 0);
signal this_stop : std_logic_vector(15 downto 0);
signal next_stop : std_logic_vector(15 downto 0);
signal next_audio_in : std_logic_vector(15 downto 0);
-- Audio variables
signal audio_sum_l : signed(19 downto 0);
@ -70,6 +74,10 @@ architecture struct of samples is
signal audio_l : signed(19 downto 0);
signal audio_r : signed(19 downto 0);
-- No Mans Land background noise specific (set port to play sample 15, and it does no mans land background instead)
signal NML_ID : integer; -- Sample actually playing (8 - 23)
signal NML_Count : integer := 0; -- Next bar to play
begin
----------------
@ -98,7 +106,8 @@ begin
if dl_download='1' and dl_wr='1' then
ID := to_integer(unsigned(dl_addr(6 downto 3)));
-- routine only plays 15 samples, but No Mans Land has 16 to choose from for background tune (8 - 23)
ID := to_integer(unsigned(dl_addr(7 downto 3)));
case dl_addr(2 downto 0) is
when "000" => -- Wave mode
@ -138,6 +147,7 @@ samples_ok <= table_loaded;
-- wave player
process (clock, reset, table_loaded)
variable NewID : integer;
begin
if table_loaded='1' then
if reset='1' then
@ -155,11 +165,22 @@ begin
next_ports <= next_ports or ports;
next_stop <= next_stop or audio_stop;
-- Devil Zone only sets this for a few cycles, so it needs to be kept until the next active audio cycle
next_audio_in <= next_audio_in or audio_in;
if snd_id <= 15 then
if snd_addr_play(snd_id)=x"FFFFFF" then
-- All Start play on 0 to 1 transition
if (last_ports(snd_id)='0' and this_ports(snd_id)='1') then
snd_addr_play(snd_id) <= wav_addr_start(snd_id);
if snd_id < 15 then
snd_addr_play(snd_id) <= wav_addr_start(snd_id);
else
-- No Mans Land special
NML_Count <= 1; -- Start at first bar, but set count for next one
NewID := 8 + to_integer(unsigned(NML_Speed)); -- (which is sample 8 + speed setting)
snd_addr_play(snd_id) <= wav_addr_start(NewID); -- Start address
NML_ID <= NewID; -- Save ID
end if;
end if;
else
-- cut out when signal zero
@ -196,8 +217,10 @@ begin
-- latch final audio / reset sum
audio_r <= audio_sum_r;
audio_l <= audio_sum_l;
audio_sum_r <= resize(signed(audio_in), 20);
audio_sum_l <= resize(signed(audio_in), 20);
audio_sum_r <= resize(signed(next_audio_in), 20);
audio_sum_l <= resize(signed(next_audio_in), 20);
next_audio_in <= audio_in;
else
wav_clk_cnt <= wav_clk_cnt + 1;
end if;
@ -290,7 +313,6 @@ begin
-- Right channel
if wav_mode(snd_id)(13)='1' then
audio_sum_r <= audio_sum_r + to_integer(signed(wave_right));
--audio_sum_r <= audio_sum_r + to_integer(signed(samp_data));
end if;
--wave_left <= x"0000";
@ -318,18 +340,41 @@ begin
end if;
if wav_clk_cnt(4 downto 0) = "01111" then -- "111111" then
-- End of Wave data ?
if snd_addr_play(snd_id) > wav_addr_end(snd_id) then
-- Restart ?
if (wav_mode(snd_id)(8)='0' and this_ports(snd_id)='1') then
-- Loop back to the start
snd_addr_play(snd_id) <= wav_addr_start(snd_id);
else
-- Stop
snd_addr_play(snd_id) <= x"FFFFFF";
end if;
end if;
end if;
-- End of Wave data ?
if (snd_id < 15) then
if (snd_addr_play(snd_id) > wav_addr_end(snd_id)) then
-- Restart ?
if (wav_mode(snd_id)(8)='0' and this_ports(snd_id)='1') then
-- Loop back to the start
snd_addr_play(snd_id) <= wav_addr_start(snd_id);
else
-- Stop
snd_addr_play(snd_id) <= x"FFFFFF";
end if;
end if;
else
if (snd_addr_play(snd_id) > wav_addr_end(NML_ID)) then
-- No Mans Land special (based on number of bits set in counter)
case NML_Count is
when 0 => NewID := 8;
when 1|2|4|8 => NewID := 12;
when 7|11|13 => NewID := 20;
when others => NewID := 16;
end case;
NewID := NewID + to_integer(unsigned(NML_Speed)); -- Offset for speed
snd_addr_play(snd_id) <= wav_addr_start(NewID); -- Get next start address
NML_ID <= NewID; -- Save ID
if (NML_Count = 13) then
NML_Count <= 0; -- Loop to beginning
else
NML_Count <= NML_Count + 1;
end if;
end if;
end if;
end if; -- Wave "01111"
end if; -- Playing