summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/sound/dave.cpp
blob: 4ca7248a52090a6e8b8980117ab98f6fb87f468c (plain) (tree)
1
2
3
4
5
6
7
8
9

                               

                                                                       
                                      
 
                                                                       
 
                
                 
 

                     
 
 


                                                                            
 


                    
 


                                                                            
 
                                                                        

 

                                                   
                                                                                           



                                              
                                                                                 
 
 
 


                                               
 


                                          





                                                                            
 
                                                   
                             
                                                   
 
                                                                                                         
                                                     

                                                        

                                                                                                                                              

                                   

                                  
 

 
 


                                                   
 
                                
 







                                                                           
 













                                                                                  

                                                                 
 

                                                                 
 

                                   
 

                                      
 

                                       
 

                                          
 
                                                        
                                                                                
 
                                               
                                                                                                  

 
 


                                                   
 
                                
 

                                

                                     



                         

                                  


 


                                                   
 
                                                                                          
 







                                                      
 

                                                 
 





                                                       


 



                                                   
 
                                                                                     
 
                                    


                                                                    
 
 
 


                                                   
 









                                                                                                                             
 
                                      
 

                             
 


                           
 


                                                                          
 





























                                                                                                        
 
                                           
 












                                                                                                        
 

                                                                                                                  
 

                                            
 
                          
         

 
 














                                                   


 


                                                   
 
                                        
 

                                                
 



                                          
 

                           
 
 


                                                   
 

                                      
                                                  
                                                     
 
                                                         
 
 
 


                                                   
 

                                       
                                                  

                                                     
                                                         








                                                   
                         

                              
         

























                            
 


                                                   
 




                                    
                                                            

         
                    


 


                                                   
 
                                  
 
                              

                                            

                          
                                            

                          
                                            



                                              
                                                                  
 
                                                               
 
                                                       

 

                                                      
                                 

                                               
                                                                                                                   

                                              
 

                                               
                                                                                                                   
 

                                              
                                 
 
                                        

 
                                                                                                             
 
                                                             

                              

                                           
                          
                                           
                          
                                           
                          
                                               
                          
                                            
                          
                                            
                          
                                            
                          
                                                




                                                                                     
                                                                                          
 
                                                             




                              
 
                          

                                                                                                




                                                                                                  
 
                                                      



                                                 

                                                                                                                  




                                       

                                                                                                                




                                       
                                                                       




                                       
                                                                       









                                                                                    

                                                        

                                                     

                                                      

                                                      

                                                      

                                                      

                                                      



                                                  

                                                        

                                                  

                                                        

                                                   

                                                        

                                                   

                                                        





                                                                                     

                                                        

                                                      

                                                      

                                                      

                                                      

                                                      

                                                      



                                                   

                                                        

                                                   

                                                        

                                                   

                                                        

                                                   

                                                        
                         
 
                                                     


                      

                                                   
 
                                             
                      
 



                                                            
 
                                             
                      
 
                  
                                             

                      
                
                                                            


         
 
                                                   
                      

                                                   
                                    
 


                                                                                                  
 
