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

                                                                            
                       
                    
 


                                                
 
                             
 


                                                              
 

                             
 

                                                                         
 


                                                                  
 
                    
 

                                                             
 
                                                             
 
                                                             
 
                                                             
 
                                                             
 
                                                             
 
                                                             
 
                                                             
 
                                                                               
 
                                                                          
 
                                                                          
 
                                                             
 
                                     
 

                                                            
 










                                                        
 


                                                                               
 






                                                                                                                                 




                                                                            
                     


                         
                                                                                   









                                                                            
                                                                                                                           
                                                        
                                                       
                                  
                         
                                         










                                                   
                                                               




















                                                                                        











                                                                                                                                      
 
                                    




                                                          


                                                     
 

                                                   


                                                         

                                               
 
                                                    



                                                         









                                                                      

                                 
 
                                                                           
                                                                                     

                                             

                                                                                  





                                          

 
                                

                                                       
                                   
 

                                                                                

                                                              

                                                              

                                                             






                                                      

                                                                            



                                                              
 
                      


 
                                                    





                                                                 


                                      
                                                                                                                                                             





                                              
                                                                                                                                                               




                                        
                                                  
 

                                                       
                                                                                  
                                                                                         
 
                                                                       
 

                                                                                             

                                
                          
 


                                                                                                                
 

                                                                                                        
                                                    
 




                                                                                                                   
                              




                                                                                                      
 



                                                                                                               
                                                   
                                                                                   
                                                          






                                                                                                                      
                                                  
 
                                                          
                         
                                                                                                      
                              
 



                                                                                                     
                                                                                  
                                                                                                          
                                                                                  


                                                                                                                                      

         
 
 
                                                 
 
                                                                             
                                  
                                                       
 
                               
         
                          
                 

                                              
 






                                                                               
 

                                   
         
 
                 

 
                                                    
 
                                 
         
                                                               
 
     



                                                   
 


                                                                                                                                                                                               
      
 


                                             
         
 


















                                                    
// license:LGPL-2.1+
// copyright-holders:David Haywood, Angelo Salese, ElSemi
/***************************************************************************

    L7A1045 L6028 DSP-A
    (QFP120 package)

    this is the audio chip used on the following
    SNK Hyper NeoGeo 64 (arcade platform)
    AKAI MPC3000 (synth)

    both are driven by a V53.

    appears to write a register number and channel/voice using
    l7a1045_sound_select_w (offset 0)
    format:

    ---- rrrr ---c cccc
    r = register, c = channel

    the channel select appears to address 32 different voices (5-bits)
    the register select appears to use 4-bits with 0x0 to 0xa being valid

    the registers data is written / read using offsets 1,2,3 after
    setting the register + channel, this gives 3 16-bit values for
    each register.

    register format:

       offset 3           offset 2           offset 1
       fedcba9876543210 | fedcba9876543210 | fedcba9876543210

    0  ----------------   ----------------   ----------------

    1  ----------------   ----------------   ----------------

    2  ----------------   ----------------   ----------------

    3  ----------------   ----------------   ----------------

    4  ----------------   ----------------   ----------------

    5  ----------------   ----------------   ----------------

    6  ----------------   ----------------   ----------------

    7  ----------------   ----------------   llllllllrrrrrrrr left/right volume

    8  ----------------   ----------------   ---------------- (read only?)

    9  ----------------   ----------------   ---------------- (read only?)

    a  ----------------   ----------------   ----------------

    Registers are not yet understood.

    probably sample start, end, loop positions, panning etc.
    like CPS3, Qsound etc.

    case 0x00:
    case 0x01:
    case 0x02:
    case 0x03: // 00003fffffff (startup only?)
    case 0x04: // doesn't use 6
    case 0x05: // 00003fffffff (mostly, often)
    case 0x06: // 00007ff0ffff mostly
    case 0x07: // 0000000f0708 etc. (low values)
    case 0x08: // doesn't write to 2/4/6 with this set??
    case 0x09: // doesn't write to 2/4/6 with this set??
    case 0x0a: // random looking values

    Some of the other ports on the HNG64 sound CPU may also be tied
    to this chip, this isn't yet clear.
    Port $8 bit 8 is keyon, low byte is sound status related (masked with 0x7f)

    Sample data format TBA

    TODO:
    - Sample format needs to be double checked;
    - Octave Control/BPM/Pitch, right now XRally Network BGM wants 66150 Hz which is definitely too fast for Terry Bogard speech;
    - Key Off;
    - ADSR (registers 2 & 4?);

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

#include "emu.h"
#include "l7a1045_l6028_dsp_a.h"
#include "debugger.h"


// device type definition
DEFINE_DEVICE_TYPE(L7A1045, l7a1045_sound_device, "l7a1045", "L7A1045 L6028 DSP-A")


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

//-------------------------------------------------
//  l7a1045_sound_device - constructor
//-------------------------------------------------

l7a1045_sound_device::l7a1045_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, L7A1045, tag, owner, clock),
		device_sound_interface(mconfig, *this),
		m_stream(nullptr),
		m_key(0),
		m_rom(*this, DEVICE_SELF)
{
}


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

void l7a1045_sound_device::device_start()
{
	/* Allocate the stream */
	m_stream = stream_alloc(0, 2, 66150); //clock() / 384);

	for (int voice = 0; voice < 32; voice++)
	{
		save_item(NAME(m_voice[voice].start), voice);
		save_item(NAME(m_voice[voice].end), voice);
		save_item(NAME(m_voice[voice].mode), voice);
		save_item(NAME(m_voice[voice].pos), voice);
		save_item(NAME(m_voice[voice].frac), voice);
		save_item(NAME(m_voice[voice].l_volume), voice);
		save_item(NAME(m_voice[voice].r_volume), voice);
	}
	save_item(NAME(m_key));
	save_item(NAME(m_audiochannel));
	save_item(NAME(m_audioregister));
	for (int reg = 0; reg < 0x10; reg++)
	{
		for (int voice = 0; voice < 0x20; voice++)
		{
			save_item(NAME(m_audiodat[reg][voice].dat), (reg << 8) | voice);
		}
	}
}


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

