⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 3812intf.c

📁 著名ARC模拟器源码,包括多个平台
💻 C
字号:
/*$DEADSERIOUSCLAN$********************************************************************** FILE*	Yamaha 3812 emulator interface - MAME VERSION** CREATED BY*	Ernesto Corvi** UPDATE LOG*	CHS 1999-01-09	Fixes new ym3812 emulation interface.*	CHS 1998-10-23	Mame streaming sound chip update*	EC	1998		Created Interface** NOTES****************************************************************************************/#include "driver.h"#include <stdlib.h>#include "sasound.h"#include "3812intf.h"#include "fm.h"#define OPL3CONVERTFREQUENCY#define TIME_IN_HZ(hz)        (1.0 / (double)(hz))#define timer_remove(t) t=NULL/* This frequency is from Yamaha 3812 and 2413 documentation */#define ym3812_StdClock 3579545/* Emulated YM3812 variables and defines */static int stream[MAX_3812];static void *Timer[MAX_3812*2];/* Non-Emulated YM3812 variables and defines */typedef struct non_emu3812_state {	int address_register;	unsigned char status_register;	unsigned char timer_register;	unsigned int timer1_val;	unsigned int timer2_val;	void *timer1;	void *timer2;	int aOPLFreqArray[16];		/* Up to 9 channels.. */}NE_OPL_STATE;#ifndef __RAINE__static double timer_step;static NE_OPL_STATE *nonemu_state;#endif/* These ones are used by both *//*static const struct YM3812interface *intf = NULL; */static const struct Y8950interface *intf = NULL;/* Function procs to access the selected YM type *//* static int ( *sh_start )( const struct MachineSound *msound ); */static void ( *sh_stop )( void );static int ( *status_port_r )( int chip );static void ( *control_port_w )( int chip, int data );static void ( *write_port_w )( int chip, int data );static int ( *read_port_r )( int chip );/**********************************************************************************************	Begin of non-emulated YM3812 interface block **********************************************************************************************/#ifndef __RAINE__static void timer1_callback (int chip){	NE_OPL_STATE *st = &nonemu_state[chip];	if (!(st->timer_register & 0x40))	{		if(!(st->status_register&0x80))			if (intf->handler[chip]) (intf->handler[chip])(ASSERT_LINE);		/* set the IRQ and timer 1 signal bits */		st->status_register |= 0x80|0x40;	}	/* next! */	st->timer1 = timer_set ((double)st->timer1_val*4*timer_step, chip, timer1_callback);}static void timer2_callback (int chip){	NE_OPL_STATE *st = &nonemu_state[chip];	if (!(st->timer_register & 0x20))	{		if(!(st->status_register&0x80))			if (intf->handler[chip]) (intf->handler[chip])(ASSERT_LINE);		/* set the IRQ and timer 2 signal bits */		st->status_register |= 0x80|0x20;	}	/* next! */	st->timer2 = timer_set ((double)st->timer2_val*16*timer_step, chip, timer2_callback);}static int nonemu_YM3812_sh_start(const struct YM3812interface *msound){	int i;	intf = ((struct Y8950interface*)msound);	nonemu_state = malloc(intf->num * sizeof(NE_OPL_STATE) );	if(nonemu_state==NULL) return 1;	memset(nonemu_state,0,intf->num * sizeof(NE_OPL_STATE));	for(i=0;i<intf->num;i++)	{		nonemu_state[i].address_register = 0;		nonemu_state[i].timer1 =		nonemu_state[i].timer2 = 0;		nonemu_state[i].status_register = 0;		nonemu_state[i].timer_register = 0;		nonemu_state[i].timer1_val =		nonemu_state[i].timer2_val = 256;	}	timer_step = TIME_IN_HZ((double)intf->baseclock / 72.0);	return 0;}static void nonemu_YM3812_sh_stop(void){	YM3812_sh_reset();	free(nonemu_state);}static int nonemu_YM3812_status_port_r(int chip){	NE_OPL_STATE *st = &nonemu_state[chip];	/* mask out the timer 1 and 2 signal bits as requested by the timer register */	return st->status_register & ~(st->timer_register & 0x60);}static void nonemu_YM3812_control_port_w(int chip,int data){	NE_OPL_STATE *st = &nonemu_state[chip];	st->address_register = data;	/* pass through all non-timer registers */#ifdef OPL3CONVERTFREQUENCY	if ( ((data==0xbd)||((data&0xe0)!=0xa0)) && ((data<2)||(data>4)) )#else	if ( ((data<2)||(data>4)) )#endif	  osd_opl_control(chip,data);}static void nonemu_WriteConvertedFrequency( int chip,int nFrq, int nCh ){	int		nRealOctave;	double	vRealFrq;	vRealFrq = (((nFrq&0x3ff)<<((nFrq&0x7000)>>12))) * (double)intf->baseclock / (double)ym3812_StdClock;	nRealOctave = 0;	while( (vRealFrq>1023.0)&&(nRealOctave<7) )	{		vRealFrq /= 2.0;		nRealOctave++;	}	osd_opl_control(chip,0xa0|nCh);	osd_opl_write(chip,((int)vRealFrq)&0xff);	osd_opl_control(chip,0xb0|nCh);	osd_opl_write(chip,((((int)vRealFrq)>>8)&3)|(nRealOctave<<2)|((nFrq&0x8000)>>10) );}static void nonemu_YM3812_write_port_w(int chip,int data){	NE_OPL_STATE *st = &nonemu_state[chip];	int nCh = st->address_register&0x0f;#ifdef OPL3CONVERTFREQUENCY	if( (nCh<9) )	{		if( (st->address_register&0xf0) == 0xa0 )		{			st->aOPLFreqArray[nCh] = (st->aOPLFreqArray[nCh] & 0xf300)|(data&0xff);			nonemu_WriteConvertedFrequency(chip, st->aOPLFreqArray[nCh], nCh );			return;		}		else if( (st->address_register&0xf0)==0xb0 )		{			st->aOPLFreqArray[st->address_register&0xf] = (st->aOPLFreqArray[nCh] & 0x00ff)|((data&0x3)<<8)|((data&0x1c)<<10)|((data&0x20)<<10);			nonemu_WriteConvertedFrequency(chip, st->aOPLFreqArray[nCh], nCh );			return;		}	}#endif	switch (st->address_register)	{		case 2:			st->timer1_val = 256 - data;			break;		case 3:			st->timer2_val = 256 - data;			break;		case 4:			/* bit 7 means reset the IRQ signal and status bits, and ignore all the other bits */			if (data & 0x80)			{				if(st->status_register&0x80)					if (intf->handler[chip]) (intf->handler[chip])(CLEAR_LINE);				st->status_register = 0;			}			else			{				/* set the new timer register */				st->timer_register = data;					/*  bit 0 starts/stops timer 1 */				if (data & 0x01)				{					if (!st->timer1)					  st->timer1 = timer_set ((double)st->timer1_val*4*timer_step, chip, timer1_callback);				}				else				  if (st->timer1)				{					timer_remove (st->timer1);					st->timer1 = 0;				}								/*  bit 1 starts/stops timer 2 */				if (data & 0x02)				{					if (!st->timer2)					  st->timer2 = timer_set ((double)st->timer2_val*16*timer_step, chip, timer2_callback);				}				else if (st->timer2)				{					timer_remove (st->timer2);					st->timer2 = 0;				}				/* bits 5 & 6 clear and mask the appropriate bit in the status register */				st->status_register &= ~(data & 0x60);				if(!(st->status_register&0x7f))				{					if(st->status_register&0x80)						if (intf->handler[chip]) (intf->handler[chip])(CLEAR_LINE);					st->status_register &=0x7f;				}			}			break;		default:			osd_opl_write(chip,data);	}}static int nonemu_YM3812_read_port_r( int chip ) {	return 0;}#endif/**********************************************************************************************	End of non-emulated YM3812 interface block **********************************************************************************************/#include "sound/fmopl.h"typedef void (*STREAM_HANDLER)(int param,void *buffer,int length);static int chiptype;static FM_OPL *F3812[MAX_3812];/* IRQ Handler */static void IRQHandler(int n,int irq){	if (intf->handler[n]) (intf->handler[n])(irq ? ASSERT_LINE : CLEAR_LINE);}/* update handler */static void YM3812UpdateHandler(int n, INT16 *buf, int length){	YM3812UpdateOne(F3812[n],buf,length); }#if (HAS_Y8950)static void Y8950UpdateHandler(int n, INT16 *buf, int length){	Y8950UpdateOne(F3812[n],buf,length); }static unsigned char Y8950PortHandler_r(int chip){	return intf->portread[chip](chip); }static void Y8950PortHandler_w(int chip,unsigned char data){	intf->portwrite[chip](chip,data); }static unsigned char Y8950KeyboardHandler_r(int chip){	return intf->keyboardread[chip](chip); }static void Y8950KeyboardHandler_w(int chip,unsigned char data){	intf->keyboardwrite[chip](chip,data); }#endif/* Timer overflow callback from timer.c */static void timer_callback_3812(int param){	int n=param>>1;	int c=param&1;	Timer[param] = 0;	OPLTimerOver(F3812[n],c);}/* TimerHandler from fm.c */static void TimerHandler(int c,double period){	if( period == 0 )	{	/* Reset FM Timer */		if( Timer[c] )		{	 		timer_remove (Timer[c]);			Timer[c] = 0;		}	}#ifndef __RAINE__	else	{	/* Start FM Timer */		Timer[c] = timer_set(period, c, timer_callback_3812 );	}#endif	}/************************************************//* Sound Hardware Start							*//************************************************/static int emu_YM3812_sh_start(const struct YM3812interface *msound){	int i;	int rate = audio_sample_rate;	intf = ((struct Y8950interface *)msound);	if( intf->num > MAX_3812 ) return 1;	/* Timer state clear */	memset(Timer,0,sizeof(Timer));	/* stream system initialize */	for (i = 0;i < intf->num;i++)	{		/* stream setup */		char name[40];		int vol = intf->mixing_level[i];		/* emulator create */		F3812[i] = OPLCreate(chiptype,intf->baseclock,rate);		if(F3812[i] == NULL) return 1;		/* stream setup */		sprintf(name,"%s #%d","YM3812",i);#if (HAS_Y8950)		/* ADPCM ROM DATA */		if(chiptype == OPL_TYPE_Y8950)		{			F3812[i]->deltat->memory = (unsigned char *)(memory_region(intf->rom_region[i]));			F3812[i]->deltat->memory_size = memory_region_length(intf->rom_region[i]);			stream[i] = stream_init(name,rate,16,i,Y8950UpdateHandler);			stream_set_volume(stream[i],vol);			/* port and keyboard handler */			OPLSetPortHandler(F3812[i],Y8950PortHandler_w,Y8950PortHandler_r,i);			OPLSetKeyboardHandler(F3812[i],Y8950KeyboardHandler_w,Y8950KeyboardHandler_r,i);		}		else#endif		stream[i] = stream_init(name,rate,16,i,YM3812UpdateHandler);		stream_set_volume(stream[i],vol);		/* YM3812 setup */		OPLSetTimerHandler(F3812[i],TimerHandler,i*2);		OPLSetIRQHandler(F3812[i]  ,IRQHandler,i);		OPLSetUpdateHandler(F3812[i],stream_update,stream[i]);	}	return 0;}/************************************************//* Sound Hardware Stop							*//************************************************/static void emu_YM3812_sh_stop(void){	int i;	for (i = 0;i < intf->num;i++)	{		OPLDestroy(F3812[i]);	}}/* reset */static void emu_YM3812_sh_reset(void){	int i;	for (i = 0;i < intf->num;i++)		OPLResetChip(F3812[i]);}static int emu_YM3812_status_port_r(int chip){	return OPLRead(F3812[chip],0);}static void emu_YM3812_control_port_w(int chip,int data){	OPLWrite(F3812[chip],0,data);}static void emu_YM3812_write_port_w(int chip,int data){	OPLWrite(F3812[chip],1,data);}static int emu_YM3812_read_port_r(int chip){	return OPLRead(F3812[chip],1);}/**********************************************************************************************	Begin of YM3812 interface stubs block **********************************************************************************************/int use_emulated_ym3812=0;static int OPL_sh_start(const struct YM3812interface *msound){	if ( use_emulated_ym3812 ) {		sh_stop  = emu_YM3812_sh_stop;		status_port_r = emu_YM3812_status_port_r;		control_port_w = emu_YM3812_control_port_w;		write_port_w = emu_YM3812_write_port_w;		read_port_r = emu_YM3812_read_port_r;		return emu_YM3812_sh_start(msound);	}#ifndef __RAINE__	// Anyway it can't be tested now... sorry !	else {		sh_stop = nonemu_YM3812_sh_stop;		status_port_r = nonemu_YM3812_status_port_r;		control_port_w = nonemu_YM3812_control_port_w;		write_port_w = nonemu_YM3812_write_port_w;		read_port_r = nonemu_YM3812_read_port_r;		return nonemu_YM3812_sh_start(msound);	}#endif		return 0;}int YM3812_sh_start(const struct YM3812interface *msound){	chiptype = OPL_TYPE_YM3812;	return OPL_sh_start(msound);}void YM3812_sh_stop( void ) {	(*sh_stop)();}void YM3812_sh_reset(void){	int i;	for(i=0xff;i<=0;i--)	{		YM3812_control_port_0_w(0,i);		YM3812_write_port_0_w(0,0);	}	/* IRQ clear */	YM3812_control_port_0_w(0,4);	YM3812_write_port_0_w(0,0x80);}WRITE_HANDLER( YM3812_control_port_0_w ) {  if (RaineSoundCard)    (*control_port_w)( 0, data );}WRITE_HANDLER( YM3812_write_port_0_w ) {  if (RaineSoundCard)    (*write_port_w)( 0, data );}READ_HANDLER( YM3812_status_port_0_r ) {   static int ta;   if(RaineSoundCard>0){      return (*status_port_r)( 0 );   }   else{      ta^=255;      return ta;			// ADDED FOR SAFETY   }}READ_HANDLER( YM3812_read_port_0_r ) {   static int ta;   if(RaineSoundCard>0){      return (*read_port_r)( 0 );   }   else{      ta^=255;      return ta;			// ADDED FOR SAFETY   }}WRITE_HANDLER( YM3812_control_port_1_w ) {   if(RaineSoundCard>0)	(*control_port_w)( 1, data );}WRITE_HANDLER( YM3812_write_port_1_w ) {   if(RaineSoundCard>0)	(*write_port_w)( 1, data );}READ_HANDLER( YM3812_status_port_1_r ) {   static int ta;   if(RaineSoundCard>0){      return (*status_port_r)( 1 );   }   else{      ta^=255;      return ta;			// ADDED FOR SAFETY   }}READ_HANDLER( YM3812_read_port_1_r ) {   static int ta;   if(RaineSoundCard>0){      return (*read_port_r)( 1 );   }   else{      ta^=255;      return ta;			// ADDED FOR SAFETY   }}UINT8 YM3812ReadZ80(UINT16 offset){   if((offset&1)==0)      return YM3812_status_port_0_r(offset)|0x60;	// Snow Bros fix/no timer emulation :(.   else      return YM3812_read_port_0_r(offset);}void YM3812WriteZ80(UINT16 offset, UINT8 data){  if((offset&1)==0)    YM3812_control_port_0_w(offset,data);  else    YM3812_write_port_0_w(offset,data);}/**********************************************************************************************	End of YM3812 interface stubs block **********************************************************************************************//**********************************************************************************************	Begin of YM3526 interface stubs block **********************************************************************************************/int YM3526_sh_start(const struct YM3526interface *msound){	chiptype = OPL_TYPE_YM3526;	return OPL_sh_start(msound);}/**********************************************************************************************	End of YM3526 interface stubs block **********************************************************************************************//**********************************************************************************************	Begin of Y8950 interface stubs block **********************************************************************************************/#if (HAS_Y8950)int Y8950_sh_start(const struct YM8950interface *msound){	chiptype = OPL_TYPE_Y8950;	if( OPL_sh_start(msound) ) return 1;	/* !!!!! port handler set !!!!! */	/* !!!!! delta-t memory address set !!!!! */	return 0;}#endif/**********************************************************************************************	End of Y8950 interface stubs block **********************************************************************************************/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -