summaryrefslogblamecommitdiffstatshomepage
path: root/src/mame/audio/gottlieb.cpp
blob: 58cbd11cedb1c28726fc9fc7e9128c29b8a03606 (plain) (tree)
1
2
3
4
5
6
7
8
9

                                

                                                                            
              


                                                       
                                                                 
 

                                                                            
                
                           
                      
                           

 


                                           

 


                                                                            
 



                                                                                                                                       
 
 
                                                                            






                                                                            
                                                                                                                                   
                                                                   


                                                





















                                                   

                                                     








                                                   






                                                                                                 


                                                   




                                                   
                                                                                                                                                                             







                                                                                                        
                                                                             



                                                   
                                                

                                                   
                                                                  
                    

                                                                                                                                


                                                                                  

                                                                               

                        
                                                                                                         
                                                                                        
                                                                                                                
                  






















                                                                            






                                                                            
                                                                                                                                   
                                                                                   


 


                                                   

                                

                                                    




                                                
 

 





                                                   
 
                                                                                     

                                           
                                                       
 

 


                                                   
 
                                                            
 





                                                          
          
                                                   
 



                                                                                             


 
                                                   
                                                  




                                                        
                                



                                                                 




                                                   
                                



                                                             


                                                             
                                



                                                
                                                                 
 
                                                                                                   
                                                








                                                                                             
                                         








                                                             

                                                   
 

                                                                      
                                                     







                                                                                                                 

 
                                                   

                                                   
 
                                      
                         





                                                     
                                                                                     

                                                  
                                          

               


                                                  
                                                                                                              
               
 
 
                                                   
                                                
                                                   
 
                                                                  
                    

                                                                                                



                                                         

                                                                                       

                        
                                                                                                         
                                                                                        
                                                                                                                
                  

 





                                                                       
 
                                                     
 

 




                                                   
 
 
 
 





                                                                            

                                          

                                                   
                                                                                                                                                           
                                                                                          
 

 
 
                                                   
                                                
                                                   
 
                                                                              



                                                             
                                                                                                     
                                                 
                  
 
 





                                                                                   
 
                                                                 
 
 
 








                                                                            
                                                                                                                                   
                                                                    


                                                       



                                         
                                     







                                     
 
 
 
 
                                                   

                                                   
 






                                                                                                  
 







                                                                                 

 
 

                                                   
                                     


                                                        
 

                                                                                             

 
 

                                                   
                                              






                                                                                                                        
 
 

                                                   
                      


                                                      
 

                                                               

 
 

                                                   
                       


                                                       
 

                                                                

 
 

                                                   
                               


                                                             
 


                                                                
 
 

                                                   
       
                                                   
 




                                                                    
 
 
                                                   

                                           
                                                   
 

                                                                    
                                 

 

                                                   

                                            
                                                   
 

                                                           
                                            
                                
 

                                              
 
                                                  
 


                                                                        
         





                                                                        
                                                                                     
                            
                                                                                     
                 


            





                                                       
                                                                          

                                                               
                 
         
 


                                                                                         
                                                         
                                                          
 
                                                  
                                     
                                  
 
 
 

                                                   
                  
                                                   
 
                                                      
 

                           
 
 
                                                   

                                             
                                                   
 



                                                         

 


                                                   
 







                                                                                                 

 



                                                   











                                                                                                       
 
 
                                                   













                                                                                     
                                                                                                                                            




                                                   
                                                   
 
                                                                  
                     

                                                          
 

                                                           
 
                         

                                                                                                          
                                                                                                                
                                                                                        
                                                              
 
                                                      
                                                  
 
                                                      
                                                  
 
                                                             
                                                 
                  
 
 
                                                   




















                                                                       
























                                                                                                       
                                                                                      




                                                                                     
 




                                           
 






                                                     
 
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************

    gottlieb.c

    Gottlieb 6502-based sound hardware implementations.

    Dedicated to Warren Davis, Jeff Lee, Tim Skelly & David Thiel

***************************************************************************/