void l7a1045_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
	/* Clear the buffers */
	memset(outputs[0], 0, samples*sizeof(*outputs[0]));
	memset(outputs[1], 0, samples*sizeof(*outputs[1]));

	for (int i = 0; i < 32; i++)
	{
		if (m_key & (1 << i))
		{
			l7a1045_voice *vptr = &m_voice[i];

			uint32_t start = vptr->start;
			uint32_t end = vptr->end;
			uint32_t step  = 0x400;

			uint32_t pos = vptr->pos;
			uint32_t frac = vptr->frac;

			for (int j = 0; j < samples; j++)
			{
				int32_t sample;
				uint8_t data;

				pos += (frac >> 12);
				frac &= 0xfff;

				if ((start + pos) >= end)
				{
					if(vptr->mode == true) // loop
					{
						pos = vptr->pos = 0;
						frac = vptr->frac = 0;
					}
					else // no loop, keyoff
					{
						m_key &= ~(1 << i);
						break;
					}
				}


				data = m_rom[(start + pos) & m_rom.mask()];
				sample = ((int8_t)(data & 0xfc)) << (3 - (data & 3));
				frac += step;

				outputs[0][j] += ((sample * vptr->l_volume) >> 9);
				outputs[1][j] += ((sample * vptr->r_volume) >> 9);
			}

			vptr->pos = pos;
			vptr->frac = frac;
		}
	}
}

// TODO: needs proper memory map
WRITE16_MEMBER( l7a1045_sound_device::l7a1045_sound_w )
{
	m_stream->update(); // TODO

	//logerror("%s: %x to %x (mask %04x)\n", tag(), data, offset, mem_mask);

	if(offset == 0)
		sound_select_w(space, offset, data, mem_mask);
	else if(offset == 8/2)
		sound_status_w(space, offset, data, mem_mask);
	else
		sound_data_w(space,offset - 1,data,mem_mask);
}


READ16_MEMBER( l7a1045_sound_device::l7a1045_sound_r )
{
	m_stream->update();

	//logerror("%s: read at %x (mask %04x)\n", tag(), offset, mem_mask);

	if(offset == 0)
		printf("sound_select_r?\n");
	else
		return sound_data_r(space,offset -1,mem_mask);

	return 0xffff;
}


WRITE16_MEMBER(l7a1045_sound_device::sound_select_w)
{
	// I'm guessing these addresses are the sound chip / DSP?

	// ---- ---- 000c cccc
	// c = channel

	if (ACCESSING_BITS_0_7)
	{
		m_audiochannel = data;
		if (m_audiochannel & 0xe0) logerror("%s l7a1045_sound_select_w unknown channel %01x\n", machine().describe_context(), m_audiochannel & 0xff);
		m_audiochannel &= 0x1f;
	}

	if (ACCESSING_BITS_8_15)
	{
		m_audioregister = (data >> 8);
		if (m_audioregister >0x0a) logerror("%s l7a1045_sound_select_w unknown register %01x\n", machine().describe_context(), m_audioregister & 0xff);
		m_audioregister &= 0x0f;
	}

}