// license:BSD-3-Clause
// copyright-holders:Curt Coder
/**********************************************************************

    Intelligent Designs DAVE emulation

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

#include "emu.h"
#include "dave.h"

//#define VERBOSE 1
#include "logmacro.h"


//**************************************************************************
//  MACROS / CONSTANTS
//**************************************************************************

#define STEP 0x08000



//**************************************************************************
//  DEVICE DEFINITIONS
//**************************************************************************

DEFINE_DEVICE_TYPE(DAVE, dave_device, "dave", "Inteligent Designs DAVE")


void dave_device::z80_program_map(address_map &map)
{
	map(0x0000, 0xffff).rw(FUNC(dave_device::program_r), FUNC(dave_device::program_w));
}

void dave_device::z80_io_map(address_map &map)
{
	map(0x0000, 0xffff).rw(FUNC(dave_device::io_r), FUNC(dave_device::io_w));
}


void dave_device::program_map(address_map &map)
{
}

void dave_device::io_map(address_map &map)
{
}



//**************************************************************************
//  LIVE DEVICE
//**************************************************************************

//-------------------------------------------------
//  dave_device - constructor
//-------------------------------------------------

dave_device::dave_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, DAVE, tag, owner, clock),
		device_memory_interface(mconfig, *this),
		device_sound_interface(mconfig, *this),
		m_program_space_config("program", ENDIANNESS_LITTLE, 8, 22, 0, address_map_constructor(FUNC(dave_device::program_map), this)),
		m_io_space_config("i/o", ENDIANNESS_LITTLE, 8, 16, 0, address_map_constructor(FUNC(dave_device::io_map), this)),
		m_write_irq(*this),
		m_write_lh(*this),
		m_write_rh(*this),
		m_irq_status(0)
{
}


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

void dave_device::device_start()
{
	// resolve callbacks
	m_write_irq.resolve_safe();
	m_write_lh.resolve_safe();
	m_write_rh.resolve_safe();

	// allocate timers
	m_timer_1hz = timer_alloc(TIMER_1HZ);
	m_timer_1hz->adjust(attotime::from_hz(2), 0, attotime::from_hz(2));

	m_timer_50hz = timer_alloc(TIMER_50HZ);
	m_timer_50hz->adjust(attotime::from_hz(2000), 0, attotime::from_hz(2000));

	// state saving
	save_item(NAME(m_segment));
	save_item(NAME(m_irq_status));
	save_item(NAME(m_irq_enable));
	save_item(NAME(m_period));
	save_item(NAME(m_count));
	save_item(NAME(m_level));
	save_item(NAME(m_level_or));
	save_item(NAME(m_level_and));
	save_item(NAME(m_mame_volumes));

	for (auto & elem : m_period)
		elem = (STEP * machine().sample_rate()) / 125000;

	for (auto & elem : m_count)
		elem = (STEP * machine().sample_rate()) / 125000;

	for (auto & elem : m_level)
		elem = 0;

	for (auto & elem : m_level_or)
		elem = 0;

	for (auto & elem : m_level_and)
		elem = 0;

	for (auto & elem : m_mame_volumes)
		elem = 0;

	/* dave has 3 tone channels and 1 noise channel.
	 the volumes are mixed internally and output as left and right volume */

	/* 3 tone channels + 1 noise channel */
	m_sound_stream_var = machine().sound().stream_alloc(*this, 0, 2, machine().sample_rate());
}


//-------------------------------------------------
//  device_reset - device-specific reset
//-------------------------------------------------

void dave_device::device_reset()
{
	m_write_irq(CLEAR_LINE);

	for (auto & elem : m_segment)
		elem = 0;

	m_irq_status = 0;
	m_irq_enable = 0;

	for (auto & elem : m_regs)
		elem = 0;
}


//-------------------------------------------------
//  device_timer - handler timer events
//-------------------------------------------------

void dave_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
	switch (id)
	{
	case TIMER_1HZ:
		m_irq_status ^= IRQ_1HZ_DIVIDER;

		if (m_irq_status & IRQ_1HZ_DIVIDER)
			m_irq_status |= IRQ_1HZ_LATCH;
		break;

	case TIMER_50HZ:
		m_irq_status ^= IRQ_50HZ_DIVIDER;

		if (m_irq_status & IRQ_50HZ_DIVIDER)
			m_irq_status |= IRQ_50HZ_LATCH;
		break;
	}

	update_interrupt();
}


//-------------------------------------------------
//  memory_space_config - return a description of
//  any address spaces owned by this device
//-------------------------------------------------

device_memory_interface::space_config_vector dave_device::memory_space_config() const
{
	return space_config_vector {
		std::make_pair(AS_PROGRAM, &m_program_space_config),
		std::make_pair(AS_IO,      &m_io_space_config)
	};
}


