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

                               





                                                                            
 

                           

                  
                                                           







                                                                                                           

                                                                                  






                                


                                                                            

                
                         
                                                 
 
                                                                            
               

                                                                            
                                                   
                            

                                                   
                                                                                                       




                                                   




                                                   





                                                   
                                                                      

                                          
 
                                          
 










                                        

                                 








                                                   
                           





                                              


                                            
                                        


                                                   




                                                                                          
                           


                                                   
                                                    


                                                   
                                                                                                                            
 
                                     
                  
                                                 





                                         
                                   





                                                      
                                    

                                                     
                                                    
 
                                                                              







                                                                                                         


                                                                                                
                                 


                                                                
                                 
 
                                                                                                                             
                                 


                                                                

                                 
                                                                                                           
                                                    
                                 

                                                            

                                                                          
                                                                                                            
                                                                               
                                                 
                                                                                                     
                                                 
                                                                                                       
                                                                               
                                                 
 

                                                                          
                                                                                                            
                                                                               
                                                 
                                                                                                     
                                                 
                                                                                                       
                                                                               

                                                      


























                                                                                                                             

                                 


                                                     




                                                     

                                                   

                                                
 






                                                                  
                                                                                                                  


                                            
                                                                                                                  











                                                         
 
                                                                                                                                                                   





                                                          
                                
 
                   
 
                                        

                                                                        

                           
                                        


                                
                                              


            
                                   

                               
                                       

                                                    
                                                           

                                                         
                                                             


                                                            

                                                             

                                                            
                                                              

                                                            
                                                                                       






                                                      



                                                             
                                                              

                                                         
                                                






                                                      



                                                             
                                                              



                                                         


                                      
                                        
                                                    
                                 









                                                                                  
                                 
 
                                                                                     
 
                                                                                                 

                                                             
                                                                 
                                                      

                                          





                                      































                                                               
                             



                            
                                    





                                                          
                                  
 
                                                    
 

                           

                                              
                                                          
                                       
 
                                                  
                         
                                                                              







                                                


                                

                                              
                                                          
                                       
 
                                                  
                         
                                                                              


                                                
                 



                                                      


            
                                                                                 
 
                                   


                                    
                                                                               
 

                                                               




                                                                            


                                                      
                                                                                                               


                                            
                                                                                 
                                         

                                      
 





                                                                            
                                                                                            
                                 


                                         
                                                          

                                      
                                   













                                                       
                                   













                                                      
                                   













                                                       
                                   













                                                      
                                   













                                                       
                                   













                                                      
                                   













                                                       
                                   














                                                      
                                                       


                                                    

         
// license:BSD-3-Clause
// copyright-holders:R. Belmont
/***************************************************************************

    asc.c

    Apple Sound Chip (ASC) 344S0063
    Enhanced Apple Sound Chip (EASC) 343S1063

    Emulation by R. Belmont

    Registers:
    0x800: VERSION
    0x801: MODE (0=inactive, 1=FIFO mode, 2=wavetable mode)
    0x802: CONTROL (bit 0=analog or PWM output, 1=stereo/mono, 7=processing time exceeded)
    0x803: FIFO MODE (bit 7=clear FIFO, bit 1="non-ROM companding", bit 0="ROM companding")
    0x804: FIFO IRQ STATUS (bit 0=ch A 1/2 full, 1=ch A full, 2=ch B 1/2 full, 3=ch B full)
    0x805: WAVETABLE CONTROL (bits 0-3 wavetables 0-3 start)
    0x806: VOLUME (bits 2-4 = 3 bit internal ASC volume, bits 5-7 = volume control sent to Sony sound chip)
    0x807: CLOCK RATE (0 = Mac 22257 Hz, 1 = undefined, 2 = 22050 Hz, 3 = 44100 Hz)
    0x80a: PLAY REC A
    0x80f: TEST (bits 6-7 = digital test, bits 4-5 = analog test)
    0x810: WAVETABLE 0 PHASE (big-endian 9.15 fixed-point, only 24 bits valid)
    0x814: WAVETABLE 0 INCREMENT (big-endian 9.15 fixed-point, only 24 bits valid)
    0x818: WAVETABLE 1 PHASE
    0x81C: WAVETABLE 1 INCREMENT
    0x820: WAVETABLE 2 PHASE
    0x824: WAVETABLE 2 INCREMENT
    0x828: WAVETABLE 3 PHASE
    0x82C: WAVETABLE 3 INCREMENT

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

#include "emu.h"
#include "asc.h"

// device type definition
DEFINE_DEVICE_TYPE(ASC, asc_device, "asc", "ASC")

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

//-------------------------------------------------
//  asc_device - constructor
//-------------------------------------------------

asc_device::asc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, ASC, tag, owner, clock)
	, device_sound_interface(mconfig, *this)
	, write_irq(*this)
	, m_chip_type(asc_type::ASC)
	, m_timer(nullptr)
{
}


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

void asc_device::device_start()
{
	// create the stream
	m_stream = machine().sound().stream_alloc(*this, 0, 2, 22257);

	memset(m_regs, 0, sizeof(m_regs));

	m_timer = timer_alloc(0, nullptr);

	save_item(NAME(m_fifo_a_rdptr));
	save_item(NAME(m_fifo_b_rdptr));
	save_item(NAME(m_fifo_a_wrptr));
	save_item(NAME(m_fifo_b_wrptr));
	save_item(NAME(m_fifo_cap_a));
	save_item(NAME(m_fifo_cap_b));
	save_item(NAME(m_fifo_a));
	save_item(NAME(m_fifo_b));
	save_item(NAME(m_regs));
	save_item(NAME(m_phase));
	save_item(NAME(m_incr));

	write_irq.resolve_safe();
}


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

void asc_device::device_reset()
{
	m_stream->update();

	memset(m_regs, 0, sizeof(m_regs));
	memset(m_fifo_a, 0, sizeof(m_fifo_a));
	memset(m_fifo_b, 0, sizeof(m_fifo_b));
	memset(m_phase, 0, sizeof(m_phase));
	memset(m_incr, 0, sizeof(m_incr));

	m_fifo_a_rdptr = m_fifo_b_rdptr = 0;
	m_fifo_a_wrptr = m_fifo_b_wrptr = 0;
	m_fifo_cap_a = m_fifo_cap_b = 0;
}

//-------------------------------------------------
//  device_timer - called when our device timer expires
//-------------------------------------------------

void asc_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
{
	m_stream->update();
}

//-------------------------------------------------
//  sound_stream_update - handle update requests for
//  our sound stream
//-------------------------------------------------

void asc_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
	stream_sample_t *outL, *outR;
	int i, ch;
	static uint32_t wtoffs[2] = { 0, 0x200 };

	outL = outputs[0];
	outR = outputs[1];

	switch (m_regs[R_MODE-0x800] & 3)
	{
		case 0: // chip off
			for (i = 0; i < samples; i++)
			{
				outL[i] = outR[i] = 0;
			}
			break;

		case 1: // FIFO mode
			for (i = 0; i < samples; i++)
			{
				int8_t smpll, smplr;

				smpll = (int8_t)m_fifo_a[m_fifo_a_rdptr]^0x80;
				if ((m_chip_type <= asc_type::EASC) || (m_chip_type == asc_type::SONORA))
				{
					smplr = (int8_t)m_fifo_b[m_fifo_b_rdptr]^0x80;
				}
				else
				{
					smplr = smpll;
				}

				// don't advance the sample pointer if there are no more samples
				if (m_fifo_cap_a)
				{
					m_fifo_a_rdptr++;
					m_fifo_a_rdptr &= 0x3ff;
					m_fifo_cap_a--;
				}

				if ((m_fifo_cap_b) && ((m_chip_type <= asc_type::EASC) || (m_chip_type == asc_type::SONORA)))
				{
					m_fifo_b_rdptr++;
					m_fifo_b_rdptr &= 0x3ff;
					m_fifo_cap_b--;
				}

				//printf("chip updating: cap A %x cap B %x\n", m_fifo_cap_a, m_fifo_cap_b);
				switch (m_chip_type)
				{
					case asc_type::ASC:
					case asc_type::EASC:
						if (m_fifo_cap_a == 0x1ff)
						{
							m_regs[R_FIFOSTAT-0x800] |= 1;  // fifo A half-empty
							write_irq(ASSERT_LINE);
						}
						else if (m_fifo_cap_a == 0x1)   // fifo A fully empty
						{
							m_regs[R_FIFOSTAT-0x800] |= 2;  // fifo A empty
							write_irq(ASSERT_LINE);
						}

						if (m_fifo_cap_b == 0x1ff)
						{
							m_regs[R_FIFOSTAT-0x800] |= 4;  // fifo B half-empty
							write_irq(ASSERT_LINE);
						}
						else if (m_fifo_cap_b == 0x1)   // fifo B fully empty
						{
							m_regs[R_FIFOSTAT-0x800] |= 8;  // fifo B empty
							write_irq(ASSERT_LINE);
						}
						break;

					default:    // V8/Sonora/Eagle/etc
						if (m_fifo_cap_a < 0x1ff)
						{
							m_regs[R_FIFOSTAT-0x800] |= 1;  // fifo A less than half full

							if (m_fifo_cap_a == 0)   // fifo A fully empty
							{
								m_regs[R_FIFOSTAT-0x800] |= 2;  // fifo A empty
							}
							write_irq(ASSERT_LINE);
						}

						if (m_chip_type == asc_type::SONORA)
						{
							if (m_fifo_cap_b < 0x1ff)
							{
								m_regs[R_FIFOSTAT-0x800] |= 4;  // fifo B less than half full

								if (m_fifo_cap_b == 0)   // fifo B fully empty
								{
									m_regs[R_FIFOSTAT-0x800] |= 8;  // fifo B empty
								}
								write_irq(ASSERT_LINE);
							}
						}
						break;
				}

				outL[i] = smpll * 64;
				outR[i] = smplr * 64;
			}
			break;

		case 2: // wavetable mode
			for (i = 0; i < samples; i++)
			{
				int32_t mixL, mixR;
				int8_t smpl;

				mixL = mixR = 0;

				// update channel pointers
				for (ch = 0; ch < 4; ch++)
				{
					m_phase[ch] += m_incr[ch];

					if (ch < 2)
					{
						smpl = (int8_t)m_fifo_a[((m_phase[ch]>>15)&0x1ff) + wtoffs[ch&1]];
					}
					else
					{
						smpl = (int8_t)m_fifo_b[((m_phase[ch]>>15)&0x1ff) + wtoffs[ch&1]];
					}

					smpl ^= 0x80;
					mixL += smpl*256;
					mixR += smpl*256;
				}

				outL[i] = mixL>>2;
				outR[i] = mixR>>2;
			}
			break;
	}

//  printf("rdA %04x rdB %04x wrA %04x wrB %04x (capA %04x B %04x)\n", m_fifo_a_rdptr, m_fifo_b_rdptr, m_fifo_a_wrptr, m_fifo_b_wrptr, m_fifo_cap_a, m_fifo_cap_b);
}

//-------------------------------------------------
//  read - read from the chip's registers and internal RAM
//-------------------------------------------------

READ8_MEMBER( asc_device::read )
{
	uint8_t rv;

//  printf("ASC: read at %x\n", offset);

	// not sure what actually happens when the CPU reads the FIFO...
	if (offset < 0x400)
	{
		return m_fifo_a[offset];
	}
	else if (offset < 0x800)
	{
		return m_fifo_b[offset-0x400];
	}
	else
	{
		m_stream->update();
		switch (offset)
		{
			case R_VERSION:
				switch (m_chip_type)
				{
					case asc_type::ASC:
						return 0;

					case asc_type::EAGLE:
						return 0xe0;

					case asc_type::V8:
					case asc_type::SPICE:
					case asc_type::VASP:
						return 0xe8;

					case asc_type::SONORA:
						return 0xbc;

					default:    // return the actual register value
						break;
				}
				break;

			case R_MODE:
				switch (m_chip_type)
				{
					case asc_type::V8:
					case asc_type::EAGLE:
					case asc_type::SPICE:
					case asc_type::VASP:
					case asc_type::SONORA:
						return 1;

					default:
						break;
				}
				break;

			case R_CONTROL:
				switch (m_chip_type)
				{
					case asc_type::V8:
					case asc_type::EAGLE:
					case asc_type::SPICE:
					case asc_type::VASP:
					case asc_type::SONORA:
						return 1;

					default:
						break;
				}
				break;

			case R_FIFOSTAT:
				switch (m_chip_type)
				{
					case asc_type::V8:
					case asc_type::EAGLE:
					case asc_type::SPICE:
					case asc_type::VASP:
						rv = m_regs[R_FIFOSTAT-0x800] & 3;
						break;

					default:
						rv = m_regs[R_FIFOSTAT-0x800];
						break;
				}

				//if (rv != 0) printf("Read FIFO stat = %02x\n", rv);

				// reading this register clears all bits (true also on V8/EAGLE?)
				m_regs[R_FIFOSTAT-0x800] = 0;

				// reading this clears interrupts
				write_irq(CLEAR_LINE);

				return rv;

			default:
				break;
		}
	}

	// WT inc/phase registers - rebuild from "live" copies"
	if ((offset >= 0x810) && (offset <= 0x82f))
	{
		m_regs[0x11] = m_phase[0]>>16;
		m_regs[0x12] = m_phase[0]>>8;
		m_regs[0x13] = m_phase[0];
		m_regs[0x15] = m_incr[0]>>16;
		m_regs[0x16] = m_incr[0]>>8;
		m_regs[0x17] = m_incr[0];

		m_regs[0x19] = m_phase[1]>>16;
		m_regs[0x1a] = m_phase[1]>>8;
		m_regs[0x1b] = m_phase[1];
		m_regs[0x1d] = m_incr[1]>>16;
		m_regs[0x1e] = m_incr[1]>>8;
		m_regs[0x1f] = m_incr[1];

		m_regs[0x21] = m_phase[2]>>16;
		m_regs[0x22] = m_phase[2]>>8;
		m_regs[0x23] = m_phase[2];
		m_regs[0x25] = m_incr[2]>>16;
		m_regs[0x26] = m_incr[2]>>8;
		m_regs[0x27] = m_incr[2];

		m_regs[0x29] = m_phase[3]>>16;
		m_regs[0x2a] = m_phase[3]>>8;
		m_regs[0x2b] = m_phase[3];
		m_regs[0x2d] = m_incr[3]>>16;
		m_regs[0x2e] = m_incr[3]>>8;
		m_regs[0x2f] = m_incr[3];
	}

	if (offset >= 0x1000)
	{
		return 0xff;
	}

	return m_regs[offset-0x800];
}

//-------------------------------------------------
//  write - write to the chip's registers and internal RAM
//-------------------------------------------------

WRITE8_MEMBER( asc_device::write )
{
  //printf("ASC: write %02x to %x\n", data, offset);

	if (offset < 0x400)
	{
		if (m_regs[R_MODE-0x800] == 1)
		{
			m_fifo_a[m_fifo_a_wrptr++] = data;
			m_fifo_cap_a++;

			if (m_fifo_cap_a == 0x3ff)
			{
				m_regs[R_FIFOSTAT-0x800] |= 2;  // fifo A full
			}

			m_fifo_a_wrptr &= 0x3ff;
		}
		else
		{
			m_fifo_a[offset] = data;
		}
	}
	else if (offset < 0x800)
	{
		if (m_regs[R_MODE-0x800] == 1)
		{
			m_fifo_b[m_fifo_b_wrptr++] = data;
			m_fifo_cap_b++;

			if (m_fifo_cap_b == 0x3ff)
			{
				m_regs[R_FIFOSTAT-0x800] |= 8;  // fifo B full
			}

			m_fifo_b_wrptr &= 0x3ff;
		}
		else
		{
			m_fifo_b[offset-0x400] = data;
		}
	}
	else
	{
//      printf("ASC: %02x to %x (was %x)\n", data, offset, m_regs[offset-0x800]);

		m_stream->update();
		switch (offset)
		{
			case R_MODE:
				data &= 3;  // only bits 0 and 1 can be written

				//printf("%d to MODE\n", data);

				if (data != m_regs[R_MODE-0x800])
				{
					m_fifo_a_rdptr = m_fifo_b_rdptr = 0;
					m_fifo_a_wrptr = m_fifo_b_wrptr = 0;
					m_fifo_cap_a = m_fifo_cap_b = 0;

					if (data != 0)
					{
						m_timer->adjust(attotime::zero, 0, attotime::from_hz(22257/4));
					}
					else
					{
						m_timer->adjust(attotime::never);
					}
				}
				break;

			case R_FIFOMODE:
				if (data & 0x80)
				{
					m_fifo_a_rdptr = m_fifo_b_rdptr = 0;
					m_fifo_a_wrptr = m_fifo_b_wrptr = 0;
					m_fifo_cap_a = m_fifo_cap_b = 0;
					m_regs[R_FIFOSTAT-0x800] |= 0xa;  // fifos A&B empty
				}
				break;

			case R_WTCONTROL:
//              printf("One-shot wavetable %02x\n", data);
				break;

			case 0x811:
				m_phase[0] &= 0x00ffff;
				m_phase[0] |= data<<16;
				break;

			case 0x812:
				m_phase[0] &= 0xff00ff;
				m_phase[0] |= data<<8;
				break;

			case 0x813:
				m_phase[0] &= 0xffff00;
				m_phase[0] |= data;
				break;

			case 0x815:
				m_incr[0] &= 0x00ffff;
				m_incr[0] |= data<<16;
				break;

			case 0x816:
				m_incr[0] &= 0xff00ff;
				m_incr[0] |= data<<8;
				break;

			case 0x817:
				m_incr[0] &= 0xffff00;
				m_incr[0] |= data;
				break;

			case 0x819:
				m_phase[1] &= 0x00ffff;
				m_phase[1] |= data<<16;
				break;

			case 0x81a:
				m_phase[1] &= 0xff00ff;
				m_phase[1] |= data<<8;
				break;

			case 0x81b:
				m_phase[1] &= 0xffff00;
				m_phase[1] |= data;
				break;

			case 0x81d:
				m_incr[1] &= 0x00ffff;
				m_incr[1] |= data<<16;
				break;

			case 0x81e:
				m_incr[1] &= 0xff00ff;
				m_incr[1] |= data<<8;
				break;

			case 0x81f:
				m_incr[1] &= 0xffff00;
				m_incr[1] |= data;
				break;

			case 0x821:
				m_phase[2] &= 0x00ffff;
				m_phase[2] |= data<<16;
				break;

			case 0x822:
				m_phase[2] &= 0xff00ff;
				m_phase[2] |= data<<8;
				break;

			case 0x823:
				m_phase[2] &= 0xffff00;
				m_phase[2] |= data;
				break;

			case 0x825:
				m_incr[2] &= 0x00ffff;
				m_incr[2] |= data<<16;
				break;

			case 0x826:
				m_incr[2] &= 0xff00ff;
				m_incr[2] |= data<<8;
				break;

			case 0x827:
				m_incr[2] &= 0xffff00;
				m_incr[2] |= data;
				break;

			case 0x829:
				m_phase[3] &= 0x00ffff;
				m_phase[3] |= data<<16;
				break;

			case 0x82a:
				m_phase[3] &= 0xff00ff;
				m_phase[3] |= data<<8;
				break;

			case 0x82b:
				m_phase[3] &= 0xffff00;
				m_phase[3] |= data;
				break;

			case 0x82d:
				m_incr[3] &= 0x00ffff;
				m_incr[3] |= data<<16;
				break;

			case 0x82e:
				m_incr[3] &= 0xff00ff;
				m_incr[3] |= data<<8;
				break;

			case 0x82f:
				m_incr[3] &= 0xffff00;
				m_incr[3] |= data;
				break;
		}

		if (offset >= 0x800 && offset < 0x1000)
		{
			m_regs[offset-0x800] = data;
		}
	}
}