WRITE16_MEMBER(l7a1045_sound_device::sound_data_w)
{
	l7a1045_voice *vptr = &m_voice[m_audiochannel];

	//if(m_audioregister != 0 && m_audioregister != 1 && m_audioregister != 7)
	//  printf("%04x %04x (%04x %04x)\n",offset,data,m_audioregister,m_audiochannel);

	m_audiodat[m_audioregister][m_audiochannel].dat[offset] = data;

	//logerror("%s: %x to ch %d reg %d\n", tag(), data, m_audiochannel, m_audioregister);

	switch (m_audioregister)
	{
		case 0x00:

			vptr->start = (m_audiodat[m_audioregister][m_audiochannel].dat[2] & 0x000f) << (16 + 4);
			vptr->start |= (m_audiodat[m_audioregister][m_audiochannel].dat[1] & 0xffff) << (4);
			vptr->start |= (m_audiodat[m_audioregister][m_audiochannel].dat[0] & 0xf000) >> (12);

			//logerror("%s: channel %d start = %08x\n", tag(), m_audiochannel, vptr->start);

			vptr->start &= m_rom.mask();

			// if voice isn't active, clear the pos on start writes (required for DMA tests on MPC3000)
			if (!(m_key & (1 << m_audiochannel)))
			{
				vptr->pos = 0;
			}
			break;
		case 0x01:
			// relative to start
				//printf("%04x\n",m_audiodat[m_audioregister][m_audiochannel].dat[0]);
				//printf("%04x\n",m_audiodat[m_audioregister][m_audiochannel].dat[1]);
				//printf("%04x\n",m_audiodat[m_audioregister][m_audiochannel].dat[2]);

			if(m_audiodat[m_audioregister][m_audiochannel].dat[2] & 0x100)
			{
				vptr->end = (m_audiodat[m_audioregister][m_audiochannel].dat[0] & 0xffff) << 2;
				vptr->end += vptr->start;
				vptr->mode = false;
				// hopefully it'll never happen? Maybe assert here?
				vptr->end &= m_rom.mask();

			}
			else // absolute
			{
				vptr->end = (m_audiodat[m_audioregister][m_audiochannel].dat[2] & 0x000f) << (16 + 4);
				vptr->end |= (m_audiodat[m_audioregister][m_audiochannel].dat[1] & 0xffff) << (4);
				vptr->end |= (m_audiodat[m_audioregister][m_audiochannel].dat[0] & 0xf000) >> (12);
				vptr->mode = true;

				vptr->end &= m_rom.mask();
			}
			//logerror("%s: channel %d end = %08x\n", tag(), m_audiochannel, vptr->start);
			break;

		case 0x07:

			vptr->r_volume = (m_audiodat[m_audioregister][m_audiochannel].dat[0] & 0xff);
			/* TODO: volume tables, linear? */
			vptr->r_volume = (vptr->r_volume) | (vptr->r_volume << 8);
			vptr->l_volume = (m_audiodat[m_audioregister][m_audiochannel].dat[0] >> 8) & 0xff;
			vptr->l_volume = (vptr->l_volume) | (vptr->l_volume << 8);
			//printf("%04x %02x %02x\n",m_audiodat[m_audioregister][m_audiochannel].dat[0],vptr->l_volume,vptr->r_volume);

			break;
	}
}


READ16_MEMBER(l7a1045_sound_device::sound_data_r)
{
	//printf("%04x (%04x %04x)\n",offset,m_audioregister,m_audiochannel);
	//machine().debug_break();
	l7a1045_voice *vptr = &m_voice[m_audiochannel];

	switch(m_audioregister)
	{
		case 0x00:
		{
			uint32_t current_addr;
			uint16_t res;

			current_addr = vptr->start + vptr->pos;
			if(offset == 0)
				res = (current_addr & 0xf) << 12; // TODO: frac
			else if(offset == 1)
				res = (current_addr & 0xffff0) >> 4;
			else
				res = (current_addr & 0xf00000) >> 20;

			return res;
		}
	}

	return 0;
}

WRITE16_MEMBER(l7a1045_sound_device::sound_status_w)
{
	if(data & 0x100) // keyin
	{
		l7a1045_voice *vptr = &m_voice[m_audiochannel];

#if 0
		if(vptr->start != 0)
		{
		printf("%08x START\n",vptr->start);
		printf("%08x END\n",vptr->end);

		for(int i=0;i<0x10;i++)
			printf("%02x (%02x) = %04x%04x%04x\n",m_audiochannel,i,m_audiodat[i][m_audiochannel].dat[2],m_audiodat[i][m_audiochannel].dat[1],m_audiodat[i][m_audiochannel].dat[0]);
		}
#endif

		vptr->frac = 0;
		vptr->pos = 0;
		m_key |= 1 << m_audiochannel;
	}
}

WRITE_LINE_MEMBER(l7a1045_sound_device::dma_hreq_cb)
{
//  m_maincpu->hack_w(1);
}

READ8_MEMBER(l7a1045_sound_device::dma_r_cb)
{
//    logerror("dma_ior3_cb: offset %x\n", offset);

	m_voice[0].pos++;
	return 0;
}

WRITE8_MEMBER(l7a1045_sound_device::dma_w_cb)
{
	m_voice[0].pos++;
//    logerror("dma_iow3_cb: offset %x\n", offset);
}