catnmous sound support

This commit is contained in:
Vas Crabb 2015-12-29 15:26:15 +11:00
parent 6d14257032
commit c379fd4d97
4 changed files with 236 additions and 149 deletions

View File

@ -2,9 +2,36 @@
// copyright-holders:Vas Crabb
/*
Laser Battle / Lazarian (c) 1981 Zaccaria
Cat and Mouse (c) 1982 Zaccaria
audio emulation by Vas Crabb
*/
#include "includes/laserbat.h"
READ8_MEMBER(laserbat_state_base::rhsc_r)
{
return m_rhsc;
}
WRITE8_MEMBER(laserbat_state_base::whsc_w)
{
m_whsc = data;
}
WRITE8_MEMBER(laserbat_state_base::csound1_w)
{
m_csound1 = data;
}
WRITE8_MEMBER(laserbat_state_base::csound2_w)
{
m_csound2 = data;
}
/*
The Laser Battle/Lazarian sound board has a SN76477 CSG, two TMS3615
tone synthesisers, and a TDA1010 power amplifier. It receives
commands from the game board over a 16-bit unidirectional data bus.
@ -99,30 +126,6 @@
*/
#include "includes/laserbat.h"
READ8_MEMBER(laserbat_state_base::rhsc_r)
{
return m_rhsc;
}
WRITE8_MEMBER(laserbat_state_base::whsc_w)
{
m_whsc = data;
}
WRITE8_MEMBER(laserbat_state_base::csound1_w)
{
m_csound1 = data;
}
WRITE8_MEMBER(laserbat_state_base::csound2_w)
{
m_csound2 = data;
}
WRITE8_MEMBER(laserbat_state::csound2_w)
{
// there are a bunch of edge-triggered things, so grab changes
@ -221,3 +224,153 @@ WRITE8_MEMBER(laserbat_state::csound2_w)
// keep for detecting changes next time
m_csound2 = data;
}
/*
The Cat and Mouse sound board has a 6802 processor with three ROMs,
a 6821 PIA, two AY-3-8910 PSGs, and some other logic and analog
circuitry. Unfortunately we lack a schematic, so all knowledge of
this board is based on tracing the sound program.
The 6821 PIA is mapped at addresses $005C..$005F. The known PIA
signal assignments are as follows:
+------+-----------------------+
| PA0 | PSG1/PSG2 DA0 |
| PA1 | PSG1/PSG2 DA1 |
| PA2 | PSG1/PSG2 DA2 |
| PA3 | PSG1/PSG2 DA3 |
| PA4 | PSG1/PSG2 DA4 |
| PA5 | PSG1/PSG2 DA5 |
| PA6 | PSG1/PSG2 DA6 |
| PA7 | PSG1/PSG2 DA7 |
| PB0 | PSG1 BC1 |
| PB1 | PSG1 BDIR |
| PB2 | PSG2 BC1 |
| PB3 | PSG2 BDIR |
| CA1 | Host interface bit 6 |
| CB1 | periodic IRQ source |
| IRQA | 6802 NMI |
| IRQB | 6802 IRQ |
+------+-----------------------+
The program makes use of I/O port A on the first PSG as outputs. At
a guess, it could have the same function as it does on other
Zaccaria sound boards.
The first PSG receives commands from the game board in the low five
bits of port B. Commands are processed on receiving an NMI. The
sound program always masks out the high three bits of the value so
they could be connected to anything on the board.
The I/O ports on the second PSG don't appear to be used at all.
The game board sends commands to the sound board over a 16-bit
unidirectional data bus. The CPU cannot write all sixteen lines
atomically, it write to lines 1-8 as one group and 9-16 as another
group. Not all bit functions are known:
+-----+----------------------------------------------------------+
| Bit | Function |
+-----+----------------------------------------------------------+
| 1 | PSG1 IOB0 |
| 2 | PSG1 IOB1 |
| 3 | PSG1 IOB2 |
| 4 | PSG1 IOB3 |
| 5 | PSG1 IOB4 |
| 6 | PIA CA1 |
| 7 | |
| 8 | |
| 9 | Used but unknown purpose |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | Used but unknown purpose |
+-----+----------------------------------------------------------+
The game board makes the the audio output from the first S2636 PVI
(5E) available on a pin at the sound board interface connector, but
it may or may not be routed anywhere.
*/
WRITE8_MEMBER(catnmous_state::csound1_w)
{
m_pia->ca1_w((data & 0x20) ? 1 : 0);
m_csound1 = data;
}
READ8_MEMBER(catnmous_state::pia_porta_r)
{
UINT8 const control = m_pia->b_output();
UINT8 data = 0xff;
if (0x01 == (control & 0x03))
data &= m_psg1->data_r(space, 0);
if (0x04 == (control & 0x0c))
data &= m_psg2->data_r(space, 0);
return data;
}
WRITE8_MEMBER(catnmous_state::pia_porta_w)
{
UINT8 const control = m_pia->b_output();
if (control & 0x02)
m_psg1->data_address_w(space, (control >> 0) & 0x01, data);
if (control & 0x08)
m_psg2->data_address_w(space, (control >> 2) & 0x01, data);
}
WRITE8_MEMBER(catnmous_state::pia_portb_w)
{
if (data & 0x02)
m_psg1->data_address_w(space, (data >> 0) & 0x01, m_pia->a_output());
if (data & 0x08)
m_psg2->data_address_w(space, (data >> 2) & 0x01, m_pia->a_output());
}
WRITE_LINE_MEMBER(catnmous_state::pia_irqa)
{
m_audiocpu->set_input_line(INPUT_LINE_NMI, state ? ASSERT_LINE : CLEAR_LINE);
}
WRITE_LINE_MEMBER(catnmous_state::pia_irqb)
{
m_audiocpu->set_input_line(INPUT_LINE_IRQ0, state ? ASSERT_LINE : CLEAR_LINE);
}
WRITE8_MEMBER(catnmous_state::psg1_porta_w)
{
// similar to zaccaria.c since we have no clue how this board really works
// this code could be completely wrong/inappropriate for this game for all we know
static double const table[8] = {
RES_K(8.2),
RES_R(820),
RES_K(3.3),
RES_R(150),
RES_K(5.6),
RES_R(390),
RES_K(1.5),
RES_R(47) };
RES_VOLTAGE_DIVIDER(RES_K(4.7), table[data & 0x07]);
m_psg2->set_volume(1, 150 * RES_VOLTAGE_DIVIDER(RES_K(4.7), table[data & 0x07]));
}
READ8_MEMBER(catnmous_state::psg1_portb_r)
{
// the program masks out the three high bits - no clue what they're connected to
return m_csound1 & 0x1f;
}
INTERRUPT_GEN_MEMBER(catnmous_state::cb1_toggle)
{
m_cb1 = !m_cb1;
m_pia->cb1_w(m_cb1 ? 1 : 0);
}

View File

@ -1,12 +1,15 @@
// license:BSD-3-Clause
// copyright-holders:Pierpaolo Prazzoli, Vas Crabb
// copyright-holders:Vas Crabb
/*
Laser Battle / Lazarian (c) 1981 Zaccaria
Cat and Mouse (c) 1982 Zaccaria
original driver by Pierpaolo Prazzoli
The two games have a similar video hardware, but sound hardware is
The two games have identical game/video boards hardware, but
completely different sound boards. Laser Battle/Lazarian have a
dumb sound board with TMS organ and CSG chips driven directly by the
game program. Cat'N'Mouse
very different and they don't use the collision detection provided
by the s2636 chips.
@ -18,10 +21,14 @@
written at I/O address 3. The sound board controls data direction
on J7 and when input from sound board to game board is latched.
Both Laser Battle/Lazarian and Cat and Mouse use the unidirectional
interface on J3. It seems there are no games that actually use the
bidirectional interface on J7.
Laser Battle/Lazarian notes:
* Cocktail cabinet has an additional "image commutation board"
consuming the screen flip output, presumably flipping the image by
means of dark magic
reversing the deflection coil connections
* Player 2 inputs are only used in cocktail mode
* Tilt input resets Laser Battle, but just causes loss of one credit
in Lazarian
@ -35,7 +42,7 @@
TODO:
- work out where all the magic layer offsets come from
- second bank of DIP switches in laserbat
- second bank of DIP switches in laserbat and catnmous
- sound in laserbat (with schematics) and in catnmous
*/
@ -99,8 +106,6 @@ READ8_MEMBER(laserbat_state_base::rrowx_r)
/*
Color handling with 2716.14L and 82S100.10M
2716.14L address lines are connected as follows:
A0 4H
@ -134,7 +139,7 @@ static ADDRESS_MAP_START( laserbat_map, AS_PROGRAM, 8, laserbat_state_base )
AM_RANGE(0x6000, 0x73ff) AM_ROM
AM_RANGE(0x7800, 0x7bff) AM_ROM
AM_RANGE(0x1400, 0x14ff) AM_MIRROR(0x6000) AM_WRITENOP // always 0 (bullet ram in Quasar)
AM_RANGE(0x1400, 0x14ff) AM_MIRROR(0x6000) AM_WRITENOP
AM_RANGE(0x1500, 0x15ff) AM_MIRROR(0x6000) AM_DEVREADWRITE("pvi1", s2636_device, read_data, write_data)
AM_RANGE(0x1600, 0x16ff) AM_MIRROR(0x6000) AM_DEVREADWRITE("pvi2", s2636_device, read_data, write_data)
AM_RANGE(0x1700, 0x17ff) AM_MIRROR(0x6000) AM_DEVREADWRITE("pvi3", s2636_device, read_data, write_data)
@ -159,7 +164,8 @@ ADDRESS_MAP_END
static ADDRESS_MAP_START( catnmous_sound_map, AS_PROGRAM, 8, catnmous_state )
AM_RANGE(0x0000, 0x007f) AM_RAM
AM_RANGE(0x500c, 0x500f) AM_DEVREADWRITE("pia", pia6821_device, read, write)
AM_RANGE(0xf000, 0xffff) AM_ROM
AM_RANGE(0xc000, 0xcfff) AM_ROM
AM_RANGE(0xe000, 0xffff) AM_ROM
ADDRESS_MAP_END
@ -348,7 +354,7 @@ static INPUT_PORTS_START( catnmous )
// PORT_DIPSETTING( 0x50, DEF_STR(Infinite) )
// PORT_DIPSETTING( 0x60, DEF_STR(Infinite) )
// PORT_DIPSETTING( 0x70, DEF_STR(Infinite) )
PORT_DIPNAME( 0x80, 0x80, "Game Over Melody" ) PORT_DIPLOCATION("SW-1:8")
PORT_DIPNAME( 0x80, 0x80, DEF_STR(Demo_Sounds) ) PORT_DIPLOCATION("SW-1:8")
PORT_DIPSETTING( 0x00, DEF_STR(Off) )
PORT_DIPSETTING( 0x80, DEF_STR(On) )
INPUT_PORTS_END
@ -387,70 +393,11 @@ static GFXDECODE_START( laserbat )
GFXDECODE_END
/* Cat'N Mouse sound ***********************************/
WRITE_LINE_MEMBER(catnmous_state::zaccaria_irq0a)
{
m_audiocpu->set_input_line(INPUT_LINE_NMI, state ? ASSERT_LINE : CLEAR_LINE);
}
WRITE_LINE_MEMBER(catnmous_state::zaccaria_irq0b)
{
m_audiocpu->set_input_line(0, state ? ASSERT_LINE : CLEAR_LINE);
}
READ8_MEMBER(catnmous_state::zaccaria_port0a_r)
{
ay8910_device *ay8910 = (m_active_8910 == 0) ? m_ay1 : m_ay2;
return ay8910->data_r(space, 0);
}
WRITE8_MEMBER(catnmous_state::zaccaria_port0a_w)
{
m_port0a = data;
}
WRITE8_MEMBER(catnmous_state::zaccaria_port0b_w)
{
/* bit 1 goes to 8910 #0 BDIR pin */
if ((m_last_port0b & 0x02) == 0x02 && (data & 0x02) == 0x00)
{
/* bit 0 goes to the 8910 #0 BC1 pin */
m_ay1->data_address_w(space, m_last_port0b >> 0, m_port0a);
}
else if ((m_last_port0b & 0x02) == 0x00 && (data & 0x02) == 0x02)
{
/* bit 0 goes to the 8910 #0 BC1 pin */
if (m_last_port0b & 0x01)
m_active_8910 = 0;
}
/* bit 3 goes to 8910 #1 BDIR pin */
if ((m_last_port0b & 0x08) == 0x08 && (data & 0x08) == 0x00)
{
/* bit 2 goes to the 8910 #1 BC1 pin */
m_ay2->data_address_w(space, m_last_port0b >> 2, m_port0a);
}
else if ((m_last_port0b & 0x08) == 0x00 && (data & 0x08) == 0x08)
{
/* bit 2 goes to the 8910 #1 BC1 pin */
if (m_last_port0b & 0x04)
m_active_8910 = 1;
}
m_last_port0b = data;
}
INTERRUPT_GEN_MEMBER(laserbat_state_base::laserbat_interrupt)
{
device.execute().set_input_line_and_vector(0, HOLD_LINE, 0x0a);
}
INTERRUPT_GEN_MEMBER(catnmous_state::zaccaria_cb1_toggle)
{
m_pia->cb1_w(m_cb1_toggle & 1);
m_cb1_toggle ^= 1;
}
DRIVER_INIT_MEMBER(laserbat_state_base, laserbat)
{
m_scanline_timer = timer_alloc(TIMER_SCANLINE);
@ -492,20 +439,7 @@ void catnmous_state::machine_start()
{
laserbat_state_base::machine_start();
save_item(NAME(m_active_8910));
save_item(NAME(m_port0a));
save_item(NAME(m_last_port0b));
save_item(NAME(m_cb1_toggle));
}
void catnmous_state::machine_reset()
{
laserbat_state_base::machine_reset();
m_active_8910 = 0;
m_port0a = 0;
m_last_port0b = 0;
m_cb1_toggle = 0;
save_item(NAME(m_cb1));
}
void laserbat_state_base::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
@ -589,22 +523,22 @@ static MACHINE_CONFIG_DERIVED_CLASS( catnmous, laserbat_base, catnmous_state )
// sound board devices
MCFG_CPU_ADD("audiocpu", M6802, 3580000) // ?
MCFG_CPU_PROGRAM_MAP(catnmous_sound_map)
MCFG_CPU_PERIODIC_INT_DRIVER(catnmous_state, zaccaria_cb1_toggle, (double)3580000/4096)
MCFG_CPU_PERIODIC_INT_DRIVER(catnmous_state, cb1_toggle, (double)3580000/4096)
MCFG_DEVICE_ADD("pia", PIA6821, 0)
MCFG_PIA_READPA_HANDLER(READ8(catnmous_state, zaccaria_port0a_r))
MCFG_PIA_WRITEPA_HANDLER(WRITE8(catnmous_state, zaccaria_port0a_w))
MCFG_PIA_WRITEPB_HANDLER(WRITE8(catnmous_state, zaccaria_port0b_w))
MCFG_PIA_IRQA_HANDLER(WRITELINE(catnmous_state, zaccaria_irq0a))
MCFG_PIA_IRQB_HANDLER(WRITELINE(catnmous_state, zaccaria_irq0b))
MCFG_PIA_READPA_HANDLER(READ8(catnmous_state, pia_porta_r))
MCFG_PIA_WRITEPA_HANDLER(WRITE8(catnmous_state, pia_porta_w))
MCFG_PIA_WRITEPB_HANDLER(WRITE8(catnmous_state, pia_portb_w))
MCFG_PIA_IRQA_HANDLER(WRITELINE(catnmous_state, pia_irqa))
MCFG_PIA_IRQB_HANDLER(WRITELINE(catnmous_state, pia_irqb))
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("ay1", AY8910, 3580000/2) // ?
MCFG_AY8910_PORT_B_READ_CB(READ8(driver_device, soundlatch_byte_r))
MCFG_SOUND_ADD("psg1", AY8910, 3580000/2) // ?
MCFG_AY8910_PORT_B_READ_CB(READ8(catnmous_state, psg1_portb_r))
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
MCFG_SOUND_ADD("ay2", AY8910, 3580000/2) // ?
MCFG_SOUND_ADD("psg2", AY8910, 3580000/2) // ?
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
MACHINE_CONFIG_END
@ -706,7 +640,7 @@ Sound Board 1b11107
6802
6821
8910
2*8910
*/
ROM_START( catnmous )
@ -746,8 +680,8 @@ ROM_START( catnmous )
ROM_LOAD( "82s100.13m", 0x0000, 0x00f5, CRC(6b724cdb) SHA1(8a0ca3b171b103661a3b2fffbca3d7162089e243) )
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "sound01.1d", 0xd000, 0x1000, CRC(f65cb9d0) SHA1(a2fe7563c6da055bf6aa20797b2d9fa184f0133c) )
ROM_LOAD( "sound01.1f", 0xe000, 0x1000, CRC(473c44de) SHA1(ff08b02d45a2c23cabb5db716aa203225a931424) )
ROM_LOAD( "sound01.1f", 0xc000, 0x1000, CRC(473c44de) SHA1(ff08b02d45a2c23cabb5db716aa203225a931424) )
ROM_LOAD( "sound01.1d", 0xe000, 0x1000, CRC(f65cb9d0) SHA1(a2fe7563c6da055bf6aa20797b2d9fa184f0133c) )
ROM_LOAD( "sound01.1e", 0xf000, 0x1000, CRC(1bd90c93) SHA1(20fd2b765a42e25cf7f716e6631b8c567785a866) )
ROM_END
@ -788,13 +722,13 @@ ROM_START( catnmousa )
ROM_LOAD( "catnmousa_82s100.13m", 0x0000, 0x00f5, CRC(6b724cdb) SHA1(8a0ca3b171b103661a3b2fffbca3d7162089e243) BAD_DUMP )
ROM_REGION( 0x10000, "audiocpu", 0 )
ROM_LOAD( "snd.1d", 0xd000, 0x1000, CRC(f65cb9d0) SHA1(a2fe7563c6da055bf6aa20797b2d9fa184f0133c) )
ROM_LOAD( "snd.1f", 0xe000, 0x1000, CRC(473c44de) SHA1(ff08b02d45a2c23cabb5db716aa203225a931424) )
ROM_LOAD( "snd.1f", 0xc000, 0x1000, CRC(473c44de) SHA1(ff08b02d45a2c23cabb5db716aa203225a931424) )
ROM_LOAD( "snd.1d", 0xe000, 0x1000, CRC(f65cb9d0) SHA1(a2fe7563c6da055bf6aa20797b2d9fa184f0133c) )
ROM_LOAD( "snd.1e", 0xf000, 0x1000, CRC(1bd90c93) SHA1(20fd2b765a42e25cf7f716e6631b8c567785a866) )
ROM_END
GAME( 1981, laserbat, 0, laserbat, laserbat, laserbat_state_base, laserbat, ROT0, "Zaccaria", "Laser Battle", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1981, lazarian, laserbat, laserbat, lazarian, laserbat_state_base, laserbat, ROT0, "Zaccaria (Bally Midway license)", "Lazarian", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1982, catnmous, 0, catnmous, catnmous, laserbat_state_base, laserbat, ROT90, "Zaccaria", "Cat and Mouse (set 1)", MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE)
GAME( 1982, catnmousa,catnmous, catnmous, catnmous, laserbat_state_base, laserbat, ROT90, "Zaccaria", "Cat and Mouse (set 2)", MACHINE_NO_SOUND | MACHINE_SUPPORTS_SAVE)
GAME( 1981, laserbat, 0, laserbat, laserbat, laserbat_state_base, laserbat, ROT0, "Zaccaria", "Laser Battle", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1981, lazarian, laserbat, laserbat, lazarian, laserbat_state_base, laserbat, ROT0, "Zaccaria (Bally Midway license)", "Lazarian", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1982, catnmous, 0, catnmous, catnmous, laserbat_state_base, laserbat, ROT90, "Zaccaria", "Cat and Mouse (set 1)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )
GAME( 1982, catnmousa, catnmous, catnmous, catnmous, laserbat_state_base, laserbat, ROT90, "Zaccaria", "Cat and Mouse (set 2)", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE )

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:Pierpaolo Prazzoli, Vas Crabb
// copyright-holders:Vas Crabb
/*************************************************************************
Laser Battle / Lazarian - Cat and Mouse
@ -185,43 +185,42 @@ class catnmous_state : public laserbat_state_base
public:
catnmous_state(const machine_config &mconfig, device_type type, const char *tag)
: laserbat_state_base(mconfig, type, tag)
, m_pia(*this, "pia")
, m_audiocpu(*this, "audiocpu")
, m_ay1(*this, "ay1")
, m_ay2(*this, "ay2")
, m_active_8910(0)
, m_port0a(0)
, m_last_port0b(0)
, m_cb1_toggle(0)
, m_pia(*this, "pia")
, m_psg1(*this, "psg1")
, m_psg2(*this, "psg2")
, m_cb1(false)
{
}
// control ports
DECLARE_WRITE_LINE_MEMBER(zaccaria_irq0a);
DECLARE_WRITE_LINE_MEMBER(zaccaria_irq0b);
DECLARE_READ8_MEMBER(zaccaria_port0a_r);
DECLARE_WRITE8_MEMBER(zaccaria_port0a_w);
DECLARE_WRITE8_MEMBER(zaccaria_port0b_w);
// sound control ports
virtual DECLARE_WRITE8_MEMBER(csound1_w) override;
// PIA handlers
DECLARE_READ8_MEMBER(pia_porta_r);
DECLARE_WRITE8_MEMBER(pia_porta_w);
DECLARE_WRITE8_MEMBER(pia_portb_w);
DECLARE_WRITE_LINE_MEMBER(pia_irqa);
DECLARE_WRITE_LINE_MEMBER(pia_irqb);
// PSG handlers
DECLARE_WRITE8_MEMBER(psg1_porta_w);
DECLARE_READ8_MEMBER(psg1_portb_r);
// periodic signal generators
INTERRUPT_GEN_MEMBER(zaccaria_cb1_toggle);
INTERRUPT_GEN_MEMBER(cb1_toggle);
protected:
// initialisation/startup
virtual void machine_start() override;
virtual void machine_reset() override;
// sound board devices
required_device<pia6821_device> m_pia;
required_device<cpu_device> m_audiocpu;
required_device<ay8910_device> m_ay1;
required_device<ay8910_device> m_ay2;
required_device<pia6821_device> m_pia;
required_device<ay8910_device> m_psg1;
required_device<ay8910_device> m_psg2;
// control line states
int m_active_8910;
int m_port0a;
int m_last_port0b;
int m_cb1_toggle;
bool m_cb1;
};

View File

@ -53,7 +53,8 @@
up indicating when player 2 is playing. In a cocktail cabinet this
goes to an "image commutation board". It's not connected to
anything in an upright cabinet. The "image commutation board" must
flip the image somehow, presumably by dark magic.
flip the image somehow, presumably by reversing the deflection coil
connections.
There are still issues with horizontal alignment between layers. I
have the schematic, yet I really can't understand where these issues