#include "emu.h"
#include "audio/gottlieb.h"
#include "sound/dac.h"
#include "sound/volt_reg.h"


#define SOUND1_CLOCK        XTAL(3'579'545)
#define SOUND2_CLOCK        XTAL(4'000'000)
#define SOUND2_SPEECH_CLOCK XTAL(3'120'000)


//**************************************************************************
//  GLOBAL VARIABLES
//**************************************************************************

DEFINE_DEVICE_TYPE(GOTTLIEB_SOUND_REV0,        gottlieb_sound_r0_device,             "gotsndr0",   "Gottlieb Sound rev. 0")
DEFINE_DEVICE_TYPE(GOTTLIEB_SOUND_REV1,        gottlieb_sound_r1_device,             "gotsndr1",   "Gottlieb Sound rev. 1")
DEFINE_DEVICE_TYPE(GOTTLIEB_SOUND_REV1_VOTRAX, gottlieb_sound_r1_with_votrax_device, "gotsndr1vt", "Gottlieb Sound rev. 1 with Votrax")
DEFINE_DEVICE_TYPE(GOTTLIEB_SOUND_REV2,        gottlieb_sound_r2_device,             "gotsndr2",   "Gottlieb Sound rev. 2")


//**************************************************************************
//  REV 0 SOUND BOARD: 6502 + 6530 + DAC
//**************************************************************************

//-------------------------------------------------
//  gottlieb_sound_r0_device - constructors
//-------------------------------------------------

gottlieb_sound_r0_device::gottlieb_sound_r0_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, GOTTLIEB_SOUND_REV0, tag, owner, clock)
	, device_mixer_interface(mconfig, *this)
	, m_audiocpu(*this, "audiocpu")
	, m_r6530(*this, "r6530")
	, m_sndcmd(0)
{
}


//-------------------------------------------------
//  read port -
//-------------------------------------------------

READ8_MEMBER( gottlieb_sound_r0_device::r6530b_r )
{
	return m_sndcmd;
}


//-------------------------------------------------
//  write - handle an external command write
//-------------------------------------------------

WRITE8_MEMBER( gottlieb_sound_r0_device::write )
{
	// write the command data to the low 4 bits
	uint8_t pb0_3 = data ^ 15;
	uint8_t pb4_7 = ioport("SB0")->read() & 0x90;
	m_sndcmd = pb0_3 | pb4_7;
	m_r6530->write(space, offset, m_sndcmd);
}


//-------------------------------------------------
//  audio CPU map
//-------------------------------------------------

void gottlieb_sound_r0_device::gottlieb_sound_r0_map(address_map &map)
{
	map.global_mask(0x0fff);
	map(0x0000, 0x003f).ram().mirror(0x1c0);
	map(0x0200, 0x020f).rw("r6530", FUNC(mos6530_device::read), FUNC(mos6530_device::write));
	map(0x0400, 0x0fff).rom();
}


//-------------------------------------------------
//  input ports
//-------------------------------------------------

INPUT_PORTS_START( gottlieb_sound_r0 )
	PORT_START("SB0")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Audio Diag") PORT_CODE(KEYCODE_0) PORT_CHANGED_MEMBER(DEVICE_SELF, gottlieb_sound_r0_device, audio_nmi, nullptr)
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Attract") PORT_CODE(KEYCODE_F1) PORT_TOGGLE
	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Music") PORT_CODE(KEYCODE_F2) PORT_TOGGLE
INPUT_PORTS_END

INPUT_CHANGED_MEMBER( gottlieb_sound_r0_device::audio_nmi )
{
	// Diagnostic button sends a pulse to NMI pin
	if (newval==CLEAR_LINE)
		m_audiocpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
}


//-------------------------------------------------
// device_add_mconfig - add device configuration
//-------------------------------------------------

MACHINE_CONFIG_START(gottlieb_sound_r0_device::device_add_mconfig)
	// audio CPU
	MCFG_DEVICE_ADD("audiocpu", M6502, SOUND1_CLOCK/4) // M6503 - clock is a gate, a resistor and a capacitor. Freq unknown.
	MCFG_DEVICE_PROGRAM_MAP(gottlieb_sound_r0_map)

	// I/O configuration
	MCFG_DEVICE_ADD("r6530", MOS6530, SOUND1_CLOCK/4) // unknown - same as cpu
	MCFG_MOS6530_OUT_PA_CB(WRITE8("dac", dac_byte_interface, write))
	MCFG_MOS6530_IN_PB_CB(READ8(*this, gottlieb_sound_r0_device, r6530b_r))

	// sound devices
	MCFG_DEVICE_ADD("dac", DAC_8BIT_R2R, 0) MCFG_SOUND_ROUTE(ALL_OUTPUTS, *this, 0.25) // unknown DAC
	MCFG_DEVICE_ADD("vref", VOLTAGE_REGULATOR, 0) MCFG_VOLTAGE_REGULATOR_OUTPUT(5.0)
	MCFG_SOUND_ROUTE(0, "dac", 1.0, DAC_VREF_POS_INPUT) MCFG_SOUND_ROUTE(0, "dac", -1.0, DAC_VREF_NEG_INPUT)
MACHINE_CONFIG_END


//-------------------------------------------------
//  device_input_ports - return a pointer to
//  the device's I/O ports
//-------------------------------------------------

ioport_constructor gottlieb_sound_r0_device::device_input_ports() const
{
	return INPUT_PORTS_NAME( gottlieb_sound_r0 );
}


//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void gottlieb_sound_r0_device::device_start()
{
}


//**************************************************************************
//  REV 1 SOUND BOARD: 6502 + DAC
//**************************************************************************

//-------------------------------------------------
//  gottlieb_sound_r1_device - constructors
//-------------------------------------------------

gottlieb_sound_r1_device::gottlieb_sound_r1_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gottlieb_sound_r1_device(mconfig, GOTTLIEB_SOUND_REV1, tag, owner, clock)
{
}

gottlieb_sound_r1_device::gottlieb_sound_r1_device(
		const machine_config &mconfig,
		device_type type,
		const char *tag,
		device_t *owner,
		uint32_t clock)
	: device_t(mconfig, type, tag, owner, clock)
	, device_mixer_interface(mconfig, *this)
	, m_audiocpu(*this, "audiocpu")
	, m_riot(*this, "riot")
	, m_votrax(*this, "votrax")
	, m_last_speech_clock(0)
{
}


//-------------------------------------------------
//  write - handle an external command write
//-------------------------------------------------

WRITE8_MEMBER( gottlieb_sound_r1_device::write )
{
	// write the command data to the low 6 bits, and the trigger to the upper bit
	uint8_t pa7 = (data & 0x0f) != 0xf;
	uint8_t pa0_5 = ~data & 0x3f;
	m_riot->porta_in_set(pa0_5 | (pa7 << 7), 0xbf);
}


//-------------------------------------------------
//  snd_interrupt - signal a sound interrupt
//-------------------------------------------------

WRITE_LINE_MEMBER( gottlieb_sound_r1_device::snd_interrupt )
{
	m_audiocpu->set_input_line(M6502_IRQ_LINE, state);
}


//-------------------------------------------------
//  r6532_portb_w - handle writes to the RIOT's
//  port B
//-------------------------------------------------

WRITE8_MEMBER( gottlieb_sound_r1_device::r6532_portb_w )
{
	// unsure if this is ever used, but the NMI is connected to the RIOT's PB7
	m_audiocpu->set_input_line(INPUT_LINE_NMI, (data & 0x80) ? CLEAR_LINE : ASSERT_LINE);
}


//-------------------------------------------------
//  votrax_data_w - write data to the Votrax SC-01
//  speech chip
//-------------------------------------------------

WRITE8_MEMBER( gottlieb_sound_r1_device::votrax_data_w )
{
	if (m_votrax != nullptr)
	{
		m_votrax->inflection_w(space, offset, data >> 6);
		m_votrax->write(space, offset, ~data & 0x3f);
	}
}


