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