//-------------------------------------------------
//  sound_stream_update - handle a stream update
//-------------------------------------------------

void dave_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
	stream_sample_t *buffer1, *buffer2;
	/* 0 = channel 0 left volume, 1 = channel 0 right volume,
	 2 = channel 1 left volume, 3 = channel 1 right volume,
	 4 = channel 2 left volume, 5 = channel 2 right volume
	 6 = noise channel left volume, 7 = noise channel right volume */
	int output_volumes[8];
	int left_volume;
	int right_volume;

	//logerror("sound update!\n");

	buffer1 = outputs[0];
	buffer2 = outputs[1];

	while (samples)
	{
		int vol[4];

		/* vol[] keeps track of how long each square wave stays */
		/* in the 1 position during the sample period. */
		vol[0] = vol[1] = vol[2] = vol[3] = 0;

		for (int i = 0; i < 3; i++)
		{
			if ((m_regs[7] & (1 << i))==0)
			{
				if (m_level[i]) vol[i] += m_count[i];
				m_count[i] -= STEP;
				/* Period[i] is the half period of the square wave. Here, in each */
				/* loop I add Period[i] twice, so that at the end of the loop the */
				/* square wave is in the same status (0 or 1) it was at the start. */
				/* vol[i] is also incremented by Period[i], since the wave has been 1 */
				/* exactly half of the time, regardless of the initial position. */
				/* If we exit the loop in the middle, Output[i] has to be inverted */
				/* and vol[i] incremented only if the exit status of the square */
				/* wave is 1. */
				while (m_count[i] <= 0)
				{
					m_count[i] += m_period[i];
					if (m_count[i] > 0)
					{
						m_level[i] ^= 0x0ffffffff;
						if (m_level[i]) vol[i] += m_period[i];
						break;
					}
					m_count[i] += m_period[i];
					vol[i] += m_period[i];
				}
				if (m_level[i])
					vol[i] -= m_count[i];
			}
		}

		/* update volume outputs */

		/* setup output volumes for each channel */
		/* channel 0 */
		output_volumes[0] = ((m_level[0] & m_level_and[0]) | m_level_or[0]) & m_mame_volumes[0];
		output_volumes[1] = ((m_level[0] & m_level_and[1]) | m_level_or[1]) & m_mame_volumes[4];
		/* channel 1 */
		output_volumes[2] = ((m_level[1] & m_level_and[2]) | m_level_or[2]) & m_mame_volumes[1];
		output_volumes[3] = ((m_level[1] & m_level_and[3]) | m_level_or[3]) & m_mame_volumes[5];
		/* channel 2 */
		output_volumes[4] = ((m_level[2] & m_level_and[4]) | m_level_or[4]) & m_mame_volumes[2];
		output_volumes[5] = ((m_level[2] & m_level_and[5]) | m_level_or[5]) & m_mame_volumes[6];
		/* channel 3 */
		output_volumes[6] = ((m_level[3] & m_level_and[6]) | m_level_or[6]) & m_mame_volumes[3];
		output_volumes[7] = ((m_level[3] & m_level_and[7]) | m_level_or[7]) & m_mame_volumes[7];

		left_volume = (output_volumes[0] + output_volumes[2] + output_volumes[4] + output_volumes[6])>>2;
		right_volume = (output_volumes[1] + output_volumes[3] + output_volumes[5] + output_volumes[7])>>2;

		*(buffer1++) = left_volume;
		*(buffer2++) = right_volume;

		samples--;
	}
}


//-------------------------------------------------
//  int1_w - interrupt 1 write
//-------------------------------------------------

WRITE_LINE_MEMBER( dave_device::int1_w )
{
	if (!(m_irq_status & IRQ_INT1) && state)
		m_irq_status |= IRQ_INT1_LATCH;

	if (state)
		m_irq_status |= IRQ_INT1;
	else
		m_irq_status &= ~IRQ_INT1;

	update_interrupt();
}


