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

                                                           


                                                           

                                                           
                
                   

 
                         
                                                                   
                                                                       

 


                                                                            
 


                                                   
 

                                                                                                                             






                                                                                                                                 
                                
 

 














                                                                                                               





                                                   
 

                                 
                                                           
                                  
 

                                                     













                                                       

 
                                                   








                                                   







                                                                                       
 


                                                   
 
                                                                                                                               
 

                                            

                                      

                                                   

                                 
                      


                                
                                        
         
                                                                   
                                
                 

                                                                     

                                                         
                                                         


                                           
                                                             
                                                             
                                 

                                                                                          

                                 
                                                                         
                                                                                        

                                                   
                                                                      
                                                                                                




                                                                                                
                                                       

















                                                                       
                                         















                                                      
                                                   
                           
                                                   
 
                                         
 
                      
 
                           

                                           
                                                         
 
                                                              

 
                                                    
 
                                            


                                              
                           



                                    
                                          
                                        

                              
                                     
                                        

                              
                                     
                                                                           

                              
                                     
                                                                                  

                              
                                     
                                                                               

                              
                                     
                                                                                      

                              
                                    


                                                                   

                              
                                             
                                                   
                                        
                                                   
                            
                                                             

                              
                                                    

                                               


                                                                                     





                              
                                                   
                        

                                                   
                                             
 
                                                    

 

                                                   
                         

                                                   
                                                        
 
                                                   
 
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert,Aaron Giles
/*********************************************************/
/*    ricoh RF5C68(or clone) PCM controller              */
/*                                                       */
/*    TODO : RF5C164 (Sega CD/Mega CD)                   */
/*           has difference?                             */
/*********************************************************/

#include "emu.h"
#include "rf5c68.h"


// device type definition
DEFINE_DEVICE_TYPE(RF5C68, rf5c68_device, "rf5c68", "Ricoh RF5C68")
DEFINE_DEVICE_TYPE(RF5C164, rf5c164_device, "rf5c164", "Ricoh RF5C164")


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

//-------------------------------------------------
//  rf5c68_device - constructor
//-------------------------------------------------

rf5c68_device::rf5c68_device(const machine_config & mconfig, device_type type, const char * tag, device_t * owner, u32 clock)
	: device_t(mconfig, type, tag, owner, clock)
	, device_sound_interface(mconfig, *this)
	, device_memory_interface(mconfig, *this)
	, m_data_config("data", ENDIANNESS_LITTLE, 8, 16) // 15 bit Address + 2 Memory select outputs(total 64KB), PSRAM/SRAM/ROM
	, m_stream(nullptr)
	, m_cbank(0)
	, m_wbank(0)
	, m_enable(0)
	, m_sample_end_cb(*this)
{
}

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


//-------------------------------------------------
//  rf5c68_device - constructor
//-------------------------------------------------

rf5c164_device::rf5c164_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: rf5c68_device(mconfig, RF5C164, tag, owner, clock)
{
}


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

void rf5c68_device::device_start()
{
	m_data = &space(0);
	// Find our direct access
	m_cache = space().cache<0, 0, ENDIANNESS_LITTLE>();
	m_sample_end_cb.resolve();

	/* allocate the stream */
	m_stream = stream_alloc(0, 2, clock() / 384);

	for (int ch = 0; ch < NUM_CHANNELS; ch++)
	{
		save_item(NAME(m_chan[ch].enable), ch);
		save_item(NAME(m_chan[ch].env), ch);
		save_item(NAME(m_chan[ch].pan), ch);
		save_item(NAME(m_chan[ch].start), ch);
		save_item(NAME(m_chan[ch].addr), ch);
		save_item(NAME(m_chan[ch].step), ch);
		save_item(NAME(m_chan[ch].loopst), ch);
	}
	save_item(NAME(m_cbank));
	save_item(NAME(m_wbank));
	save_item(NAME(m_enable));
}

//-------------------------------------------------
//  device_clock_changed
//-------------------------------------------------

void rf5c68_device::device_clock_changed()
{
	m_stream->set_sample_rate(clock() / 384);
}

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

device_memory_interface::space_config_vector rf5c68_device::memory_space_config() const
{
	return space_config_vector{ std::make_pair(0, &m_data_config) };
}

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