//-------------------------------------------------
//  speech_clock_dac_w - modify the clock driving
//  the Votrax SC-01 speech chip
//-------------------------------------------------

WRITE8_MEMBER( gottlieb_sound_r1_device::speech_clock_dac_w )
{
	// prevent negative clock values (and possible crash)
	if (data < 0x65) data = 0x65;

	if (m_votrax != nullptr)
	{
		// nominal clock is 0xa0
		if (data != m_last_speech_clock)
		{
			osd_printf_debug("clock = %02X\n", data);

			// totally random guesswork; would like to get real measurements on a board
			if (m_votrax != nullptr)
				m_votrax->set_unscaled_clock(600000 + (data - 0xa0) * 10000);
			m_last_speech_clock = data;
		}
	}
}


//-------------------------------------------------
//  votrax_request - map the VOTRAX SC-01 request
//  line to the NMI pin on the sound chip
//-------------------------------------------------

WRITE_LINE_MEMBER( gottlieb_sound_r1_device::votrax_request )
{
	m_audiocpu->set_input_line(INPUT_LINE_NMI, state);
}


//-------------------------------------------------
//  audio CPU map
//-------------------------------------------------

void gottlieb_sound_r1_device::gottlieb_sound_r1_map(address_map &map)
{
	// A15 not decoded except in expansion socket
	map.global_mask(0x7fff);
	map(0x0000, 0x007f).mirror(0x0d80).ram();
	map(0x0200, 0x021f).mirror(0x0de0).rw("riot", FUNC(riot6532_device::read), FUNC(riot6532_device::write));
	map(0x1000, 0x1000).mirror(0x0fff).w("dac", FUNC(dac_byte_interface::write));
	map(0x2000, 0x2000).mirror(0x0fff).w(this, FUNC(gottlieb_sound_r1_device::votrax_data_w));
	map(0x3000, 0x3000).mirror(0x0fff).w(this, FUNC(gottlieb_sound_r1_device::speech_clock_dac_w));
	map(0x6000, 0x7fff).rom();
}


//-------------------------------------------------
//  input ports
//-------------------------------------------------

INPUT_PORTS_START( gottlieb_sound_r1 )
	PORT_START("SB1")
	PORT_DIPUNKNOWN_DIPLOC( 0x01, 0x01, "SB1:7" )
	PORT_DIPUNKNOWN_DIPLOC( 0x02, 0x02, "SB1:6" )
	PORT_DIPUNKNOWN_DIPLOC( 0x04, 0x04, "SB1:5" )
	PORT_DIPUNKNOWN_DIPLOC( 0x08, 0x08, "SB1:1" )
	PORT_DIPUNKNOWN_DIPLOC( 0x10, 0x10, "SB1:4" )
	PORT_DIPUNKNOWN_DIPLOC( 0x20, 0x20, "SB1:3" )
	PORT_DIPNAME( 0x40, 0x40, "Sound Test" )            PORT_DIPLOCATION("SB1:2")
	PORT_DIPSETTING(    0x40, DEF_STR( Off ) )
	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
	PORT_BIT( 0x80, 0x80, IPT_CUSTOM )
INPUT_PORTS_END

