espial,zodiack: add sound nmi timer, small cleanup, increase netwars sound nmi frequency

This commit is contained in:
hap 2025-01-07 15:19:02 +01:00
parent 1cdd24ebb8
commit a6fddc3fe4
5 changed files with 344 additions and 190 deletions

View File

@ -68,15 +68,15 @@ void namcos1_state::TilemapCB(u16 code, int &tile, int &mask)
void namcos1_state::video_start()
{
/* set table for sprite color == 0x7f */
// set table for sprite color == 0x7f
for (int i = 0; i < 15; i++)
m_drawmode_table[i] = DRAWMODE_SHADOW;
m_drawmode_table[15] = DRAWMODE_NONE;
/* all palette entries are not affected by shadow sprites... */
// all palette entries are not affected by shadow sprites...
for (int i = 0; i < 0x2000; i++)
m_c116->shadow_table()[i] = i;
/* ... except for tilemap colors */
// ... except for tilemap colors
for (int i = 0x0800; i < 0x1000; i++)
m_c116->shadow_table()[i] = i + 0x0800;
@ -95,11 +95,11 @@ void namcos1_state::video_start()
void namcos1_state::spriteram_w(offs_t offset, u8 data)
{
/* 0000-07ff work ram */
/* 0800-0fff sprite ram */
// 0000-07ff work ram
// 0800-0fff sprite ram
m_spriteram[offset] = data;
/* a write to this offset tells the sprite chip to buffer the sprite list */
// a write to this offset tells the sprite chip to buffer the sprite list
if (offset == 0x0ff2)
m_copy_sprites = true;
}
@ -135,7 +135,7 @@ sprite format:
void namcos1_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
u8 *spriteram = m_spriteram + 0x800;
const u8 *source = &spriteram[0x800-0x20]; /* the last is NOT a sprite */
const u8 *source = &spriteram[0x800-0x20]; // the last is NOT a sprite
const u8 *finish = &spriteram[0];
gfx_element *gfx = m_gfxdecode->gfx(0);
@ -175,7 +175,7 @@ void namcos1_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, co
flipy = !flipy;
}
sy++; /* sprites are buffered and delayed by one scanline */
sy++; // sprites are buffered and delayed by one scanline
gfx->set_source_clip(tx, sizex, ty, sizey);
if (color != 0x7f)
@ -207,13 +207,13 @@ u32 namcos1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, co
{
rectangle new_clip = cliprect;
/* flip screen is embedded in the sprite control registers */
// flip screen is embedded in the sprite control registers
flip_screen_set(m_spriteram[0x0ff6] & 1);
/* background color */
// background color
bitmap.fill(m_c116->black_pen(), cliprect);
/* berabohm uses asymmetrical visibility windows to iris on the character */
// berabohm uses asymmetrical visibility windows to iris on the character
int i = m_c116->get_reg(0) - 1; // min x
if (new_clip.min_x < i) new_clip.min_x = i;
i = m_c116->get_reg(1) - 1 - 1; // max x
@ -230,8 +230,8 @@ u32 namcos1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, co
screen.priority().fill(0, new_clip);
/* bit 0-2 priority */
/* bit 3 disable */
// bit 0-2 priority
// bit 3 disable
for (int priority = 0; priority < 8; priority++)
{
m_c123tmap->draw(screen, bitmap, new_clip, priority, priority, 0);
@ -244,9 +244,9 @@ u32 namcos1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, co
void namcos1_state::screen_vblank(int state)
{
// rising edge
if (state)
{
// rising edge
if (m_copy_sprites)
{
u8 *spriteram = m_spriteram + 0x800;
@ -265,6 +265,8 @@ void namcos1_state::screen_vblank(int state)
}
else
{
// falling edge
// splatter 2nd bossfight music fails if audiocpu irq is at the same time as main/sub irq
m_audiocpu->set_input_line(M6809_IRQ_LINE, ASSERT_LINE);
m_mcu->set_input_line(HD6301_IRQ1_LINE, ASSERT_LINE);
}

View File

@ -3,7 +3,10 @@
/***************************************************************************
Espial hardware games
Espial hardware games
2 XTALS (12.0MHz and 18.432MHz), both CPUs are 3.0MHz and the AY is 1.5MHz.
18.432MHz XTAL is probably for the pixel clock.
Espial: The Orca logo is displayed, but looks to be "blacked out" via the
color PROMs by having 0x1c & 0x1d set to black.
@ -43,7 +46,6 @@ Stephh's notes (based on the games Z80 code and some tests) :
#include "cpu/z80/z80.h"
#include "machine/gen_latch.h"
#include "machine/timer.h"
#include "machine/watchdog.h"
#include "sound/ay8910.h"
@ -67,9 +69,11 @@ public:
m_colorram(*this, "colorram"),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
m_screen(*this, "screen"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette"),
m_soundlatch(*this, "soundlatch")
m_soundlatch(*this, "soundlatch%u", 0),
m_aysnd(*this, "aysnd")
{ }
void espial(machine_config &config);
@ -88,22 +92,29 @@ protected:
// video-related
tilemap_t *m_bg_tilemap = nullptr;
uint8_t m_flipscreen = 0U;
uint8_t m_flipscreen = 0;
// sound-related
uint8_t m_main_nmi_enabled = 0U;
uint8_t m_sound_nmi_enabled = 0U;
uint8_t m_main_nmi_enabled = 0;
uint8_t m_sound_nmi_enabled = 0;
uint8_t m_sound_nmi_freq = 0;
emu_timer *sound_nmi_timer;
// devices
required_device<cpu_device> m_maincpu;
required_device<cpu_device> m_audiocpu;
required_device<screen_device> m_screen;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
required_device<generic_latch_8_device> m_soundlatch;
required_device_array<generic_latch_8_device, 2> m_soundlatch;
required_device<ay8910_device> m_aysnd;
void master_interrupt_mask_w(uint8_t data);
void master_soundlatch_w(uint8_t data);
void sound_nmi_mask_w(uint8_t data);
void porta_w(offs_t offset, uint8_t data, uint8_t mem_mask);
TIMER_CALLBACK_MEMBER(sound_nmi_gen);
void vblank(int state);
void videoram_w(offs_t offset, uint8_t data);
void colorram_w(offs_t offset, uint8_t data);
void attributeram_w(offs_t offset, uint8_t data);
@ -112,9 +123,8 @@ protected:
TILE_GET_INFO_MEMBER(get_tile_info);
void palette(palette_device &palette) const;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
INTERRUPT_GEN_MEMBER(sound_nmi_gen);
TIMER_DEVICE_CALLBACK_MEMBER(scanline);
void draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect);
void main_map(address_map &map) ATTR_COLD;
void sound_io_map(address_map &map) ATTR_COLD;
void sound_map(address_map &map) ATTR_COLD;
@ -123,7 +133,9 @@ protected:
class netwars_state : public espial_state
{
public:
using espial_state::espial_state;
netwars_state(const machine_config &mconfig, device_type type, const char *tag) :
espial_state(mconfig, type, tag)
{ }
void netwars(machine_config &config);
@ -135,7 +147,32 @@ private:
};
/***************************************************************************
/*************************************
*
* Machine initialization
*
*************************************/
void espial_state::machine_start()
{
save_item(NAME(m_flipscreen));
save_item(NAME(m_main_nmi_enabled));
save_item(NAME(m_sound_nmi_enabled));
save_item(NAME(m_sound_nmi_freq));
sound_nmi_timer = timer_alloc(FUNC(espial_state::sound_nmi_gen), this);
}
void espial_state::machine_reset()
{
m_main_nmi_enabled = false;
m_sound_nmi_enabled = false;
}
/*************************************
Convert the color PROMs into a more useable format.
@ -153,7 +190,7 @@ private:
-- 470 ohm resistor -- RED
bit 0 -- 1 kohm resistor -- RED
***************************************************************************/
*************************************/
void espial_state::palette(palette_device &palette) const
{
@ -168,11 +205,13 @@ void espial_state::palette(palette_device &palette) const
bit1 = BIT(color_prom[i], 1);
bit2 = BIT(color_prom[i], 2);
int const r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// green component
bit0 = BIT(color_prom[i], 3);
bit1 = BIT(color_prom[i + palette.entries()], 0);
bit2 = BIT(color_prom[i + palette.entries()], 1);
int const g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
// blue component
bit0 = 0;
bit1 = BIT(color_prom[i + palette.entries()], 2);
@ -185,23 +224,6 @@ void espial_state::palette(palette_device &palette) const
/***************************************************************************
Callbacks for the TileMap code
***************************************************************************/
TILE_GET_INFO_MEMBER(espial_state::get_tile_info)
{
uint8_t const code = m_videoram[tile_index];
uint8_t const col = m_colorram[tile_index];
uint8_t const attr = m_attributeram[tile_index];
tileinfo.set(0, code | ((attr & 0x03) << 8), col & 0x3f, TILE_FLIPYX(attr >> 2));
}
/*************************************
*
* Video system start
@ -212,61 +234,25 @@ void espial_state::video_start()
{
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(espial_state::get_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
m_bg_tilemap->set_scroll_cols(32);
save_item(NAME(m_flipscreen));
}
void netwars_state::video_start()
{
// Net Wars has a tile map that's twice as big as Espial's
m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(netwars_state::get_tile_info)), TILEMAP_SCAN_ROWS, 8, 8, 32, 64);
m_bg_tilemap->set_scroll_cols(32);
save_item(NAME(m_flipscreen));
}
/*************************************
*
* Memory handlers
*
*************************************/
void espial_state::videoram_w(offs_t offset, uint8_t data)
TILE_GET_INFO_MEMBER(espial_state::get_tile_info)
{
m_videoram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset);
uint8_t const code = m_videoram[tile_index];
uint8_t const col = m_colorram[tile_index];
uint8_t const attr = m_attributeram[tile_index];
tileinfo.set(0, code | ((attr & 0x03) << 8), col & 0x3f, TILE_FLIPYX(attr >> 2));
}
void espial_state::colorram_w(offs_t offset, uint8_t data)
{
m_colorram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset);
}
void espial_state::attributeram_w(offs_t offset, uint8_t data)
{
m_attributeram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset);
}
void espial_state::scrollram_w(offs_t offset, uint8_t data)
{
m_scrollram[offset] = data;
m_bg_tilemap->set_scrolly(offset, data);
}
void espial_state::flipscreen_w(uint8_t data)
{
m_flipscreen = data;
m_bg_tilemap->set_flip(m_flipscreen ? TILEMAP_FLIPX | TILEMAP_FLIPY : 0);
}
/*************************************
*
@ -333,7 +319,6 @@ void espial_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
}
}
uint32_t espial_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
@ -342,20 +327,66 @@ uint32_t espial_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap
}
void espial_state::machine_reset()
{
m_flipscreen = 0;
m_main_nmi_enabled = false;
m_sound_nmi_enabled = false;
/*************************************
*
* Memory handlers
*
*************************************/
void espial_state::vblank(int state)
{
// vblank irq
if (state && m_main_nmi_enabled)
m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
// timer irq, checks soundlatch port then updates some sound related work RAM buffers
if (state)
m_maincpu->set_input_line(0, HOLD_LINE);
}
void espial_state::machine_start()
TIMER_CALLBACK_MEMBER(espial_state::sound_nmi_gen)
{
save_item(NAME(m_sound_nmi_enabled));
if (m_sound_nmi_enabled)
m_audiocpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
}
void espial_state::videoram_w(offs_t offset, uint8_t data)
{
m_videoram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset);
}
void espial_state::colorram_w(offs_t offset, uint8_t data)
{
m_colorram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset);
}
void espial_state::attributeram_w(offs_t offset, uint8_t data)
{
m_attributeram[offset] = data;
m_bg_tilemap->mark_tile_dirty(offset);
}
void espial_state::scrollram_w(offs_t offset, uint8_t data)
{
m_scrollram[offset] = data;
m_bg_tilemap->set_scrolly(offset, data);
}
void espial_state::flipscreen_w(uint8_t data)
{
m_flipscreen = data;
m_bg_tilemap->set_flip(m_flipscreen ? TILEMAP_FLIPX | TILEMAP_FLIPY : 0);
}
void espial_state::master_interrupt_mask_w(uint8_t data)
{
m_main_nmi_enabled = ~(data & 1);
@ -367,31 +398,46 @@ void espial_state::sound_nmi_mask_w(uint8_t data)
m_sound_nmi_enabled = data & 1;
}
TIMER_DEVICE_CALLBACK_MEMBER(espial_state::scanline)
void espial_state::porta_w(offs_t offset, uint8_t data, uint8_t mem_mask)
{
int const scanline = param;
if (mem_mask && data != m_sound_nmi_freq)
{
// sound NMI frequency
m_sound_nmi_freq = data;
attotime period;
if (scanline == 240 && m_main_nmi_enabled) // vblank-out irq
m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
// netwars writes 0xf8 and expects 32 NMIs per frame
// espial writes 0xfe and expects 4 NMIs per frame
switch (data)
{
case 0:
period = attotime::never;
break;
if (scanline == 16) // timer irq, checks soundlatch port then updates some sound related work RAM buffers
m_maincpu->set_input_line(0, HOLD_LINE);
case 0xfe:
period = m_screen->frame_period() / 4;
break;
case 0xf8:
period = m_screen->frame_period() / 32;
break;
default:
logerror("%s: unknown sound NMI frequency %02X", machine().describe_context(), data);
return;
}
sound_nmi_timer->adjust(period, 0, period);
}
}
INTERRUPT_GEN_MEMBER(espial_state::sound_nmi_gen)
{
if (m_sound_nmi_enabled)
m_audiocpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
}
void espial_state::master_soundlatch_w(uint8_t data)
{
m_soundlatch->write(data);
m_audiocpu->set_input_line(0, HOLD_LINE);
}
/*************************************
*
* Address maps
*
*************************************/
void espial_state::main_map(address_map &map)
{
@ -401,7 +447,7 @@ void espial_state::main_map(address_map &map)
map(0x6082, 0x6082).portr("DSW1");
map(0x6083, 0x6083).portr("IN1");
map(0x6084, 0x6084).portr("IN2");
map(0x6090, 0x6090).r("soundlatch2", FUNC(generic_latch_8_device::read)).w(FUNC(espial_state::master_soundlatch_w));
map(0x6090, 0x6090).r(m_soundlatch[1], FUNC(generic_latch_8_device::read)).w(m_soundlatch[0], FUNC(generic_latch_8_device::write));
map(0x7000, 0x7000).rw("watchdog", FUNC(watchdog_timer_device::reset_r), FUNC(watchdog_timer_device::reset_w));
map(0x7100, 0x7100).w(FUNC(espial_state::master_interrupt_mask_w));
map(0x7200, 0x7200).w(FUNC(espial_state::flipscreen_w));
@ -427,7 +473,7 @@ void netwars_state::main_map(address_map &map)
map(0x6082, 0x6082).portr("DSW1");
map(0x6083, 0x6083).portr("IN1");
map(0x6084, 0x6084).portr("IN2");
map(0x6090, 0x6090).r("soundlatch2", FUNC(generic_latch_8_device::read)).w(FUNC(netwars_state::master_soundlatch_w));
map(0x6090, 0x6090).r(m_soundlatch[1], FUNC(generic_latch_8_device::read)).w(m_soundlatch[0], FUNC(generic_latch_8_device::write));
map(0x7000, 0x7000).rw("watchdog", FUNC(watchdog_timer_device::reset_r), FUNC(watchdog_timer_device::reset_w));
map(0x7100, 0x7100).w(FUNC(netwars_state::master_interrupt_mask_w));
map(0x7200, 0x7200).w(FUNC(netwars_state::flipscreen_w));
@ -446,16 +492,23 @@ void espial_state::sound_map(address_map &map)
map(0x0000, 0x1fff).rom();
map(0x2000, 0x23ff).ram();
map(0x4000, 0x4000).w(FUNC(espial_state::sound_nmi_mask_w));
map(0x6000, 0x6000).r(m_soundlatch, FUNC(generic_latch_8_device::read)).w("soundlatch2", FUNC(generic_latch_8_device::write));
map(0x6000, 0x6000).r(m_soundlatch[0], FUNC(generic_latch_8_device::read)).w(m_soundlatch[1], FUNC(generic_latch_8_device::write));
}
void espial_state::sound_io_map(address_map &map)
{
map.global_mask(0xff);
map(0x00, 0x01).w("aysnd", FUNC(ay8910_device::address_data_w));
map(0x00, 0x01).w(m_aysnd, FUNC(ay8910_device::address_data_w));
}
/*************************************
*
* Input ports
*
*************************************/
// verified from Z80 code
static INPUT_PORTS_START( espial )
PORT_START("IN0")
@ -580,6 +633,13 @@ static INPUT_PORTS_START( netwars )
INPUT_PORTS_END
/*************************************
*
* GFX layouts
*
*************************************/
static const gfx_layout charlayout =
{
8,8,
@ -610,29 +670,35 @@ GFXDECODE_END
/*************************************
*
* Machine configs
*
*************************************/
void espial_state::espial(machine_config &config)
{
// basic machine hardware
Z80(config, m_maincpu, 3'072'000); // 3.072 MHz
Z80(config, m_maincpu, 12_MHz_XTAL / 4);
m_maincpu->set_addrmap(AS_PROGRAM, &espial_state::main_map);
TIMER(config, "scantimer").configure_scanline(FUNC(espial_state::scanline), "screen", 0, 1);
Z80(config, m_audiocpu, 3'072'000); // 2 MHz??????
Z80(config, m_audiocpu, 12_MHz_XTAL / 4);
m_audiocpu->set_addrmap(AS_PROGRAM, &espial_state::sound_map);
m_audiocpu->set_addrmap(AS_IO, &espial_state::sound_io_map);
m_audiocpu->set_periodic_int(FUNC(espial_state::sound_nmi_gen), attotime::from_hz(4 * 60));
config.set_maximum_quantum(attotime::from_hz(600));
WATCHDOG_TIMER(config, "watchdog");
// video hardware
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); // not accurate
screen.set_size(32*8, 32*8);
screen.set_visarea(0*8, 32*8-1, 2*8, 30*8-1);
screen.set_screen_update(FUNC(espial_state::screen_update));
screen.set_palette(m_palette);
SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
m_screen->set_refresh_hz(59);
m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500)); // not accurate
m_screen->set_size(32*8, 32*8);
m_screen->set_visarea(0*8, 32*8-1, 2*8, 30*8-1);
m_screen->set_screen_update(FUNC(espial_state::screen_update));
m_screen->set_palette(m_palette);
m_screen->screen_vblank().set(FUNC(espial_state::vblank));
GFXDECODE(config, m_gfxdecode, m_palette, gfx_espial);
PALETTE(config, m_palette, FUNC(espial_state::palette), 256);
@ -640,10 +706,14 @@ void espial_state::espial(machine_config &config)
// sound hardware
SPEAKER(config, "mono").front_center();
GENERIC_LATCH_8(config, m_soundlatch);
GENERIC_LATCH_8(config, "soundlatch2");
GENERIC_LATCH_8(config, m_soundlatch[0]);
m_soundlatch[0]->data_pending_callback().set_inputline(m_audiocpu, 0);
AY8910(config, "aysnd", 1'500'000).add_route(ALL_OUTPUTS, "mono", 0.50);
GENERIC_LATCH_8(config, m_soundlatch[1]);
AY8910(config, m_aysnd, 12_MHz_XTAL / 8).add_route(ALL_OUTPUTS, "mono", 0.50);
m_aysnd->port_a_write_callback().set(FUNC(espial_state::porta_w));
m_aysnd->port_b_write_callback().set_nop(); // spams 0x00
}
void netwars_state::netwars(machine_config &config)
@ -652,18 +722,15 @@ void netwars_state::netwars(machine_config &config)
// basic machine hardware
m_maincpu->set_addrmap(AS_PROGRAM, &netwars_state::main_map);
// video hardware
subdevice<screen_device>("screen")->set_size(32*8, 64*8);
}
/***************************************************************************
Game driver(s)
***************************************************************************/
/*************************************
*
* ROM definitions
*
*************************************/
ROM_START( espial )
ROM_REGION( 0x10000, "maincpu", 0 )
@ -786,6 +853,13 @@ ROM_END
} // anonymous namespace
/*************************************
*
* Game driver(s)
*
*************************************/
GAME( 1983, espial, 0, espial, espial, espial_state, empty_init, ROT0, "Orca / Thunderbolt", "Espial (Europe)", MACHINE_SUPPORTS_SAVE )
GAME( 1983, espialj, espial, espial, espial, espial_state, empty_init, ROT0, "Orca / Thunderbolt", "Espial (Japan)", MACHINE_SUPPORTS_SAVE )
GAME( 1983, espialn, espial, espial, espial, espial_state, empty_init, ROT0, "Orca / Thunderbolt", "Espial (Nova Apparate license)", MACHINE_SUPPORTS_SAVE )