//-------------------------------------------------
//  int2_w - interrupt 2 write
//-------------------------------------------------

WRITE_LINE_MEMBER( dave_device::int2_w )
{
	if (!(m_irq_status & IRQ_INT2) && state)
		m_irq_status |= IRQ_INT2_LATCH;

	if (state)
		m_irq_status |= IRQ_INT2;
	else
		m_irq_status &= ~IRQ_INT2;

	update_interrupt();
}


//-------------------------------------------------
//  program_r - program space read
//-------------------------------------------------

READ8_MEMBER( dave_device::program_r )
{
	uint8_t segment = m_segment[offset >> 14];
	offset = (segment << 14) | (offset & 0x3fff);

	return this->space(AS_PROGRAM).read_byte(offset);
}


//-------------------------------------------------
//  program_w - program space write
//-------------------------------------------------

WRITE8_MEMBER( dave_device::program_w )
{
	uint8_t segment = m_segment[offset >> 14];
	offset = (segment << 14) | (offset & 0x3fff);

	this->space(AS_PROGRAM).write_byte(offset, data);
}


//-------------------------------------------------
//  io_r - I/O space read
//-------------------------------------------------

READ8_MEMBER( dave_device::io_r )
{
	uint8_t data = 0;

	switch (offset & 0xff)
	{
	case 0xa0:
	case 0xa1:
	case 0xa2:
	case 0xa3:
	case 0xa4:
	case 0xa5:
	case 0xa6:
	case 0xa7:
	case 0xa8:
	case 0xa9:
	case 0xaa:
	case 0xab:
	case 0xac:
	case 0xad:
	case 0xae:
	case 0xaf:
	case 0xb8:
	case 0xb9:
	case 0xba:
	case 0xbb:
	case 0xbc:
	case 0xbd:
	case 0xbe:
	case 0xbf:
		data = 0xff;
		break;

	case 0xb0: case 0xb1: case 0xb2: case 0xb3:
		data = m_segment[offset & 0x03];
		break;

	case 0xb4:
		data = m_irq_status;
		break;

	default:
		data = this->space(AS_IO).read_byte(offset);
	}

	return data;
}


//-------------------------------------------------
//  io_w - I/O space write
//-------------------------------------------------

