1 /***************************************************************************
2
3 2610intf.c
4
5 The YM2610 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 "2610intf.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 _ym2610_state ym2610_state;
30 struct _ym2610_state
31 {
32 //sound_stream * stream;
33 //emu_timer * timer[2];
34 void * chip;
35 void * psg;
36 int AY_EMU_CORE;
37 //const ym2610_interface *intf;
38 //const device_config *device;
39 };
40
41 #define CHTYPE_YM2610 0x22
42
43
44 /*INLINE ym2610_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_YM2610 || sound_get_type(device) == SOUND_YM2610B);
50 return (ym2610_state *)device->token;
51 }*/
52
53
psg_set_clock(void * param,int clock)54 static void psg_set_clock(void *param, int clock)
55 {
56 ym2610_state *info = (ym2610_state *)param;
57 if (info->psg != NULL)
58 {
59 switch(info->AY_EMU_CORE)
60 {
61 #ifdef ENABLE_ALL_CORES
62 case EC_MAME:
63 ay8910_set_clock_ym(info->psg, clock);
64 break;
65 #endif
66 case EC_EMU2149:
67 PSG_set_clock((PSG*)info->psg, clock);
68 break;
69 }
70 }
71 }
72
psg_write(void * param,int address,int data)73 static void psg_write(void *param, int address, int data)
74 {
75 ym2610_state *info = (ym2610_state *)param;
76 if (info->psg != NULL)
77 {
78 switch(info->AY_EMU_CORE)
79 {
80 #ifdef ENABLE_ALL_CORES
81 case EC_MAME:
82 ay8910_write_ym(info->psg, address, data);
83 break;
84 #endif
85 case EC_EMU2149:
86 PSG_writeIO((PSG*)info->psg, address, data);
87 break;
88 }
89 }
90 }
91
psg_read(void * param)92 static int psg_read(void *param)
93 {
94 ym2610_state *info = (ym2610_state *)param;
95 if (info->psg != NULL)
96 {
97 switch(info->AY_EMU_CORE)
98 {
99 #ifdef ENABLE_ALL_CORES
100 case EC_MAME:
101 return ay8910_read_ym(info->psg);
102 #endif
103 case EC_EMU2149:
104 return PSG_readIO((PSG*)info->psg);
105 }
106 }
107 return 0x00;
108 }
109
psg_reset(void * param)110 static void psg_reset(void *param)
111 {
112 ym2610_state *info = (ym2610_state *)param;
113 if (info->psg != NULL)
114 {
115 switch(info->AY_EMU_CORE)
116 {
117 #ifdef ENABLE_ALL_CORES
118 case EC_MAME:
119 ay8910_reset_ym(info->psg);
120 break;
121 #endif
122 case EC_EMU2149:
123 PSG_reset((PSG*)info->psg);
124 break;
125 }
126 }
127 }
128
129 static const ssg_callbacks psgintf =
130 {
131 psg_set_clock,
132 psg_write,
133 psg_read,
134 psg_reset
135 };
136
137 /*------------------------- TM2610 -------------------------------*/
138 /* IRQ Handler */
139 /*static void IRQHandler(void *param,int irq)
140 {
141 ym2610_state *info = (ym2610_state *)param;
142 //if(info->intf->handler) info->intf->handler(info->device, irq);
143 //if(info->intf->handler) info->intf->handler(irq);
144 }*/
145
146 /* Timer overflow callback from timer.c */
147 /*static TIMER_CALLBACK( timer_callback_0 )
148 {
149 ym2610_state *info = (ym2610_state *)ptr;
150 ym2610_timer_over(info->chip,0);
151 }
152
153 static TIMER_CALLBACK( timer_callback_1 )
154 {
155 ym2610_state *info = (ym2610_state *)ptr;
156 ym2610_timer_over(info->chip,1);
157 }*/
158
159 /*static void timer_handler(void *param,int c,int count,int clock)
160 {
161 ym2610_state *info = (ym2610_state *)param;
162 if( count == 0 )
163 { // Reset FM Timer
164 //timer_enable(info->timer[c], 0);
165 }
166 else
167 { // Start FM Timer
168 //attotime period = attotime_mul(ATTOTIME_IN_HZ(clock), count);
169
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 */
ym2610_update_request(void * param)178 void ym2610_update_request(void *param)
179 {
180 ym2610_state *info = (ym2610_state *)param;
181 //stream_update(info->stream);
182
183 ym2610b_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
190 //static STREAM_UPDATE( ym2610_stream_update )
ym2610_stream_update(void * param,stream_sample_t ** outputs,int samples)191 void ym2610_stream_update(void *param, stream_sample_t **outputs, int samples)
192 {
193 ym2610_state *info = (ym2610_state *)param;
194 ym2610_update_one(info->chip, outputs, samples);
195 }
196
197 //static STREAM_UPDATE( ym2610b_stream_update )
ym2610b_stream_update(void * param,stream_sample_t ** outputs,int samples)198 void ym2610b_stream_update(void *param, stream_sample_t **outputs, int samples)
199 {
200 ym2610_state *info = (ym2610_state *)param;
201 ym2610b_update_one(info->chip, outputs, samples);
202 }
203
ym2610_stream_update_ay(void * param,stream_sample_t ** outputs,int samples)204 void ym2610_stream_update_ay(void *param, stream_sample_t **outputs, int samples)
205 {
206 ym2610_state *info = (ym2610_state *)param;
207
208 if (info->psg != NULL)
209 {
210 switch(info->AY_EMU_CORE)
211 {
212 #ifdef ENABLE_ALL_CORES
213 case EC_MAME:
214 ay8910_update_one(info->psg, outputs, samples);
215 break;
216 #endif
217 case EC_EMU2149:
218 PSG_calc_stereo((PSG*)info->psg, outputs, samples);
219 break;
220 }
221 }
222 else
223 {
224 memset(outputs[0], 0x00, samples * sizeof(stream_sample_t));
225 memset(outputs[1], 0x00, samples * sizeof(stream_sample_t));
226 }
227 }
228
229
230 //static STATE_POSTLOAD( ym2610_intf_postload )
231 /*static void ym2610_intf_postload(UINT8 ChipID)
232 {
233 //ym2610_state *info = (ym2610_state *)param;
234 ym2610_state *info = &YM2610Data[ChipID];
235 ym2610_postload(info->chip);
236 }*/
237
238
239 //static DEVICE_START( ym2610 )
device_start_ym2610(void ** _info,int AY_EMU_CORE,int clock,UINT8 AYDisable,int * AYrate,int CHIP_SAMPLING_MODE,int CHIP_SAMPLE_RATE)240 int device_start_ym2610(void **_info, int AY_EMU_CORE, int clock, UINT8 AYDisable, int* AYrate, int CHIP_SAMPLING_MODE, int CHIP_SAMPLE_RATE)
241 {
242 // clock bit 31: 0 - YM2610
243 // 1 - YM2610B
244
245 //static const ym2610_interface generic_2610 = { 0 };
246 static const ay8910_interface generic_ay8910 =
247 {
248 AY8910_LEGACY_OUTPUT | AY8910_SINGLE_OUTPUT,
249 AY8910_DEFAULT_LOADS
250 //DEVCB_NULL, DEVCB_NULL, DEVCB_NULL, DEVCB_NULL
251 };
252 //const ym2610_interface *intf = device->static_config ? (const ym2610_interface *)device->static_config : &generic_2610;
253 //const ym2610_interface *intf = &generic_2610;
254 int rate;
255 int ay_clock;
256 //void *pcmbufa,*pcmbufb;
257 //int pcmsizea,pcmsizeb;
258 //ym2610_state *info = get_safe_token(device);
259 ym2610_state *info;
260 //astring *name = astring_alloc();
261 //sound_type type = sound_get_type(device);
262 unsigned char ChipType;
263
264 #ifdef ENABLE_ALL_CORES
265 if (AY_EMU_CORE >= 0x02)
266 AY_EMU_CORE = EC_EMU2149;
267 #else
268 AY_EMU_CORE = EC_EMU2149;
269 #endif
270
271 info = (ym2610_state *) calloc(1, sizeof(ym2610_state));
272 *_info = (void *) info;
273
274 info->AY_EMU_CORE = AY_EMU_CORE;
275 ChipType = (clock & 0x80000000) ? 0x01 : 0x00;
276 clock &= 0x7FFFFFFF;
277 rate = clock/72;
278 if ((CHIP_SAMPLING_MODE == 0x01 && rate < CHIP_SAMPLE_RATE) ||
279 CHIP_SAMPLING_MODE == 0x02)
280 rate = CHIP_SAMPLE_RATE;
281 //info->intf = intf;
282 //info->device = device;
283 //info->psg = ay8910_start_ym(NULL, sound_get_type(device), device, device->clock, &generic_ay8910);
284 if (! AYDisable)
285 {
286 ay_clock = clock / 4;
287 *AYrate = ay_clock / 8;
288 switch(AY_EMU_CORE)
289 {
290 #ifdef ENABLE_ALL_CORES
291 case EC_MAME:
292 info->psg = ay8910_start_ym(NULL, CHTYPE_YM2610 + ChipType, ay_clock, &generic_ay8910);
293 break;
294 #endif
295 case EC_EMU2149:
296 info->psg = PSG_new(ay_clock, *AYrate);
297 if (info->psg == NULL)
298 return 0;
299 PSG_setVolumeMode((PSG*)info->psg, 1); // YM2149 volume mode
300 break;
301 }
302 }
303 else
304 {
305 info->psg = NULL;
306 *AYrate = 0;
307 }
308 //assert_always(info->psg != NULL, "Error creating YM2610/AY8910 chip");
309
310 /* Timer Handler set */
311 //info->timer[0] = timer_alloc(device->machine, timer_callback_0, info);
312 //info->timer[1] = timer_alloc(device->machine, timer_callback_1, info);
313
314 /* stream system initialize */
315 //info->stream = stream_create(device,0,2,rate,info,(type == SOUND_YM2610) ? ym2610_stream_update : ym2610b_stream_update);
316 /* setup adpcm buffers */
317 //pcmbufa = device->region;
318 //pcmsizea = device->regionbytes;
319 //astring_printf(name, "%s.deltat", device->tag);
320 //pcmbufb = (void *)(memory_region(device->machine, astring_c(name)));
321 //pcmsizeb = memory_region_length(device->machine, astring_c(name));
322 //astring_free(name);
323 /*if (pcmbufb == NULL || pcmsizeb == 0)
324 {
325 pcmbufb = pcmbufa;
326 pcmsizeb = pcmsizea;
327 }*/
328
329 /**** initialize YM2610 ****/
330 //info->chip = ym2610_init(info,device,device->clock,rate,
331 // pcmbufa,pcmsizea,pcmbufb,pcmsizeb,
332 // timer_handler,IRQHandler,&psgintf);
333 info->chip = ym2610_init(info, clock & 0x7FFFFFFF, rate, NULL, NULL, &psgintf);
334 //assert_always(info->chip != NULL, "Error creating YM2610 chip");
335
336 //state_save_register_postload(device->machine, ym2610_intf_postload, info);
337
338 return rate;
339 }
340
341 //static DEVICE_STOP( ym2610 )
device_stop_ym2610(void * _info)342 void device_stop_ym2610(void *_info)
343 {
344 //ym2610_state *info = get_safe_token(device);
345 ym2610_state* info = (ym2610_state *)_info;
346 ym2610_shutdown(info->chip);
347 if (info->psg != NULL)
348 {
349 switch(info->AY_EMU_CORE)
350 {
351 #ifdef ENABLE_ALL_CORES
352 case EC_MAME:
353 ay8910_stop_ym(info->psg);
354 break;
355 #endif
356 case EC_EMU2149:
357 PSG_delete((PSG*)info->psg);
358 break;
359 }
360 info->psg = NULL;
361 }
362 free(info);
363 }
364
365 //static DEVICE_RESET( ym2610 )
device_reset_ym2610(void * _info)366 void device_reset_ym2610(void *_info)
367 {
368 //ym2610_state *info = get_safe_token(device);
369 ym2610_state* info = (ym2610_state *)_info;
370 ym2610_reset_chip(info->chip); // also resets the AY clock
371 //psg_reset(info); // already done as a callback in ym2610_reset_chip
372 }
373
374
375 //READ8_DEVICE_HANDLER( ym2610_r )
ym2610_r(void * _info,offs_t offset)376 UINT8 ym2610_r(void *_info, offs_t offset)
377 {
378 //ym2610_state *info = get_safe_token(device);
379 ym2610_state* info = (ym2610_state *)_info;
380 return ym2610_read(info->chip, offset & 3);
381 }
382
383 //WRITE8_DEVICE_HANDLER( ym2610_w )
ym2610_w(void * _info,offs_t offset,UINT8 data)384 void ym2610_w(void *_info, offs_t offset, UINT8 data)
385 {
386 //ym2610_state *info = get_safe_token(device);
387 ym2610_state* info = (ym2610_state *)_info;
388 ym2610_write(info->chip, offset & 3, data);
389 }
390
391
392 //READ8_DEVICE_HANDLER( ym2610_status_port_a_r )
ym2610_status_port_a_r(void * info,offs_t offset)393 UINT8 ym2610_status_port_a_r(void *info, offs_t offset)
394 {
395 return ym2610_r(info, 0);
396 }
397 //READ8_DEVICE_HANDLER( ym2610_status_port_b_r )
ym2610_status_port_b_r(void * info,offs_t offset)398 UINT8 ym2610_status_port_b_r(void *info, offs_t offset)
399 {
400 return ym2610_r(info, 2);
401 }
402 //READ8_DEVICE_HANDLER( ym2610_read_port_r )
ym2610_read_port_r(void * info,offs_t offset)403 UINT8 ym2610_read_port_r(void *info, offs_t offset)
404 {
405 return ym2610_r(info, 1);
406 }
407
408 //WRITE8_DEVICE_HANDLER( ym2610_control_port_a_w )
ym2610_control_port_a_w(void * info,offs_t offset,UINT8 data)409 void ym2610_control_port_a_w(void *info, offs_t offset, UINT8 data)
410 {
411 ym2610_w(info, 0, data);
412 }
413 //WRITE8_DEVICE_HANDLER( ym2610_control_port_b_w )
ym2610_control_port_b_w(void * info,offs_t offset,UINT8 data)414 void ym2610_control_port_b_w(void *info, offs_t offset, UINT8 data)
415 {
416 ym2610_w(info, 2, data);
417 }
418 //WRITE8_DEVICE_HANDLER( ym2610_data_port_a_w )
ym2610_data_port_a_w(void * info,offs_t offset,UINT8 data)419 void ym2610_data_port_a_w(void *info, offs_t offset, UINT8 data)
420 {
421 ym2610_w(info, 1, data);
422 }
423 //WRITE8_DEVICE_HANDLER( ym2610_data_port_b_w )
ym2610_data_port_b_w(void * info,offs_t offset,UINT8 data)424 void ym2610_data_port_b_w(void *info, offs_t offset, UINT8 data)
425 {
426 ym2610_w(info, 3, data);
427 }
428
429
ym2610_write_data_pcmrom(void * _info,UINT8 rom_id,offs_t ROMSize,offs_t DataStart,offs_t DataLength,const UINT8 * ROMData)430 void ym2610_write_data_pcmrom(void *_info, UINT8 rom_id, offs_t ROMSize, offs_t DataStart,
431 offs_t DataLength, const UINT8* ROMData)
432 {
433 ym2610_state* info = (ym2610_state *)_info;
434 ym2610_write_pcmrom(info->chip, rom_id, ROMSize, DataStart, DataLength, ROMData);
435 }
436
ym2610_set_mute_mask(void * _info,UINT32 MuteMaskFM,UINT32 MuteMaskAY)437 void ym2610_set_mute_mask(void *_info, UINT32 MuteMaskFM, UINT32 MuteMaskAY)
438 {
439 ym2610_state* info = (ym2610_state *)_info;
440 ym2610_set_mutemask(info->chip, MuteMaskFM);
441 if (info->psg != NULL)
442 {
443 switch(info->AY_EMU_CORE)
444 {
445 #ifdef ENABLE_ALL_CORES
446 case EC_MAME:
447 ay8910_set_mute_mask_ym(info->psg, MuteMaskAY);
448 break;
449 #endif
450 case EC_EMU2149:
451 PSG_setMask((PSG*)info->psg, MuteMaskAY);
452 break;
453 }
454 }
455 }
456
457
458 /**************************************************************************
459 * Generic get_info
460 **************************************************************************/
461
462 /*DEVICE_GET_INFO( ym2610 )
463 {
464 switch (state)
465 {
466 // --- the following bits of info are returned as 64-bit signed integers ---
467 case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(ym2610_state); break;
468
469 // --- the following bits of info are returned as pointers to data or functions ---
470 case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( ym2610 ); break;
471 case DEVINFO_FCT_STOP: info->stop = DEVICE_STOP_NAME( ym2610 ); break;
472 case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( ym2610 ); break;
473
474 // --- the following bits of info are returned as NULL-terminated strings ---
475 case DEVINFO_STR_NAME: strcpy(info->s, "YM2610"); break;
476 case DEVINFO_STR_FAMILY: strcpy(info->s, "Yamaha FM"); break;
477 case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
478 case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
479 case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
480 }
481 }*/
482
483 /*DEVICE_GET_INFO( ym2610b )
484 {
485 switch (state)
486 {
487 // --- the following bits of info are returned as NULL-terminated strings ---
488 case DEVINFO_STR_NAME: strcpy(info->s, "YM2610B"); break;
489
490 default: DEVICE_GET_INFO_CALL(ym2610); break;
491 }
492 }*/
493