📄 3812intf.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 + -