View File

@ -28,17 +28,17 @@
DEFINE_DEVICE_TYPE(ORCA_OVG_40C, orca_ovg_40c_device, "orca_ovg_40c", "Orca OVG 40c video PCB")
orca_ovg_40c_device::orca_ovg_40c_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, ORCA_OVG_40C, tag, owner, clock),
device_gfx_interface(mconfig, *this, nullptr, "palette"),
device_video_interface(mconfig, *this),
m_videoram(*this, "videoram"),
m_videoram_2(*this,"videoram_2"),
m_attributeram(*this, "attributeram"),
m_spriteram(*this, "spriteram"),
m_bulletsram(*this, "bulletsram"),
m_percuss_hardware(false),
m_flip_screen(false)
orca_ovg_40c_device::orca_ovg_40c_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, ORCA_OVG_40C, tag, owner, clock),
device_gfx_interface(mconfig, *this, nullptr, "palette"),
device_video_interface(mconfig, *this),
m_videoram(*this, "videoram"),
m_videoram_2(*this,"videoram_2"),
m_attributeram(*this, "attributeram"),
m_spriteram(*this, "spriteram"),
m_bulletsram(*this, "bulletsram"),
m_percuss_hardware(false),
m_flip_screen(false)
{
}

View File

@ -700,7 +700,7 @@ ROM_START( dogfightp ) // all 2732
ROM_LOAD( "10.7p", 0x1800, 0x1000, CRC(2cb51793) SHA1(d90177ef28730774202a04a0846281537a1883df) )
ROM_REGION( 0x0040, "videopcb:proms", 0 ) // on ORCA OVG-40c sub board
ROM_LOAD( "blue.2a.82s123", 0x0000, 0x0020, CRC(aa839a24) SHA1(9b8217e1c257d24e873888fd083c099fc93c7878) ) //doesn't match parent
ROM_LOAD( "blue.2a.82s123", 0x0000, 0x0020, CRC(aa839a24) SHA1(9b8217e1c257d24e873888fd083c099fc93c7878) ) // doesn't match parent
ROM_LOAD( "pink.2b.82s123", 0x0020, 0x0020, CRC(596ae457) SHA1(1c1a3130d88c5fd5c66ce9f91d97a09c0a0b535f) )
ROM_END

View File

@ -117,11 +117,12 @@ public:
driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
m_soundlatch(*this, "soundlatch%u", 0)
m_screen(*this, "screen"),
m_soundlatch(*this, "soundlatch%u", 0),
m_aysnd(*this, "aysnd")
{ }
void zodiack(machine_config &config);
void dogfight(machine_config &config);
void percuss(machine_config &config);
protected:
@ -133,18 +134,23 @@ private:
void irq_mask_w(uint8_t data);
void sound_nmi_enable_w(uint8_t data);
void control_w(uint8_t data);
void porta_w(offs_t offset, uint8_t data, uint8_t mem_mask);
// devices
required_device<z80_device> m_maincpu;
required_device<z80_device> m_audiocpu;
required_device<screen_device> m_screen;
required_device_array<generic_latch_8_device, 2> m_soundlatch;
required_device<ay8910_device> m_aysnd;
// state
uint8_t m_main_nmi_enabled = 0;
uint8_t m_main_irq_enabled = 0;
uint8_t m_sound_nmi_enabled = 0;
uint8_t m_sound_nmi_freq = 0;
emu_timer *sound_nmi_timer;
INTERRUPT_GEN_MEMBER(sound_nmi_gen);
TIMER_CALLBACK_MEMBER(sound_nmi_gen);
void vblank(int state);
void io_map(address_map &map) ATTR_COLD;
@ -152,6 +158,39 @@ private:
void sound_map(address_map &map) ATTR_COLD;
};
/*************************************
*
* Machine initialization
*
*************************************/
void zodiack_state::machine_start()
{
save_item(NAME(m_main_nmi_enabled));
save_item(NAME(m_main_irq_enabled));
save_item(NAME(m_sound_nmi_enabled));
save_item(NAME(m_sound_nmi_freq));
sound_nmi_timer = timer_alloc(FUNC(zodiack_state::sound_nmi_gen), this);
}
void zodiack_state::machine_reset()
{
m_main_nmi_enabled = 0;
m_main_irq_enabled = 0;
m_sound_nmi_enabled = 0;
}
/*************************************
*
* Memory handlers
*
*************************************/
void zodiack_state::nmi_mask_w(uint8_t data)
{
m_main_nmi_enabled = (data & 1) ^ 1;
@ -176,7 +215,7 @@ void zodiack_state::vblank(int state)
m_maincpu->set_input_line(0, HOLD_LINE);
}
INTERRUPT_GEN_MEMBER(zodiack_state::sound_nmi_gen)
TIMER_CALLBACK_MEMBER(zodiack_state::sound_nmi_gen)
{
if (m_sound_nmi_enabled)
m_audiocpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
@ -190,6 +229,46 @@ void zodiack_state::control_w(uint8_t data)
// Bit 2 - ????
}
void zodiack_state::porta_w(offs_t offset, uint8_t data, uint8_t mem_mask)
{
if (mem_mask && data != m_sound_nmi_freq)
{
// sound NMI frequency
m_sound_nmi_freq = data;
attotime period;
// dogfight writes 0xc0 and expects 4 NMIs per frame
// others write 0xe0 and expect 8 NMIs per frame
switch (data)
{
case 0:
period = attotime::never;
break;
case 0xc0:
period = m_screen->frame_period() / 4;
break;
case 0xe0:
period = m_screen->frame_period() / 8;
break;
default:
logerror("%s: unknown sound NMI frequency %02X", machine().describe_context(), data);
return;
}
sound_nmi_timer->adjust(period, 0, period);
}
}
/*************************************
*
* Address maps
*
*************************************/
void zodiack_state::main_map(address_map &map)
{
@ -224,11 +303,17 @@ void zodiack_state::sound_map(address_map &map)
void zodiack_state::io_map(address_map &map)
{
map.global_mask(0xff);
map(0x00, 0x01).w("aysnd", FUNC(ay8910_device::address_data_w));
map(0x00, 0x01).w(m_aysnd, FUNC(ay8910_device::address_data_w));
}
/*************************************
*
* Input ports
*
*************************************/
static INPUT_PORTS_START( zodiack )
PORT_START("DSW0") // never read in this game
PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED )
@ -540,39 +625,30 @@ static INPUT_PORTS_START( bounty )
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY
INPUT_PORTS_END
void zodiack_state::machine_start()
{
save_item(NAME(m_main_nmi_enabled));
save_item(NAME(m_main_irq_enabled));
save_item(NAME(m_sound_nmi_enabled));
}
void zodiack_state::machine_reset()
{
m_main_nmi_enabled = 0;
m_main_irq_enabled = 0;
m_sound_nmi_enabled = 0;
}
/*************************************
*
* Machine configs
*
*************************************/
void zodiack_state::zodiack(machine_config &config)
{
// basic machine hardware
Z80(config, m_maincpu, XTAL(18'432'000) / 6);
Z80(config, m_maincpu, 18.432_MHz_XTAL / 6);
m_maincpu->set_addrmap(AS_PROGRAM, &zodiack_state::main_map);
Z80(config, m_audiocpu, XTAL(18'432'000) / 6);
Z80(config, m_audiocpu, 18.432_MHz_XTAL / 6);
m_audiocpu->set_addrmap(AS_PROGRAM, &zodiack_state::sound_map);
m_audiocpu->set_addrmap(AS_IO, &zodiack_state::io_map);
m_audiocpu->set_periodic_int(FUNC(zodiack_state::sound_nmi_gen), attotime::from_hz(8 * 60)); // sound tempo - unknown source, timing is guessed
config.set_maximum_quantum(attotime::from_hz(600));
WATCHDOG_TIMER(config, "watchdog");
// video hardware
SCREEN(config, "screen", SCREEN_TYPE_RASTER).screen_vblank().set(FUNC(zodiack_state::vblank));
SCREEN(config, m_screen, SCREEN_TYPE_RASTER).screen_vblank().set(FUNC(zodiack_state::vblank));
orca_ovg_40c_device &videopcb(ORCA_OVG_40C(config, "videopcb", 0));
videopcb.set_screen("screen");
@ -585,7 +661,8 @@ void zodiack_state::zodiack(machine_config &config)
GENERIC_LATCH_8(config, m_soundlatch[1]);
AY8910(config, "aysnd", XTAL(18'432'000) / 12).add_route(ALL_OUTPUTS, "mono", 0.50);
AY8910(config, m_aysnd, 18.432_MHz_XTAL / 12).add_route(ALL_OUTPUTS, "mono", 0.50);
m_aysnd->port_a_write_callback().set(FUNC(zodiack_state::porta_w));
}
void zodiack_state::percuss(machine_config &config)
@ -596,19 +673,13 @@ void zodiack_state::percuss(machine_config &config)
videopcb.set_percuss_hardware(true);
}
void zodiack_state::dogfight(machine_config &config)
{
zodiack(config);
m_audiocpu->set_periodic_int(FUNC(zodiack_state::sound_nmi_gen), attotime::from_hz(4 * 60)); // 4 interrupts per frame
}
/***************************************************************************
Game driver(s)
***************************************************************************/
/*************************************
*
* ROM definitions
*
*************************************/
ROM_START( zodiack )
ROM_REGION( 0x10000, "maincpu", 0 )
@ -735,9 +806,16 @@ ROM_END
} // anonymous namespace
GAME( 1983, zodiack, 0, zodiack, zodiack, zodiack_state, empty_init, ROT270, "Orca (Esco Trading Co., Inc. license)", "Zodiack", MACHINE_IMPERFECT_COLORS | MACHINE_SUPPORTS_SAVE ) // bullet color needs to be verified
GAME( 1983, dogfight, 0, dogfight, dogfight, zodiack_state, empty_init, ROT270, "Orca / Thunderbolt", "Dog Fight (Thunderbolt)", MACHINE_SUPPORTS_SAVE )
GAME( 1982, moguchan, 0, percuss, moguchan, zodiack_state, empty_init, ROT270, "Orca (Eastern Commerce Inc. license)", "Mogu Chan (bootleg?)", MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE ) // license copyright taken from ROM string at $0b5c
GAME( 1981, percuss, 0, percuss, percuss, zodiack_state, empty_init, ROT270, "Orca", "The Percussor", MACHINE_SUPPORTS_SAVE )
GAME( 1982, bounty, 0, percuss, bounty, zodiack_state, empty_init, ROT180, "Orca", "The Bounty (set 1)", MACHINE_SUPPORTS_SAVE )
GAME( 1982, bounty2, bounty, percuss, bounty, zodiack_state, empty_init, ROT180, "Orca", "The Bounty (set 2)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // seems to use a different memory map
/*************************************
*
* Game driver(s)
*
*************************************/
GAME( 1983, zodiack, 0, zodiack, zodiack, zodiack_state, empty_init, ROT270, "Orca (Esco Trading Co., Inc. license)", "Zodiack", MACHINE_IMPERFECT_COLORS | MACHINE_SUPPORTS_SAVE ) // bullet color needs to be verified
GAME( 1983, dogfight, 0, zodiack, dogfight, zodiack_state, empty_init, ROT270, "Orca / Thunderbolt", "Dog Fight (Thunderbolt)", MACHINE_SUPPORTS_SAVE )
GAME( 1982, moguchan, 0, percuss, moguchan, zodiack_state, empty_init, ROT270, "Orca (Eastern Commerce Inc. license)", "Mogu Chan (bootleg?)", MACHINE_WRONG_COLORS | MACHINE_SUPPORTS_SAVE ) // license copyright taken from ROM string at $0b5c
GAME( 1981, percuss, 0, percuss, percuss, zodiack_state, empty_init, ROT270, "Orca", "The Percussor", MACHINE_SUPPORTS_SAVE )
GAME( 1982, bounty, 0, percuss, bounty, zodiack_state, empty_init, ROT180, "Orca", "The Bounty (set 1)", MACHINE_SUPPORTS_SAVE )
GAME( 1982, bounty2, bounty, percuss, bounty, zodiack_state, empty_init, ROT180, "Orca", "The Bounty (set 2)", MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) // seems to use a different memory map