INPUT_PORTS_START( gottlieb_sound_r1_with_votrax )
	PORT_INCLUDE(gottlieb_sound_r1)
	PORT_MODIFY("SB1")
	PORT_BIT( 0x80, 0x80, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER("votrax", votrax_sc01_device, request)
INPUT_PORTS_END


//-------------------------------------------------
// device_add_mconfig - add device configuration
//-------------------------------------------------

MACHINE_CONFIG_START(gottlieb_sound_r1_device::device_add_mconfig)
	// audio CPU
	MCFG_DEVICE_ADD("audiocpu", M6502, SOUND1_CLOCK/4) // the board can be set to /2 as well
	MCFG_DEVICE_PROGRAM_MAP(gottlieb_sound_r1_map)

	// I/O configuration
	MCFG_DEVICE_ADD("riot", RIOT6532, SOUND1_CLOCK/4)
	MCFG_RIOT6532_IN_PB_CB(IOPORT("SB1"))
	MCFG_RIOT6532_OUT_PB_CB(WRITE8(*this, gottlieb_sound_r1_device, r6532_portb_w))
	MCFG_RIOT6532_IRQ_CB(WRITELINE(*this, gottlieb_sound_r1_device, snd_interrupt))

	// sound devices
	MCFG_DEVICE_ADD("dac", DAC_8BIT_R2R, 0) MCFG_SOUND_ROUTE(ALL_OUTPUTS, *this, 0.25) // unknown DAC
	MCFG_DEVICE_ADD("vref", VOLTAGE_REGULATOR, 0) MCFG_VOLTAGE_REGULATOR_OUTPUT(5.0)
	MCFG_SOUND_ROUTE(0, "dac", 1.0, DAC_VREF_POS_INPUT) MCFG_SOUND_ROUTE(0, "dac", -1.0, DAC_VREF_NEG_INPUT)
MACHINE_CONFIG_END


//-------------------------------------------------
//  device_input_ports - return a pointer to
//  the device's I/O ports
//-------------------------------------------------

ioport_constructor gottlieb_sound_r1_device::device_input_ports() const
{
	return INPUT_PORTS_NAME( gottlieb_sound_r1 );
}


//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void gottlieb_sound_r1_device::device_start()
{
}



//**************************************************************************
//  REV 1 SOUND BOARD WITH VOTRAX
//**************************************************************************

//-------------------------------------------------
//  gottlieb_sound_r1_with_votrax_device -
//  constructor
//-------------------------------------------------

gottlieb_sound_r1_with_votrax_device::gottlieb_sound_r1_with_votrax_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: gottlieb_sound_r1_device(mconfig, GOTTLIEB_SOUND_REV1_VOTRAX, tag, owner, clock)
{
}


//-------------------------------------------------
// device_add_mconfig - add device configuration
//-------------------------------------------------

MACHINE_CONFIG_START(gottlieb_sound_r1_with_votrax_device::device_add_mconfig)
	gottlieb_sound_r1_device::device_add_mconfig(config);

	// add the VOTRAX
	MCFG_DEVICE_ADD("votrax", VOTRAX_SC01, 720000)
	MCFG_VOTRAX_SC01_REQUEST_CB(WRITELINE(DEVICE_SELF, gottlieb_sound_r1_device, votrax_request))
	MCFG_SOUND_ROUTE(ALL_OUTPUTS, *this, 0.5)
MACHINE_CONFIG_END


//-------------------------------------------------
//  device_input_ports - return a pointer to
//  the device's I/O ports
//-------------------------------------------------

ioport_constructor gottlieb_sound_r1_with_votrax_device::device_input_ports() const
{
	return INPUT_PORTS_NAME( gottlieb_sound_r1_with_votrax );
}



//**************************************************************************
//  REV 2 SOUND BOARD: 6502 + 2 x DAC + 2 x AY-8913
//**************************************************************************

//-------------------------------------------------
//  gottlieb_sound_r2_device - constructor
//-------------------------------------------------

gottlieb_sound_r2_device::gottlieb_sound_r2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, GOTTLIEB_SOUND_REV2, tag, owner, clock),
		device_mixer_interface(mconfig, *this),
		m_audiocpu(*this, "audiocpu"),
		m_speechcpu(*this, "speechcpu"),
		m_ay1(*this, "ay1"),
		m_ay2(*this, "ay2"),
		m_sp0250(*this, "spsnd"),
		m_cobram3_mod(false),
		m_nmi_timer(nullptr),
		m_nmi_state(0),
		m_audiocpu_latch(0),
		m_speechcpu_latch(0),
		m_speech_control(0),
		m_last_command(0),
		m_psg_latch(0),
		m_psg_data_latch(0),
		m_sp0250_latch(0)
{
}


//-------------------------------------------------
//  write - handle an external command write
//-------------------------------------------------