void rf5c68_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
	stream_sample_t *left = outputs[0];
	stream_sample_t *right = outputs[1];

	/* start with clean buffers */
	memset(left, 0, samples * sizeof(*left));
	memset(right, 0, samples * sizeof(*right));

	/* bail if not enabled */
	if (!m_enable)
		return;

	/* loop over channels */
	for (pcm_channel &chan : m_chan)
	{
		/* if this channel is active, accumulate samples */
		if (chan.enable)
		{
			int lv = (chan.pan & 0x0f) * chan.env;
			int rv = ((chan.pan >> 4) & 0x0f) * chan.env;

			/* loop over the sample buffer */
			for (int j = 0; j < samples; j++)
			{
				int sample;

				/* trigger sample callback */
				if(!m_sample_end_cb.isnull())
				{
					if(((chan.addr >> 11) & 0xfff) == 0xfff)
						m_sample_end_cb((chan.addr >> 11)/0x2000);
				}

				/* fetch the sample and handle looping */
				sample = m_cache->read_byte((chan.addr >> 11) & 0xffff);
				if (sample == 0xff)
				{
					chan.addr = chan.loopst << 11;
					sample = m_cache->read_byte((chan.addr >> 11) & 0xffff);

					/* if we loop to a loop point, we're effectively dead */
					if (sample == 0xff)
						break;
				}
				chan.addr += chan.step;

				/* add to the buffer */
				if (sample & 0x80)
				{
					sample &= 0x7f;
					left[j] += (sample * lv) >> 5;
					right[j] += (sample * rv) >> 5;
				}
				else
				{
					left[j] -= (sample * lv) >> 5;
					right[j] -= (sample * rv) >> 5;
				}
			}
		}
	}

	/* now clamp and shift the result (output is only 10 bits) */
	for (int j = 0; j < samples; j++)
	{
		stream_sample_t temp;

		temp = left[j];
		if (temp > 32767) temp = 32767;
		else if (temp < -32768) temp = -32768;
		left[j] = temp & ~0x3f;

		temp = right[j];
		if (temp > 32767) temp = 32767;
		else if (temp < -32768) temp = -32768;
		right[j] = temp & ~0x3f;
	}
}


//-------------------------------------------------
//    RF5C68 write register
//-------------------------------------------------

u8 rf5c68_device::rf5c68_r(offs_t offset)
{
	uint8_t shift;

	m_stream->update();
	shift = (offset & 1) ? 11 + 8 : 11;

//  printf("%08x\n",(m_chan[(offset & 0x0e) >> 1].addr));

	return (m_chan[(offset & 0x0e) >> 1].addr) >> (shift);
}

void rf5c68_device::rf5c68_w(offs_t offset, u8 data)
{
	pcm_channel &chan = m_chan[m_cbank];
	int i;

	/* force the stream to update first */
	m_stream->update();

	/* switch off the address */
	switch (offset)
	{
		case 0x00:  /* envelope */
			chan.env = data;
			break;

		case 0x01:  /* pan */
			chan.pan = data;
			break;

		case 0x02:  /* FDL */
			chan.step = (chan.step & 0xff00) | (data & 0x00ff);
			break;

		case 0x03:  /* FDH */
			chan.step = (chan.step & 0x00ff) | ((data << 8) & 0xff00);
			break;

		case 0x04:  /* LSL */
			chan.loopst = (chan.loopst & 0xff00) | (data & 0x00ff);
			break;

		case 0x05:  /* LSH */
			chan.loopst = (chan.loopst & 0x00ff) | ((data << 8) & 0xff00);
			break;

		case 0x06:  /* ST */
			chan.start = data;
			if (!chan.enable)
				chan.addr = chan.start << (8 + 11);
			break;

		case 0x07:  /* control reg */
			m_enable = (data >> 7) & 1;
			if (data & 0x40)
				m_cbank = data & 7;
			else
				m_wbank = (data & 0xf) << 12;
			break;

		case 0x08:  /* channel on/off reg */
			for (i = 0; i < 8; i++)
			{
				m_chan[i].enable = (~data >> i) & 1;
				if (!m_chan[i].enable)
					m_chan[i].addr = m_chan[i].start << (8 + 11);
			}
			break;
	}
}


//-------------------------------------------------
//    RF5C68 read memory
//-------------------------------------------------

u8 rf5c68_device::rf5c68_mem_r(offs_t offset)
{
	return m_cache->read_byte(m_wbank | offset);
}


//-------------------------------------------------
//    RF5C68 write memory
//-------------------------------------------------

void rf5c68_device::rf5c68_mem_w(offs_t offset, u8 data)
{
	m_data->write_byte(m_wbank | offset, data);
}