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