WRITE8_MEMBER( gottlieb_sound_r2_device::write )
{
	// when data is not 0xff, the transparent latch at A3 allows it to pass through unmolested
	if (data != 0xff)
	{
		// latch data on a timer
		synchronize(TID_SOUND_LATCH_WRITE, data);

		// if the previous data was 0xff, clock an IRQ on each
		if (m_last_command == 0xff)
		{
			m_audiocpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE);
			m_speechcpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE);
		}
	}
	m_last_command = data;
}


//-------------------------------------------------
//  nmi_timer_adjust - adjust the NMI timer to
//  fire based on its configured rate
//-------------------------------------------------

inline void gottlieb_sound_r2_device::nmi_timer_adjust()
{
	// adjust timer to go off in the future based on the current rate
	m_nmi_timer->adjust(attotime::from_hz(SOUND2_CLOCK/16) * (256 * (256 - m_nmi_rate)));
}


//-------------------------------------------------
//  nmi_state_update - update the NMI state based
//  on the timer firing and the enable control
//-------------------------------------------------

inline void gottlieb_sound_r2_device::nmi_state_update()
{
	// update the NMI line state based on the enable and state
	m_speechcpu->set_input_line(INPUT_LINE_NMI, (m_nmi_state && (m_speech_control & 1)) ? ASSERT_LINE : CLEAR_LINE);
}


//-------------------------------------------------
//  speech_data_r - read the input command latch
//  from the audio CPU
//-------------------------------------------------

READ8_MEMBER( gottlieb_sound_r2_device::audio_data_r )
{
	m_audiocpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE);
	return m_audiocpu_latch;
}


//-------------------------------------------------
//  speech_data_r - read the input command latch
//  from the speech CPU
//-------------------------------------------------

READ8_MEMBER( gottlieb_sound_r2_device::speech_data_r )
{
	m_speechcpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE);
	return m_speechcpu_latch;
}


//-------------------------------------------------
//  signal_audio_nmi_w - signal an NMI from the
//  speech CPU to the audio CPU
//-------------------------------------------------

WRITE8_MEMBER( gottlieb_sound_r2_device::signal_audio_nmi_w )
{
	m_audiocpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
	m_audiocpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
}


//-------------------------------------------------
//  nmi_rate_w - adjust the NMI rate on the speech
//  CPU
//-------------------------------------------------

WRITE8_MEMBER( gottlieb_sound_r2_device::nmi_rate_w )
{
	// the new rate is picked up when the previous timer expires
	m_nmi_rate = data;
}


//-------------------------------------------------
//  speech_drq_custom_r - return the SP0250
//  request line as an input port bit
//-------------------------------------------------

CUSTOM_INPUT_MEMBER( gottlieb_sound_r2_device::speech_drq_custom_r )
{
	return m_sp0250->drq_r();
}


//-------------------------------------------------
//  speech_control_w - primary audio control
//  register on the speech board
//-------------------------------------------------

WRITE8_MEMBER( gottlieb_sound_r2_device::speech_control_w )
{
	uint8_t previous = m_speech_control;
	m_speech_control = data;

	// bit 0 enables/disables the NMI line
	nmi_state_update();

	// bit 1 controls a LED on the sound board

	// bits 2-4 control the AY-8913, but act differently between the
	// standard sound board and the modified Cobra Command board
	if (!m_cobram3_mod)
	{
		// bit 2 goes to 8913 BDIR pin
		if ((previous & 0x04) != 0 && (data & 0x04) == 0)
		{
			// bit 3 selects which of the two 8913 to enable
			// bit 4 goes to the 8913 BC1 pin
			if ((data & 0x08) != 0)
				m_ay1->data_address_w(space, data >> 4, m_psg_latch);
			else
				m_ay2->data_address_w(space, data >> 4, m_psg_latch);
		}
	}
	else
	{
		if ( data & 0x10 )
		{
			m_psg_data_latch = m_psg_latch;
		}
		else
		{
			ay8913_device *ay = (data & 0x08) ? m_ay1 : m_ay2;
			ay->address_w(space, 0, m_psg_latch);
			ay->data_w(space, 0, m_psg_data_latch);
		}
	}

	// bit 5 goes to the speech chip DIRECT DATA TEST pin

	// bit 6 = speech chip DATA PRESENT pin; high then low to make the chip read data
	if ((previous & 0x40) == 0 && (data & 0x40) != 0)
		m_sp0250->write(space, 0, m_sp0250_latch);

	// bit 7 goes to the speech chip RESET pin
	if ((previous ^ data) & 0x80)
		m_sp0250->reset();
}


