1 /***************************************************************************
2
3 2608intf.c
4
5 The YM2608 emulator supports up to 2 chips.
6 Each chip has the following connections:
7 - Status Read / Control Write A
8 - Port Read / Data Write A
9 - Control Write B
10 - Data Write B
11
12 ***************************************************************************/
13
14 #include <memory.h> // for memset
15 #include <stdlib.h> // for free
16 #include <stddef.h> // for NULL
17 #include "mamedef.h"
18 //#include "sndintrf.h"
19 //#include "streams.h"
20 #include "2608intf.h"
21 //#include "fm.h"
22
23
24 #ifdef ENABLE_ALL_CORES
25 #define EC_MAME 0x01 // AY8910 core from MAME
26 #endif
27 #define EC_EMU2149 0x00
28
29 typedef struct _ym2608_state ym2608_state;
30 struct _ym2608_state
31 {
32 //sound_stream * stream;
33 //emu_timer * timer[2];
34 void * chip;
35 void * psg;
36 ym2608_interface intf;
37 int AY_EMU_CORE;
38 //const device_config *device;
39 };
40
41 #define CHTYPE_YM2608 0x21
42
43
44 /*INLINE ym2608_state *get_safe_token(const device_config *device)
45 {
46 assert(device != NULL);
47 assert(device->token != NULL);
48 assert(device->type == SOUND);
49 assert(sound_get_type(device) == SOUND_YM2608);
50 return (ym2608_state *)device->token;
51 }*/
52
53
54
psg_set_clock(void * param,int clock)55 static void psg_set_clock(void *param, int clock)
56 {
57 ym2608_state *info = (ym2608_state *)param;
58 if (info->psg != NULL)
59 {
60 switch(info->AY_EMU_CORE)
61 {
62 #ifdef ENABLE_ALL_CORES
63 case EC_MAME:
64 ay8910_set_clock_ym(info->psg, clock);
65 break;
66 #endif
67 case EC_EMU2149:
68 PSG_set_clock((PSG*)info->psg, clock);
69 break;
70 }
71 }
72 }
73
psg_write(void * param,int address,int data)74 static void psg_write(void *param, int address, int data)
75 {
76 ym2608_state *info = (ym2608_state *)param;
77 if (info->psg != NULL)
78 {
79 switch(info->AY_EMU_CORE)
80 {
81 #ifdef ENABLE_ALL_CORES
82 case EC_MAME:
83 ay8910_write_ym(info->psg, address, data);
84 break;
85 #endif
86 case EC_EMU2149:
87 PSG_writeIO((PSG*)info->psg, address, data);
88 break;
89 }
90 }
91 }
92
psg_read(void * param)93 static int psg_read(void *param)
94 {
95 ym2608_state *info = (ym2608_state *)param;
96 if (info->psg != NULL)
97 {
98 switch(info->AY_EMU_CORE)
99 {
100 #ifdef ENABLE_ALL_CORES
101 case EC_MAME:
102 return ay8910_read_ym(info->psg);
103 #endif
104 case EC_EMU2149:
105 return PSG_readIO((PSG*)info->psg);
106 }
107 }
108 return 0x00;
109 }
110
psg_reset(void * param)111 static void psg_reset(void *param)
112 {
113 ym2608_state *info = (ym2608_state *)param;
114 if (info->psg != NULL)
115 {
116 switch(info->AY_EMU_CORE)
117 {
118 #ifdef ENABLE_ALL_CORES
119 case EC_MAME:
120 ay8910_reset_ym(info->psg);
121 break;
122 #endif
123 case EC_EMU2149:
124 PSG_reset((PSG*)info->psg);
125 break;
126 }
127 }
128 }
129
130 static const ssg_callbacks psgintf =
131 {
132 psg_set_clock,
133 psg_write,
134 psg_read,
135 psg_reset
136 };
137
138
139 /* IRQ Handler */
140 /*static void IRQHandler(void *param,int irq)
141 {
142 ym2608_state *info = (ym2608_state *)param;
143 //if(info->intf->handler) info->intf->handler(info->device, irq);
144 if(info->intf.handler) info->intf.handler(irq);
145 }*/
146
147 /* Timer overflow callback from timer.c */
148 /*static TIMER_CALLBACK( timer_callback_2608_0 )
149 {
150 ym2608_state *info = (ym2608_state *)ptr;
151 ym2608_timer_over(info->chip,0);
152 }
153
154 static TIMER_CALLBACK( timer_callback_2608_1 )
155 {
156 ym2608_state *info = (ym2608_state *)ptr;
157 ym2608_timer_over(info->chip,1);
158 }*/
159
160 /*static void timer_handler(void *param,int c,int count,int clock)
161 {
162 ym2608_state *info = (ym2608_state *)param;
163 if( count == 0 )
164 { // Reset FM Timer
165 //timer_enable(info->timer[c], 0);
166 }
167 else
168 { // Start FM Timer
169 //attotime period = attotime_mul(ATTOTIME_IN_HZ(clock), count);
170 //if (!timer_enable(info->timer[c], 1))
171 // timer_adjust_oneshot(info->timer[c], period, 0);
172 }
173 }*/
174
175 static stream_sample_t* DUMMYBUF[0x02] = {NULL, NULL};
176
177 /* update request from fm.c */
ym2608_update_request(void * param)178 void ym2608_update_request(void *param)
179 {
180 ym2608_state *info = (ym2608_state *)param;
181 //stream_update(info->stream);
182
183 ym2608_update_one(info->chip, DUMMYBUF, 0);
184 // Not necessary.
185 //if (info->psg != NULL)
186 // ay8910_update_one(info->psg, DUMMYBUF, 0);
187 }
188
189 //static STREAM_UPDATE( ym2608_stream_update )
ym2608_stream_update(void * _info,stream_sample_t ** outputs,int samples)190 void ym2608_stream_update(void *_info, stream_sample_t **outputs, int samples)
191 {
192 //ym2608_state *info = (ym2608_state *)param;
193 ym2608_state *info = (ym2608_state *)_info;
194 ym2608_update_one(info->chip, outputs, samples);
195 }
196
ym2608_stream_update_ay(void * _info,stream_sample_t ** outputs,int samples)197 void ym2608_stream_update_ay(void *_info, stream_sample_t **outputs, int samples)
198 {
199 //ym2608_state *info = (ym2608_state *)param;
200 ym2608_state *info = (ym2608_state *)_info;
201
202 if (info->psg != NULL)
203 {
204 switch(info->AY_EMU_CORE)
205 {
206 #ifdef ENABLE_ALL_CORES
207 case EC_MAME:
208 ay8910_update_one(info->psg, outputs, samples);
209 break;
210 #endif
211 case EC_EMU2149:
212 PSG_calc_stereo((PSG*)info->psg, outputs, samples);
213 break;
214 }
215 }
216 else
217 {
218 memset(outputs[0], 0x00, samples * sizeof(stream_sample_t));
219 memset(outputs[1], 0x00, samples * sizeof(stream_sample_t));
220 }
221 }
222
223
224 //static STATE_POSTLOAD( ym2608_intf_postload )
225 /*static void ym2608_intf_postload(UINT8 ChipID)
226 {
227 //ym2608_state *info = (ym2608_state *)param;
228 ym2608_state *info = &YM2608Data[ChipID];
229 ym2608_postload(info->chip);
230 }*/
231
232
233 //static DEVICE_START( ym2608 )
device_start_ym2608(void ** _info,int AY_EMU_CORE,int clock,UINT8 AYDisable,UINT8 AYFlags,int * AYrate,int CHIP_SAMPLING_MODE,int CHIP_SAMPLE_RATE)234 int device_start_ym2608(void **_info, int AY_EMU_CORE, int clock, UINT8 AYDisable, UINT8 AYFlags, int* AYrate, int CHIP_SAMPLING_MODE, int CHIP_SAMPLE_RATE)
235 {
236 static const ym2608_interface generic_2608 =
237 {
238 {
239 AY8910_LEGACY_OUTPUT | AY8910_SINGLE_OUTPUT,
240 AY8910_DEFAULT_LOADS
241 //DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL
242 },
243 NULL
244 };
245 //const ym2608_interface *intf = device->static_config ? (const ym2608_interface *)device->static_config : &generic_2608;
246 ym2608_interface *intf;
247 int rate;
248 int ay_clock;
249 //void *pcmbufa;
250 //int pcmsizea;
251
252 #ifdef ENABLE_ALL_CORES
253 if (AY_EMU_CORE >= 0x02)
254 AY_EMU_CORE = EC_EMU2149;
255 #else
256 AY_EMU_CORE = EC_EMU2149;
257 #endif
258
259 //ym2608_state *info = get_safe_token(device);
260 ym2608_state *info;
261
262 info = (ym2608_state *) calloc(1, sizeof(ym2608_state));
263 *_info = (void *) info;
264
265 info->AY_EMU_CORE = AY_EMU_CORE;
266 rate = clock/72;
267 if ((CHIP_SAMPLING_MODE == 0x01 && rate < CHIP_SAMPLE_RATE) ||
268 CHIP_SAMPLING_MODE == 0x02)
269 rate = CHIP_SAMPLE_RATE;
270 info->intf = generic_2608;
271 intf = &info->intf;
272 if (AYFlags)
273 intf->ay8910_intf.flags = AYFlags;
274 //info->device = device;
275
276 /* FIXME: Force to use single output */
277 //info->psg = ay8910_start_ym(NULL, SOUND_YM2608, clock, &intf->ay8910_intf);
278 if (! AYDisable)
279 {
280 ay_clock = clock / 4;
281 *AYrate = ay_clock / 8;
282 switch(AY_EMU_CORE)
283 {
284 #ifdef ENABLE_ALL_CORES
285 case EC_MAME:
286 info->psg = ay8910_start_ym(NULL, CHTYPE_YM2608, ay_clock, &intf->ay8910_intf);
287 break;
288 #endif
289 case EC_EMU2149:
290 info->psg = PSG_new(ay_clock, *AYrate);
291 if (info->psg == NULL)
292 return 0;
293 PSG_setVolumeMode((PSG*)info->psg, 1); // YM2149 volume mode
294 break;
295 }
296 }
297 else
298 {
299 info->psg = NULL;
300 *AYrate = 0;
301 }
302 //assert_always(info->psg != NULL, "Error creating YM2608/AY8910 chip");
303
304 /* Timer Handler set */
305 //info->timer[0] = timer_alloc(device->machine, timer_callback_2608_0, info);
306 //info->timer[1] = timer_alloc(device->machine, timer_callback_2608_1, info);
307
308 /* stream system initialize */
309 //info->stream = stream_create(device,0,2,rate,info,ym2608_stream_update);
310 /* setup adpcm buffers */
311 //pcmbufa = device->region;
312 //pcmsizea = device->regionbytes;
313
314 /* initialize YM2608 */
315 //info->chip = ym2608_init(info,device,device->clock,rate,
316 // pcmbufa,pcmsizea,
317 // timer_handler,IRQHandler,&psgintf);
318 info->chip = ym2608_init(info, clock, rate, NULL, NULL, &psgintf);
319 //assert_always(info->chip != NULL, "Error creating YM2608 chip");
320
321 //state_save_register_postload(device->machine, ym2608_intf_postload, info);
322
323 return rate;
324 }
325
326 //static DEVICE_STOP( ym2608 )
device_stop_ym2608(void * _info)327 void device_stop_ym2608(void *_info)
328 {
329 //ym2608_state *info = get_safe_token(device);
330 ym2608_state *info = (ym2608_state *)_info;
331 ym2608_shutdown(info->chip);
332 if (info->psg != NULL)
333 {
334 switch(info->AY_EMU_CORE)
335 {
336 #ifdef ENABLE_ALL_CORES
337 case EC_MAME:
338 ay8910_stop_ym(info->psg);
339 break;
340 #endif
341 case EC_EMU2149:
342 PSG_delete((PSG*)info->psg);
343 break;
344 }
345 info->psg = NULL;
346 }
347 free(info);
348 }
349
350 //static DEVICE_RESET( ym2608 )
device_reset_ym2608(void * _info)351 void device_reset_ym2608(void *_info)
352 {
353 //ym2608_state *info = get_safe_token(device);
354 ym2608_state *info = (ym2608_state *)_info;
355 ym2608_reset_chip(info->chip); // also resets the AY clock
356 //psg_reset(info); // already done as a callback in ym2608_reset_chip
357 }
358
359
360 //READ8_DEVICE_HANDLER( ym2608_r )
ym2608_r(void * _info,offs_t offset)361 UINT8 ym2608_r(void *_info, offs_t offset)
362 {
363 //ym2608_state *info = get_safe_token(device);
364 ym2608_state *info = (ym2608_state *)_info;
365 return ym2608_read(info->chip, offset & 3);
366 }
367
368 //WRITE8_DEVICE_HANDLER( ym2608_w )
ym2608_w(void * _info,offs_t offset,UINT8 data)369 void ym2608_w(void *_info, offs_t offset, UINT8 data)
370 {
371 //ym2608_state *info = get_safe_token(device);
372 ym2608_state *info = (ym2608_state *)_info;
373 ym2608_write(info->chip, offset & 3, data);
374 }
375
376 //READ8_DEVICE_HANDLER( ym2608_read_port_r )
ym2608_read_port_r(void * info,offs_t offset)377 UINT8 ym2608_read_port_r(void *info, offs_t offset)
378 {
379 return ym2608_r(info, 1);
380 }
381 //READ8_DEVICE_HANDLER( ym2608_status_port_a_r )
ym2608_status_port_a_r(void * info,offs_t offset)382 UINT8 ym2608_status_port_a_r(void *info, offs_t offset)
383 {
384 return ym2608_r(info, 0);
385 }
386 //READ8_DEVICE_HANDLER( ym2608_status_port_b_r )
ym2608_status_port_b_r(void * info,offs_t offset)387 UINT8 ym2608_status_port_b_r(void *info, offs_t offset)
388 {
389 return ym2608_r(info, 2);
390 }
391
392 //WRITE8_DEVICE_HANDLER( ym2608_control_port_a_w )
ym2608_control_port_a_w(void * info,offs_t offset,UINT8 data)393 void ym2608_control_port_a_w(void *info, offs_t offset, UINT8 data)
394 {
395 ym2608_w(info, 0, data);
396 }
397 //WRITE8_DEVICE_HANDLER( ym2608_control_port_b_w )
ym2608_control_port_b_w(void * info,offs_t offset,UINT8 data)398 void ym2608_control_port_b_w(void *info, offs_t offset, UINT8 data)
399 {
400 ym2608_w(info, 2, data);
401 }
402 //WRITE8_DEVICE_HANDLER( ym2608_data_port_a_w )
ym2608_data_port_a_w(void * info,offs_t offset,UINT8 data)403 void ym2608_data_port_a_w(void *info, offs_t offset, UINT8 data)
404 {
405 ym2608_w(info, 1, data);
406 }
407 //WRITE8_DEVICE_HANDLER( ym2608_data_port_b_w )
ym2608_data_port_b_w(void * info,offs_t offset,UINT8 data)408 void ym2608_data_port_b_w(void *info, offs_t offset, UINT8 data)
409 {
410 ym2608_w(info, 3, data);
411 }
412
413
ym2608_write_data_pcmrom(void * _info,UINT8 rom_id,offs_t ROMSize,offs_t DataStart,offs_t DataLength,const UINT8 * ROMData)414 void ym2608_write_data_pcmrom(void *_info, UINT8 rom_id, offs_t ROMSize, offs_t DataStart,
415 offs_t DataLength, const UINT8* ROMData)
416 {
417 ym2608_state* info = (ym2608_state *)_info;
418 ym2608_write_pcmrom(info->chip, rom_id, ROMSize, DataStart, DataLength, ROMData);
419 }
420
ym2608_set_mute_mask(void * _info,UINT32 MuteMaskFM,UINT32 MuteMaskAY)421 void ym2608_set_mute_mask(void *_info, UINT32 MuteMaskFM, UINT32 MuteMaskAY)
422 {
423 ym2608_state* info = (ym2608_state *)_info;
424 ym2608_set_mutemask(info->chip, MuteMaskFM);
425 if (info->psg != NULL)
426 {
427 switch(info->AY_EMU_CORE)
428 {
429 #ifdef ENABLE_ALL_CORES
430 case EC_MAME:
431 ay8910_set_mute_mask_ym(info->psg, MuteMaskAY);
432 break;
433 #endif
434 case EC_EMU2149:
435 PSG_setMask((PSG*)info->psg, MuteMaskAY);
436 break;
437 }
438 }
439 }
440
ym2608_set_srchg_cb(void * _info,SRATE_CALLBACK CallbackFunc,void * DataPtr,void * AYDataPtr)441 void ym2608_set_srchg_cb(void *_info, SRATE_CALLBACK CallbackFunc, void* DataPtr, void* AYDataPtr)
442 {
443 ym2608_state* info = (ym2608_state *)_info;
444
445 if (info->psg != NULL)
446 {
447 switch(info->AY_EMU_CORE)
448 {
449 #ifdef ENABLE_ALL_CORES
450 case EC_MAME:
451 ay8910_set_srchg_cb_ym(info->psg, CallbackFunc, AYDataPtr);
452 break;
453 #endif
454 case EC_EMU2149:
455 break;
456 }
457 }
458
459 return;
460 }
461
462
463 /**************************************************************************
464 * Generic get_info
465 **************************************************************************/
466
467 /*DEVICE_GET_INFO( ym2608 )
468 {
469 switch (state)
470 {
471 // --- the following bits of info are returned as 64-bit signed integers ---
472 case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(ym2608_state); break;
473
474 // --- the following bits of info are returned as pointers to data or functions ---
475 case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( ym2608 ); break;
476 case DEVINFO_FCT_STOP: info->stop = DEVICE_STOP_NAME( ym2608 ); break;
477 case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( ym2608 ); break;
478
479 // --- the following bits of info are returned as NULL-terminated strings ---
480 case DEVINFO_STR_NAME: strcpy(info->s, "YM2608"); break;
481 case DEVINFO_STR_FAMILY: strcpy(info->s, "Yamaha FM"); break;
482 case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
483 case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
484 case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
485 }
486 }*/
487