1 /*$DEADSERIOUSCLAN$*********************************************************************
2 * FILE
3 *	Yamaha 3812 emulator interface - MAME VERSION
4 *
5 * CREATED BY
6 *	Ernesto Corvi
7 *
8 * UPDATE LOG
9 *	CHS 1999-01-09	Fixes new ym3812 emulation interface.
10 *	CHS 1998-10-23	Mame streaming sound chip update
11 *	EC	1998		Created Interface
12 *
13 * NOTES
14 *
15 ***************************************************************************************/
16 #include "driver.h"
17 #include "3812intf.h"
18 #include "fm.h"
19 
20 #define OPL3CONVERTFREQUENCY
21 
22 /* This frequency is from Yamaha 3812 and 2413 documentation */
23 #define ym3812_StdClock 3579545
24 
25 
26 /* Emulated YM3812 variables and defines */
27 static int stream[MAX_3812];
28 static void *Timer[MAX_3812*2];
29 
30 /* Non-Emulated YM3812 variables and defines */
31 typedef struct non_emu3812_state {
32 	int address_register;
33 	unsigned char status_register;
34 	unsigned char timer_register;
35 	unsigned int timer1_val;
36 	unsigned int timer2_val;
37 	void *timer1;
38 	void *timer2;
39 	int aOPLFreqArray[16];		/* Up to 9 channels.. */
40 }NE_OPL_STATE;
41 
42 static timer_tm timer_step;
43 static NE_OPL_STATE *nonemu_state;
44 
45 /* These ones are used by both */
46 /*static const struct YM3812interface *intf = NULL; */
47 static const struct Y8950interface *intf = NULL;
48 
49 /* Function procs to access the selected YM type */
50 /* static int ( *sh_start )( const struct MachineSound *msound ); */
51 static void ( *sh_stop )( void );
52 static int ( *status_port_r )( int chip );
53 static void ( *control_port_w )( int chip, int data );
54 static void ( *write_port_w )( int chip, int data );
55 static int ( *read_port_r )( int chip );
56 
57 /**********************************************************************************************
58 	Begin of non-emulated YM3812 interface block
59  **********************************************************************************************/
60 
timer1_callback(int chip)61 static void timer1_callback (int chip)
62 {
63 	NE_OPL_STATE *st = &nonemu_state[chip];
64 	if (!(st->timer_register & 0x40))
65 	{
66 		if(!(st->status_register&0x80))
67 			if (intf->handler[chip]) (intf->handler[chip])(ASSERT_LINE);
68 		/* set the IRQ and timer 1 signal bits */
69 		st->status_register |= 0x80|0x40;
70 	}
71 
72 	/* next! */
73 	st->timer1 = timer_set ((timer_tm)st->timer1_val*4*timer_step, chip, timer1_callback);
74 }
75 
timer2_callback(int chip)76 static void timer2_callback (int chip)
77 {
78 	NE_OPL_STATE *st = &nonemu_state[chip];
79 	if (!(st->timer_register & 0x20))
80 	{
81 		if(!(st->status_register&0x80))
82 			if (intf->handler[chip]) (intf->handler[chip])(ASSERT_LINE);
83 		/* set the IRQ and timer 2 signal bits */
84 		st->status_register |= 0x80|0x20;
85 	}
86 
87 	/* next! */
88 	st->timer2 = timer_set ((timer_tm)st->timer2_val*16*timer_step, chip, timer2_callback);
89 }
90 
nonemu_YM3812_sh_start(const struct MachineSound * msound)91 static int nonemu_YM3812_sh_start(const struct MachineSound *msound)
92 {
93 	int i;
94 
95 	intf = (const struct Y8950interface *)msound->sound_interface;
96 
97 	nonemu_state = (NE_OPL_STATE*)malloc(intf->num * sizeof(NE_OPL_STATE) );
98 	if(nonemu_state==NULL) return 1;
99 	memset(nonemu_state,0,intf->num * sizeof(NE_OPL_STATE));
100 	for(i=0;i<intf->num;i++)
101 	{
102 		nonemu_state[i].address_register = 0;
103 		nonemu_state[i].timer1 =
104 		nonemu_state[i].timer2 = 0;
105 		nonemu_state[i].status_register = 0;
106 		nonemu_state[i].timer_register = 0;
107 		nonemu_state[i].timer1_val =
108 		nonemu_state[i].timer2_val = 256;
109 	}
110 	timer_step = TIME_IN_HZ((float)intf->baseclock / 72.0);
111 	return 0;
112 }
113 
nonemu_YM3812_sh_stop(void)114 static void nonemu_YM3812_sh_stop(void)
115 {
116 	YM3812_sh_reset();
117 	free(nonemu_state);
118 }
119 
nonemu_YM3812_status_port_r(int chip)120 static int nonemu_YM3812_status_port_r(int chip)
121 {
122 	NE_OPL_STATE *st = &nonemu_state[chip];
123 	/* mask out the timer 1 and 2 signal bits as requested by the timer register */
124 	return st->status_register & ~(st->timer_register & 0x60);
125 }
126 
nonemu_YM3812_control_port_w(int chip,int data)127 static void nonemu_YM3812_control_port_w(int chip,int data)
128 {
129 	NE_OPL_STATE *st = &nonemu_state[chip];
130 	st->address_register = data;
131 
132 	/* pass through all non-timer registers */
133 #ifdef OPL3CONVERTFREQUENCY
134 	if ( ((data==0xbd)||((data&0xe0)!=0xa0)) && ((data<2)||(data>4)) )
135 #else
136 	if ( ((data<2)||(data>4)) )
137 #endif
138 		osd_opl_control(chip,data);
139 }
140 
nonemu_WriteConvertedFrequency(int chip,int nFrq,int nCh)141 static void nonemu_WriteConvertedFrequency( int chip,int nFrq, int nCh )
142 {
143 	int		nRealOctave;
144 	int	vRealFrq;
145 
146 	vRealFrq = (((nFrq&0x3ff)<<((nFrq&0x7000)>>12))) * (float)intf->baseclock / (float)ym3812_StdClock;
147 	nRealOctave = 0;
148 
149 	while( (vRealFrq>1023.0)&&(nRealOctave<7) )
150 	{
151 		vRealFrq /= 2.0;
152 		nRealOctave++;
153 	}
154 	osd_opl_control(chip,0xa0|nCh);
155 	osd_opl_write(chip,((int)vRealFrq)&0xff);
156 	osd_opl_control(chip,0xb0|nCh);
157 	osd_opl_write(chip,((((int)vRealFrq)>>8)&3)|(nRealOctave<<2)|((nFrq&0x8000)>>10) );
158 }
159 
nonemu_YM3812_write_port_w(int chip,int data)160 static void nonemu_YM3812_write_port_w(int chip,int data)
161 {
162 	NE_OPL_STATE *st = &nonemu_state[chip];
163 	int nCh = st->address_register&0x0f;
164 
165 #ifdef OPL3CONVERTFREQUENCY
166 	if( (nCh<9) )
167 	{
168 		if( (st->address_register&0xf0) == 0xa0 )
169 		{
170 			st->aOPLFreqArray[nCh] = (st->aOPLFreqArray[nCh] & 0xf300)|(data&0xff);
171 			nonemu_WriteConvertedFrequency(chip, st->aOPLFreqArray[nCh], nCh );
172 			return;
173 		}
174 		else if( (st->address_register&0xf0)==0xb0 )
175 		{
176 			st->aOPLFreqArray[st->address_register&0xf] = (st->aOPLFreqArray[nCh] & 0x00ff)|((data&0x3)<<8)|((data&0x1c)<<10)|((data&0x20)<<10);
177 			nonemu_WriteConvertedFrequency(chip, st->aOPLFreqArray[nCh], nCh );
178 			return;
179 		}
180 	}
181 #endif
182 	switch (st->address_register)
183 	{
184 		case 2:
185 			st->timer1_val = 256 - data;
186 			break;
187 		case 3:
188 			st->timer2_val = 256 - data;
189 			break;
190 		case 4:
191 			/* bit 7 means reset the IRQ signal and status bits, and ignore all the other bits */
192 			if (data & 0x80)
193 			{
194 				if(st->status_register&0x80)
195 					if (intf->handler[chip]) (intf->handler[chip])(CLEAR_LINE);
196 				st->status_register = 0;
197 			}
198 			else
199 			{
200 				/* set the new timer register */
201 				st->timer_register = data;
202 					/*  bit 0 starts/stops timer 1 */
203 				if (data & 0x01)
204 				{
205 					if (!st->timer1)
206 						st->timer1 = timer_set ((timer_tm)st->timer1_val*4*timer_step, chip, timer1_callback);
207 				}
208 				else if (st->timer1)
209 				{
210 					timer_remove (st->timer1);
211 					st->timer1 = 0;
212 				}
213 				/*  bit 1 starts/stops timer 2 */
214 				if (data & 0x02)
215 				{
216 					if (!st->timer2)
217 						st->timer2 = timer_set ((timer_tm)st->timer2_val*16*timer_step, chip, timer2_callback);
218 				}
219 				else if (st->timer2)
220 				{
221 					timer_remove (st->timer2);
222 					st->timer2 = 0;
223 				}
224 				/* bits 5 & 6 clear and mask the appropriate bit in the status register */
225 				st->status_register &= ~(data & 0x60);
226 
227 				if(!(st->status_register&0x7f))
228 				{
229 					if(st->status_register&0x80)
230 						if (intf->handler[chip]) (intf->handler[chip])(CLEAR_LINE);
231 					st->status_register &=0x7f;
232 				}
233 			}
234 			break;
235 		default:
236 			osd_opl_write(chip,data);
237 	}
238 }
239 
nonemu_YM3812_read_port_r(int chip)240 static int nonemu_YM3812_read_port_r( int chip ) {
241 	return 0;
242 }
243 
244 /**********************************************************************************************
245 	End of non-emulated YM3812 interface block
246  **********************************************************************************************/
247 
248 #include "sound/fmopl.h"
249 
250 typedef void (*STREAM_HANDLER)(int param,void *buffer,int length);
251 
252 static int chiptype;
253 static FM_OPL *F3812[MAX_3812];
254 
255 /* IRQ Handler */
IRQHandler(int n,int irq)256 static void IRQHandler(int n,int irq)
257 {
258 	if (intf->handler[n]) (intf->handler[n])(irq ? ASSERT_LINE : CLEAR_LINE);
259 }
260 
261 /* update handler */
YM3812UpdateHandler(int n,INT16 * buf,int length)262 static void YM3812UpdateHandler(int n, INT16 *buf, int length)
263 {	YM3812UpdateOne(F3812[n],buf,length); }
264 
265 #if (HAS_Y8950)
Y8950UpdateHandler(int n,INT16 * buf,int length)266 static void Y8950UpdateHandler(int n, INT16 *buf, int length)
267 {	Y8950UpdateOne(F3812[n],buf,length); }
268 
Y8950PortHandler_r(int chip)269 static unsigned char Y8950PortHandler_r(int chip)
270 {	return intf->portread[chip](chip); }
271 
Y8950PortHandler_w(int chip,unsigned char data)272 static void Y8950PortHandler_w(int chip,unsigned char data)
273 {	intf->portwrite[chip](chip,data); }
274 
Y8950KeyboardHandler_r(int chip)275 static unsigned char Y8950KeyboardHandler_r(int chip)
276 {	return intf->keyboardread[chip](chip); }
277 
Y8950KeyboardHandler_w(int chip,unsigned char data)278 static void Y8950KeyboardHandler_w(int chip,unsigned char data)
279 {	intf->keyboardwrite[chip](chip,data); }
280 #endif
281 
282 /* Timer overflow callback from timer.c */
timer_callback_3812(int param)283 static void timer_callback_3812(int param)
284 {
285 	int n=param>>1;
286 	int c=param&1;
287 	Timer[param] = 0;
288 	OPLTimerOver(F3812[n],c);
289 }
290 
291 /* TimerHandler from fm.c */
TimerHandler(int c,timer_tm period)292 static void TimerHandler(int c,timer_tm period)
293 {
294 	if( period == 0 )
295 	{	/* Reset FM Timer */
296 		if( Timer[c] )
297 		{
298 	 		timer_remove (Timer[c]);
299 			Timer[c] = 0;
300 		}
301 	}
302 	else
303 	{	/* Start FM Timer */
304 		Timer[c] = timer_set(period, c, timer_callback_3812 );
305 	}
306 }
307 
308 /************************************************/
309 /* Sound Hardware Start							*/
310 /************************************************/
emu_YM3812_sh_start(const struct MachineSound * msound)311 static int emu_YM3812_sh_start(const struct MachineSound *msound)
312 {
313 	int i;
314 	int rate = Machine->sample_rate;
315 
316 	intf = (const struct Y8950interface *)msound->sound_interface;
317 	if( intf->num > MAX_3812 ) return 1;
318 
319 	/* Timer state clear */
320 	memset(Timer,0,sizeof(Timer));
321 
322 	/* stream system initialize */
323 	for (i = 0;i < intf->num;i++)
324 	{
325 		/* stream setup */
326 		char name[40];
327 		int vol = intf->mixing_level[i];
328 		/* emulator create */
329 		F3812[i] = OPLCreate(chiptype,intf->baseclock,rate);
330 		if(F3812[i] == NULL) return 1;
331 		/* stream setup */
332 		sprintf(name,"%s #%d",sound_name(msound),i);
333 #if (HAS_Y8950)
334 		/* ADPCM ROM DATA */
335 		if(chiptype == OPL_TYPE_Y8950)
336 		{
337 			F3812[i]->deltat->memory = (unsigned char *)(memory_region(intf->rom_region[i]));
338 			F3812[i]->deltat->memory_size = memory_region_length(intf->rom_region[i]);
339 			stream[i] = stream_init(name,vol,rate,i,Y8950UpdateHandler);
340 			/* port and keyboard handler */
341 			OPLSetPortHandler(F3812[i],Y8950PortHandler_w,Y8950PortHandler_r,i);
342 			OPLSetKeyboardHandler(F3812[i],Y8950KeyboardHandler_w,Y8950KeyboardHandler_r,i);
343 		}
344 		else
345 #endif
346 		stream[i] = stream_init(name,vol,rate,i,YM3812UpdateHandler);
347 		/* YM3812 setup */
348 		OPLSetTimerHandler(F3812[i],TimerHandler,i*2);
349 		OPLSetIRQHandler(F3812[i]  ,IRQHandler,i);
350 		OPLSetUpdateHandler(F3812[i],stream_update,stream[i]);
351 	}
352 	return 0;
353 }
354 
355 /************************************************/
356 /* Sound Hardware Stop							*/
357 /************************************************/
emu_YM3812_sh_stop(void)358 static void emu_YM3812_sh_stop(void)
359 {
360 	int i;
361 
362 	for (i = 0;i < intf->num;i++)
363 	{
364 		OPLDestroy(F3812[i]);
365 	}
366 }
367 
368 /* reset */
369 /*
370 static void emu_YM3812_sh_reset(void)
371 {
372 	int i;
373 
374 	for (i = 0;i < intf->num;i++)
375 		OPLResetChip(F3812[i]);
376 }
377 */
378 
emu_YM3812_status_port_r(int chip)379 static int emu_YM3812_status_port_r(int chip)
380 {
381 	return OPLRead(F3812[chip],0);
382 }
emu_YM3812_control_port_w(int chip,int data)383 static void emu_YM3812_control_port_w(int chip,int data)
384 {
385 	OPLWrite(F3812[chip],0,data);
386 }
emu_YM3812_write_port_w(int chip,int data)387 static void emu_YM3812_write_port_w(int chip,int data)
388 {
389 	OPLWrite(F3812[chip],1,data);
390 }
391 
emu_YM3812_read_port_r(int chip)392 static int emu_YM3812_read_port_r(int chip)
393 {
394 	return OPLRead(F3812[chip],1);
395 }
396 
397 /**********************************************************************************************
398 	Begin of YM3812 interface stubs block
399  **********************************************************************************************/
400 
OPL_sh_start(const struct MachineSound * msound)401 static int OPL_sh_start(const struct MachineSound *msound)
402 {
403 	if ( options.use_emulated_ym3812 ) {
404 		sh_stop  = emu_YM3812_sh_stop;
405 		status_port_r = emu_YM3812_status_port_r;
406 		control_port_w = emu_YM3812_control_port_w;
407 		write_port_w = emu_YM3812_write_port_w;
408 		read_port_r = emu_YM3812_read_port_r;
409 		return emu_YM3812_sh_start(msound);
410 	} else {
411 		sh_stop = nonemu_YM3812_sh_stop;
412 		status_port_r = nonemu_YM3812_status_port_r;
413 		control_port_w = nonemu_YM3812_control_port_w;
414 		write_port_w = nonemu_YM3812_write_port_w;
415 		read_port_r = nonemu_YM3812_read_port_r;
416 		return nonemu_YM3812_sh_start(msound);
417 	}
418 }
419 
YM3812_sh_start(const struct MachineSound * msound)420 int YM3812_sh_start(const struct MachineSound *msound)
421 {
422 	chiptype = OPL_TYPE_YM3812;
423 	return OPL_sh_start(msound);
424 }
425 
YM3812_sh_stop(void)426 void YM3812_sh_stop( void ) {
427 	(*sh_stop)();
428 }
429 
YM3812_sh_reset(void)430 void YM3812_sh_reset(void)
431 {
432 	int i;
433 
434 	for(i=0xff;i<=0;i--)
435 	{
436 		YM3812_control_port_0_w(0,i);
437 		YM3812_write_port_0_w(0,0);
438 	}
439 	/* IRQ clear */
440 	YM3812_control_port_0_w(0,4);
441 	YM3812_write_port_0_w(0,0x80);
442 }
443 
WRITE_HANDLER(YM3812_control_port_0_w)444 WRITE_HANDLER( YM3812_control_port_0_w ) {
445 	(*control_port_w)( 0, data );
446 }
447 
WRITE_HANDLER(YM3812_write_port_0_w)448 WRITE_HANDLER( YM3812_write_port_0_w ) {
449 	(*write_port_w)( 0, data );
450 }
451 
READ_HANDLER(YM3812_status_port_0_r)452 READ_HANDLER( YM3812_status_port_0_r ) {
453 	return (*status_port_r)( 0 );
454 }
455 
READ_HANDLER(YM3812_read_port_0_r)456 READ_HANDLER( YM3812_read_port_0_r ) {
457 	return (*read_port_r)( 0 );
458 }
459 
WRITE_HANDLER(YM3812_control_port_1_w)460 WRITE_HANDLER( YM3812_control_port_1_w ) {
461 	(*control_port_w)( 1, data );
462 }
463 
WRITE_HANDLER(YM3812_write_port_1_w)464 WRITE_HANDLER( YM3812_write_port_1_w ) {
465 	(*write_port_w)( 1, data );
466 }
467 
READ_HANDLER(YM3812_status_port_1_r)468 READ_HANDLER( YM3812_status_port_1_r ) {
469 	return (*status_port_r)( 1 );
470 }
471 
READ_HANDLER(YM3812_read_port_1_r)472 READ_HANDLER( YM3812_read_port_1_r ) {
473 	return (*read_port_r)( 1 );
474 }
475 
476 /**********************************************************************************************
477 	End of YM3812 interface stubs block
478  **********************************************************************************************/
479 
480 /**********************************************************************************************
481 	Begin of YM3526 interface stubs block
482  **********************************************************************************************/
YM3526_sh_start(const struct MachineSound * msound)483 int YM3526_sh_start(const struct MachineSound *msound)
484 {
485 	chiptype = OPL_TYPE_YM3526;
486 	return OPL_sh_start(msound);
487 }
488 
489 /**********************************************************************************************
490 	End of YM3526 interface stubs block
491  **********************************************************************************************/
492 
493 /**********************************************************************************************
494 	Begin of Y8950 interface stubs block
495  **********************************************************************************************/
496 #if (HAS_Y8950)
Y8950_sh_start(const struct MachineSound * msound)497 int Y8950_sh_start(const struct MachineSound *msound)
498 {
499 	chiptype = OPL_TYPE_Y8950;
500 	if( OPL_sh_start(msound) ) return 1;
501 	/* !!!!! port handler set !!!!! */
502 	/* !!!!! delta-t memory address set !!!!! */
503 	return 0;
504 }
505 #endif
506 
507 /**********************************************************************************************
508 	End of Y8950 interface stubs block
509  **********************************************************************************************/
510