//-------------------------------------------------
//  psg_latch_w - store an 8-bit value in the PSG
//  latch register
//-------------------------------------------------

WRITE8_MEMBER( gottlieb_sound_r2_device::psg_latch_w )
{
	m_psg_latch = data;
}


//-------------------------------------------------
//  psg_latch_w - store an 8-bit value in the
//  SP0250 latch register
//-------------------------------------------------

WRITE8_MEMBER( gottlieb_sound_r2_device::sp0250_latch_w )
{
	m_sp0250_latch = data;
}


//-------------------------------------------------
//  sound CPU address map
//-------------------------------------------------

void gottlieb_sound_r2_device::gottlieb_sound_r2_map(address_map &map)
{
	map(0x0000, 0x03ff).mirror(0x3c00).ram();
	map(0x4000, 0x4000).mirror(0x3ffe).w("dacvol", FUNC(dac_byte_interface::write));
	map(0x4001, 0x4001).mirror(0x3ffe).w("dac", FUNC(dac_byte_interface::write));
	map(0x8000, 0x8000).mirror(0x3fff).r(this, FUNC(gottlieb_sound_r2_device::audio_data_r));
	map(0xc000, 0xdfff).mirror(0x2000).rom();
}


//-------------------------------------------------
//  sppech CPU address map
//-------------------------------------------------

void gottlieb_sound_r2_device::gottlieb_speech_r2_map(address_map &map)
{
	map(0x0000, 0x03ff).mirror(0x1c00).ram();
	map(0x2000, 0x2000).mirror(0x1fff).w(this, FUNC(gottlieb_sound_r2_device::sp0250_latch_w));
	map(0x4000, 0x4000).mirror(0x1fff).w(this, FUNC(gottlieb_sound_r2_device::speech_control_w));
	map(0x6000, 0x6000).mirror(0x1fff).portr("SB2");
	map(0x8000, 0x8000).mirror(0x1fff).w(this, FUNC(gottlieb_sound_r2_device::psg_latch_w));
	map(0xa000, 0xa000).mirror(0x07ff).w(this, FUNC(gottlieb_sound_r2_device::nmi_rate_w));
	map(0xa800, 0xa800).mirror(0x07ff).r(this, FUNC(gottlieb_sound_r2_device::speech_data_r));
	map(0xb000, 0xb000).mirror(0x07ff).w(this, FUNC(gottlieb_sound_r2_device::signal_audio_nmi_w));
	map(0xc000, 0xffff).rom();
}


//-------------------------------------------------
//  input ports
//-------------------------------------------------

INPUT_PORTS_START( gottlieb_sound_r2 )
	PORT_START("SB2")
	PORT_DIPUNKNOWN_DIPLOC( 0x01, 0x01, "SB2:1")
	PORT_DIPUNKNOWN_DIPLOC( 0x02, 0x02, "SB2:2")
	PORT_DIPUNKNOWN_DIPLOC( 0x04, 0x04, "SB2:3")
	PORT_DIPUNKNOWN_DIPLOC( 0x08, 0x08, "SB2:4")
	PORT_DIPUNKNOWN_DIPLOC( 0x10, 0x10, "SB2:5")
	PORT_DIPUNKNOWN_DIPLOC( 0x20, 0x20, "SB2:6")
	PORT_DIPNAME( 0x40, 0x40, "Sound Test" )            PORT_DIPLOCATION("SB2:7")
	PORT_DIPSETTING(    0x40, DEF_STR( Off ) )
	PORT_DIPSETTING(    0x00, DEF_STR( On ) )
	PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(DEVICE_SELF, gottlieb_sound_r2_device, speech_drq_custom_r, nullptr)
INPUT_PORTS_END


//-------------------------------------------------
// device_add_mconfig - add device configuration
//-------------------------------------------------

MACHINE_CONFIG_START(gottlieb_sound_r2_device::device_add_mconfig)
	// audio CPUs
	MCFG_DEVICE_ADD("audiocpu", M6502, SOUND2_CLOCK/4)
	MCFG_DEVICE_PROGRAM_MAP(gottlieb_sound_r2_map)

	MCFG_DEVICE_ADD("speechcpu", M6502, SOUND2_CLOCK/4)
	MCFG_DEVICE_PROGRAM_MAP(gottlieb_speech_r2_map)

	// sound hardware
	MCFG_DEVICE_ADD("dac", DAC_8BIT_R2R, 0) MCFG_SOUND_ROUTE(ALL_OUTPUTS, *this, 0.075) // unknown DAC
	MCFG_DEVICE_ADD("dacvol", DAC_8BIT_R2R, 0) // unknown DAC
	MCFG_SOUND_ROUTE(0, "dac", 1.0, DAC_VREF_POS_INPUT) MCFG_SOUND_ROUTE(0, "dac", -1.0, DAC_VREF_NEG_INPUT)
	MCFG_DEVICE_ADD("vref", VOLTAGE_REGULATOR, 0) MCFG_VOLTAGE_REGULATOR_OUTPUT(5.0)
	MCFG_SOUND_ROUTE(0, "dacvol", 1.0, DAC_VREF_POS_INPUT)

	MCFG_DEVICE_ADD("ay1", AY8913, SOUND2_CLOCK/2)
	MCFG_SOUND_ROUTE(ALL_OUTPUTS, *this, 0.15)

	MCFG_DEVICE_ADD("ay2", AY8913, SOUND2_CLOCK/2)
	MCFG_SOUND_ROUTE(ALL_OUTPUTS, *this, 0.15)

	MCFG_DEVICE_ADD("spsnd", SP0250, SOUND2_SPEECH_CLOCK)
	MCFG_SOUND_ROUTE(ALL_OUTPUTS, *this, 1.0)
MACHINE_CONFIG_END


//-------------------------------------------------
//  device_input_ports - return a pointer to
//  the device's I/O ports
//-------------------------------------------------

ioport_constructor gottlieb_sound_r2_device::device_input_ports() const
{
	return INPUT_PORTS_NAME( gottlieb_sound_r2 );
}


//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void gottlieb_sound_r2_device::device_start()
{
	// set up the NMI timer
	m_nmi_timer = timer_alloc(TID_NMI_GENERATE);
	m_nmi_rate = 0;
	nmi_timer_adjust();

	// disable the non-speech CPU for cobram3
	if (m_cobram3_mod)
		m_audiocpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);

	// register for save states
	save_item(NAME(m_nmi_rate));
	save_item(NAME(m_nmi_state));
	save_item(NAME(m_speech_control));
	save_item(NAME(m_last_command));
}


//-------------------------------------------------
//  device_timer - handle timer-based behaviors
//-------------------------------------------------

void gottlieb_sound_r2_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	switch (id)
	{
		case TID_NMI_GENERATE:
			// update state
			m_nmi_state = 1;
			nmi_state_update();

			// set a timer to turn it off again on the next SOUND_CLOCK/16
			timer_set(attotime::from_hz(SOUND2_CLOCK/16), TID_NMI_CLEAR);

			// adjust the NMI timer for the next time
			nmi_timer_adjust();
			break;

		case TID_NMI_CLEAR:
			// update state
			m_nmi_state = 0;
			nmi_state_update();
			break;

		case TID_SOUND_LATCH_WRITE:
			// each CPU has its own latch
			m_audiocpu_latch = param;
			m_speechcpu_latch = param;
			break;
	}
}