WRITE8_MEMBER( dave_device::io_w )
{
	switch (offset & 0xff)
	{
		/* channel 0 down-counter */
		case 0xa0:
		case 0xa1:
		/* channel 1 down-counter */
		case 0xa2:
		case 0xa3:
		/* channel 2 down-counter */
		case 0xa4:
		case 0xa5:
			{
				int count = 0;
				int channel_index = (offset>>1)&3;

				/* Fout = 125,000 / (n+1) Hz */

				/* sample rate/clock */


				/* get down-count */
				switch (offset & 0x01)
				{
					case 0:
					{
						count = (data & 0x0ff) | ((m_regs[(offset & 0x1f) + 1] & 0x0f)<<8);
					}
					break;

					case 1:
					{
						count = (m_regs[(offset & 0x1f) - 1] & 0x0ff) | ((data & 0x0f)<<8);

					}
					break;
				}

				count++;


				m_period[channel_index] = ((STEP  * machine().sample_rate())/125000) * count;

				m_regs[offset & 0x1f] = data;
			}
			break;

		/* channel 0 left volume */
		case 0xa8:
		/* channel 1 left volume */
		case 0xa9:
		/* channel 2 left volume */
		case 0xaa:
		/* noise channel left volume */
		case 0xab:
		/* channel 0 right volume */
		case 0xac:
		/* channel 1 right volume */
		case 0xad:
		/* channel 2 right volume */
		case 0xae:
		/* noise channel right volume */
		case 0xaf:
			{
				/* update mame version of volume from data written */
				/* 0x03f->0x07e00. Max is 0x07fff */
				/* I believe the volume is linear - to be checked! */
				m_mame_volumes[(offset & 0x1f) - 8] = (data & 0x03f) << 9;

				m_regs[offset & 0x1f] = data;
			}
			break;

		case 0xa6:
			break;

		case 0xa7:
		{
			/*  force => the value of this register is forced regardless of the wave
			        state,
			    remove => this value is force to zero so that it has no influence over
			        the final volume calculation, regardless of wave state
			    use => the volume value is dependant on the wave state and is included
			        in the final volume calculation */

			//logerror("selectable int ");
			switch ((data>>5) & 0x03)
			{
				case 0:
				{
					//logerror("1kHz\n");
					m_timer_50hz->adjust(attotime::from_hz(2000), 0, attotime::from_hz(2000));
				}
				break;

				case 1:
				{
					//logerror("50Hz\n");
					m_timer_50hz->adjust(attotime::from_hz(100), 0, attotime::from_hz(100));
				}
				break;

				case 2:
				{
					//logerror("tone channel 0\n");
				}
				break;

				case 3:
				{
					//logerror("tone channel 1\n");
				}
				break;
			}



			/* turn L.H audio output into D/A, outputting value in R8 */
			if (data & (1<<3))
			{
				/* force r8 value */
				m_level_or[0] = 0x0ffff;
				m_level_and[0] = 0x00;

				/* remove r9 value */
				m_level_or[2] = 0x000;
				m_level_and[2] = 0x00;

				/* remove r10 value */
				m_level_or[4] = 0x000;
				m_level_and[4] = 0x00;

				/* remove r11 value */
				m_level_or[6] = 0x000;
				m_level_and[6] = 0x00;
			}
			else
			{
				/* use r8 value */
				m_level_or[0] = 0x000;
				m_level_and[0] = 0xffff;

				/* use r9 value */
				m_level_or[2] = 0x000;
				m_level_and[2] = 0xffff;

				/* use r10 value */
				m_level_or[4] = 0x000;
				m_level_and[4] = 0xffff;

				/* use r11 value */
				m_level_or[6] = 0x000;
				m_level_and[6] = 0xffff;
			}

			/* turn L.H audio output into D/A, outputting value in R12 */
			if (data & (1<<4))
			{
				/* force r12 value */
				m_level_or[1] = 0x0ffff;
				m_level_and[1] = 0x00;

				/* remove r13 value */
				m_level_or[3] = 0x000;
				m_level_and[3] = 0x00;

				/* remove r14 value */
				m_level_or[5] = 0x000;
				m_level_and[5] = 0x00;

				/* remove r15 value */
				m_level_or[7] = 0x000;
				m_level_and[7] = 0x00;
			}
			else
			{
				/* use r12 value */
				m_level_or[1] = 0x000;
				m_level_and[1] = 0xffff;

				/* use r13 value */
				m_level_or[3] = 0x000;
				m_level_and[3] = 0xffff;

				/* use r14 value */
				m_level_or[5] = 0x000;
				m_level_and[5] = 0xffff;

				/* use r15 value */
				m_level_or[7] = 0x000;
				m_level_and[7] = 0xffff;
			}

			m_regs[offset & 0x1f] = data;
		}
		break;

	case 0xb0: case 0xb1: case 0xb2: case 0xb3:
		m_segment[offset & 0x03] = data;

		m_regs[offset & 0x1f] = data;
		break;

	case 0xb4:
		m_irq_enable = data;
		m_irq_status &= ~(m_irq_enable & IRQ_LATCH);
		update_interrupt();

		m_regs[offset & 0x1f] = data;
		break;

	case 0xbf:
		m_regs[offset & 0x1f] = data;
		break;

	default:
		this->space(AS_IO).write_byte(offset, data);
	}
}


//-------------------------------------------------
//  update_interrupt -
//-------------------------------------------------

void dave_device::update_interrupt()
{
	int state = ((m_irq_status & (m_irq_enable << 1)) & IRQ_LATCH) ? ASSERT_LINE : CLEAR_LINE;

	m_write_irq(state);
}