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 "sndintrf.h"
15 #include "streams.h"
16 #include "ay8910.h"
17 #include "2608intf.h"
18 #include "fm.h"
19 
20 #ifdef BUILD_YM2608
21 
22 struct ym2608_info
23 {
24 	sound_stream *	stream;
25 	mame_timer *	timer[2];
26 	void *			chip;
27 	void *			psg;
28 	const struct YM2608interface *intf;
29 };
30 
31 
32 
psg_set_clock(void * param,int clock)33 static void psg_set_clock(void *param, int clock)
34 {
35 	struct ym2608_info *info = param;
36 	ay8910_set_clock_ym(info->psg, clock);
37 }
38 
psg_write(void * param,int address,int data)39 static void psg_write(void *param, int address, int data)
40 {
41 	struct ym2608_info *info = param;
42 	ay8910_write_ym(info->psg, address, data);
43 }
44 
psg_read(void * param)45 static int psg_read(void *param)
46 {
47 	struct ym2608_info *info = param;
48 	return ay8910_read_ym(info->psg);
49 }
50 
psg_reset(void * param)51 static void psg_reset(void *param)
52 {
53 	struct ym2608_info *info = param;
54 	ay8910_reset_ym(info->psg);
55 }
56 
57 static const struct ssg_callbacks psgintf =
58 {
59 	psg_set_clock,
60 	psg_write,
61 	psg_read,
62 	psg_reset
63 };
64 
65 
66 /* IRQ Handler */
IRQHandler(void * param,int irq)67 static void IRQHandler(void *param,int irq)
68 {
69 	struct ym2608_info *info = param;
70 	if(info->intf->handler) info->intf->handler(irq);
71 }
72 
73 /* Timer overflow callback from timer.c */
timer_callback_2608_0(void * param)74 static void timer_callback_2608_0(void *param)
75 {
76 	struct ym2608_info *info = param;
77 	YM2608TimerOver(info->chip,0);
78 }
79 
timer_callback_2608_1(void * param)80 static void timer_callback_2608_1(void *param)
81 {
82 	struct ym2608_info *info = param;
83 	YM2608TimerOver(info->chip,1);
84 }
85 
86 /* TimerHandler from fm.c */
TimerHandler(void * param,int c,int count,double stepTime)87 static void TimerHandler(void *param,int c,int count,double stepTime)
88 {
89 	struct ym2608_info *info = param;
90 	if( count == 0 )
91 	{	/* Reset FM Timer */
92 		timer_enable(info->timer[c], 0);
93 	}
94 	else
95 	{	/* Start FM Timer */
96 		double timeSec = (double)count * stepTime;
97 		if (!timer_enable(info->timer[c], 1))
98 			timer_adjust_ptr(info->timer[c], timeSec, 0);
99 	}
100 }
101 
102 /* update request from fm.c */
YM2608UpdateRequest(void * param)103 void YM2608UpdateRequest(void *param)
104 {
105 	struct ym2608_info *info = param;
106 	stream_update(info->stream);
107 }
108 
ym2608_stream_update(void * param,stream_sample_t ** inputs,stream_sample_t ** buffers,int length)109 static void ym2608_stream_update(void *param, stream_sample_t **inputs, stream_sample_t **buffers, int length)
110 {
111 	struct ym2608_info *info = param;
112 	YM2608UpdateOne(info->chip, buffers, length);
113 }
114 
115 
116 #if 0		/* QUASI88 */
117 static void ym2608_postload(void *param)
118 {
119 	struct ym2608_info *info = param;
120 	YM2608Postload(info->chip);
121 }
122 #endif		/* QUASI88 */
123 
124 
ym2608_start(int sndindex,int clock,const void * config)125 static void *ym2608_start(int sndindex, int clock, const void *config)
126 {
127 	static const struct YM2608interface generic_2608 = { 0 };
128 	const struct YM2608interface *intf = config ? config : &generic_2608;
129 	int rate = Machine->sample_rate;
130 	void *pcmbufa;
131 	int  pcmsizea;
132 
133 	struct ym2608_info *info;
134 
135 	info = auto_malloc(sizeof(*info));
136 	memset(info, 0, sizeof(*info));
137 
138 	info->intf = intf;
139 	info->psg = ay8910_start_ym(SOUND_YM2608, sndindex, clock, 1, intf->portAread, intf->portBread, intf->portAwrite, intf->portBwrite);
140 	if (!info->psg) return NULL;
141 
142 	/* Timer Handler set */
143 	info->timer[0] =timer_alloc_ptr(timer_callback_2608_0, info);
144 	info->timer[1] =timer_alloc_ptr(timer_callback_2608_1, info);
145 
146 	/* stream system initialize */
147 	info->stream = stream_create(0,2,rate,info,ym2608_stream_update);
148 	/* setup adpcm buffers */
149 #if 0		/* QUASI88 */
150 	pcmbufa  = (void *)(memory_region(info->intf->pcmrom));
151 	pcmsizea = memory_region_length(info->intf->pcmrom);
152 #else		/* QUASI88 */
153 	if( sound2_adpcm==NULL ){
154 	  sound2_adpcm = (byte *)malloc( 256 * 1024 * sizeof(char) );
155 	}
156 	pcmbufa  = sound2_adpcm;
157 	pcmsizea = 256 * 1024;
158 #endif		/* QUASI88 */
159 
160 	/* initialize YM2608 */
161 #if 0		/* QUASI88 */
162 	info->chip = YM2608Init(info,sndindex,clock,rate,
163 		           pcmbufa,pcmsizea,
164 		           TimerHandler,IRQHandler,&psgintf);
165 #else		/* QUASI88 */
166 	info->chip = YM2608Init(info,sndindex,clock,rate,
167 		           pcmbufa,pcmsizea,
168 		           0,0,&psgintf);
169 #endif		/* QUASI88 */
170 
171 	state_save_register_func_postload_ptr(ym2608_postload, info);
172 
173 	if (info->chip)
174 		return info;
175 
176 	/* error */
177 	return NULL;
178 }
179 
ym2608_stop(void * token)180 static void ym2608_stop(void *token)
181 {
182 	struct ym2608_info *info = token;
183 	YM2608Shutdown(info->chip);
184 	ay8910_stop_ym(info->psg);
185 }
186 
ym2608_reset(void * token)187 static void ym2608_reset(void *token)
188 {
189 	struct ym2608_info *info = token;
190 	YM2608ResetChip(info->chip);
191 }
192 
193 /************************************************/
194 /* Status Read for YM2608 - Chip 0              */
195 /************************************************/
READ8_HANDLER(YM2608_status_port_0_A_r)196 READ8_HANDLER( YM2608_status_port_0_A_r )
197 {
198 /*logerror("PC %04x: 2608 S0A=%02X\n",activecpu_get_pc(),YM2608Read(sndti_token(SOUND_YM2608, 0),0)); */
199 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
200 	return YM2608Read(info->chip,0);
201 }
202 
READ8_HANDLER(YM2608_status_port_0_B_r)203 READ8_HANDLER( YM2608_status_port_0_B_r )
204 {
205 /*logerror("PC %04x: 2608 S0B=%02X\n",activecpu_get_pc(),YM2608Read(sndti_token(SOUND_YM2608, 0),2)); */
206 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
207 	return YM2608Read(info->chip,2);
208 }
209 
210 /************************************************/
211 /* Status Read for YM2608 - Chip 1              */
212 /************************************************/
READ8_HANDLER(YM2608_status_port_1_A_r)213 READ8_HANDLER( YM2608_status_port_1_A_r ) {
214 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
215 	return YM2608Read(info->chip,0);
216 }
217 
READ8_HANDLER(YM2608_status_port_1_B_r)218 READ8_HANDLER( YM2608_status_port_1_B_r ) {
219 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
220 	return YM2608Read(info->chip,2);
221 }
222 
223 /************************************************/
224 /* Port Read for YM2608 - Chip 0                */
225 /************************************************/
READ8_HANDLER(YM2608_read_port_0_r)226 READ8_HANDLER( YM2608_read_port_0_r ){
227 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
228 	return YM2608Read(info->chip,1);
229 }
230 
231 /************************************************/
232 /* Port Read for YM2608 - Chip 1                */
233 /************************************************/
READ8_HANDLER(YM2608_read_port_1_r)234 READ8_HANDLER( YM2608_read_port_1_r ){
235 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
236 	return YM2608Read(info->chip,1);
237 }
238 
239 /************************************************/
240 /* Control Write for YM2608 - Chip 0            */
241 /* Consists of 2 addresses                      */
242 /************************************************/
WRITE8_HANDLER(YM2608_control_port_0_A_w)243 WRITE8_HANDLER( YM2608_control_port_0_A_w )
244 {
245 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
246 	YM2608Write(info->chip,0,data);
247 }
248 
WRITE8_HANDLER(YM2608_control_port_0_B_w)249 WRITE8_HANDLER( YM2608_control_port_0_B_w )
250 {
251 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
252 	YM2608Write(info->chip,2,data);
253 }
254 
255 /************************************************/
256 /* Control Write for YM2608 - Chip 1            */
257 /* Consists of 2 addresses                      */
258 /************************************************/
WRITE8_HANDLER(YM2608_control_port_1_A_w)259 WRITE8_HANDLER( YM2608_control_port_1_A_w ){
260 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
261 	YM2608Write(info->chip,0,data);
262 }
263 
WRITE8_HANDLER(YM2608_control_port_1_B_w)264 WRITE8_HANDLER( YM2608_control_port_1_B_w ){
265 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
266 	YM2608Write(info->chip,2,data);
267 }
268 
269 /************************************************/
270 /* Data Write for YM2608 - Chip 0               */
271 /* Consists of 2 addresses                      */
272 /************************************************/
WRITE8_HANDLER(YM2608_data_port_0_A_w)273 WRITE8_HANDLER( YM2608_data_port_0_A_w )
274 {
275 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
276 	YM2608Write(info->chip,1,data);
277 }
278 
WRITE8_HANDLER(YM2608_data_port_0_B_w)279 WRITE8_HANDLER( YM2608_data_port_0_B_w )
280 {
281 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
282 	YM2608Write(info->chip,3,data);
283 }
284 
285 /************************************************/
286 /* Data Write for YM2608 - Chip 1               */
287 /* Consists of 2 addresses                      */
288 /************************************************/
WRITE8_HANDLER(YM2608_data_port_1_A_w)289 WRITE8_HANDLER( YM2608_data_port_1_A_w ){
290 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
291 	YM2608Write(info->chip,1,data);
292 }
WRITE8_HANDLER(YM2608_data_port_1_B_w)293 WRITE8_HANDLER( YM2608_data_port_1_B_w ){
294 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
295 	YM2608Write(info->chip,3,data);
296 }
297 
298 /**************** end of file ****************/
299 #if 1		/* QUASI88 */
YM2608_timer_over_0(int c)300 int	YM2608_timer_over_0(int c) { struct ym2608_info *info = sndti_token(SOUND_YM2608, 0); return YM2608TimerOver(info->chip,c); }
YM2608_timer_over_1(int c)301 int	YM2608_timer_over_1(int c) { struct ym2608_info *info = sndti_token(SOUND_YM2608, 1); return YM2608TimerOver(info->chip,c); }
302 
YM2608_set_volume_0(float volume)303 void YM2608_set_volume_0(float volume)
304 {
305 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
306 	stream_set_output_gain(info->stream, 0, volume);
307 	stream_set_output_gain(info->stream, 1, volume);
308 }
YM2608_set_volume_1(float volume)309 void YM2608_set_volume_1(float volume)
310 {
311 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
312 	stream_set_output_gain(info->stream, 0, volume);
313 	stream_set_output_gain(info->stream, 1, volume);
314 }
315 
YM2608_AY8910_set_volume_0(float volume)316 void YM2608_AY8910_set_volume_0(float volume)
317 {
318 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 0);
319 	ay8910_set_volume_ym(info->psg, ALL_8910_CHANNELS, volume);
320 }
YM2608_AY8910_set_volume_1(float volume)321 void YM2608_AY8910_set_volume_1(float volume)
322 {
323 	struct ym2608_info *info = sndti_token(SOUND_YM2608, 1);
324 	ay8910_set_volume_ym(info->psg, ALL_8910_CHANNELS, volume);
325 }
326 #endif		/* QUASI88 */
327 
328 
329 /**************************************************************************
330  * Generic get_info
331  **************************************************************************/
332 
ym2608_set_info(void * token,UINT32 state,sndinfo * info)333 static void ym2608_set_info(void *token, UINT32 state, sndinfo *info)
334 {
335 	switch (state)
336 	{
337 		/* no parameters to set */
338 	}
339 }
340 
341 
ym2608_get_info(void * token,UINT32 state,sndinfo * info)342 void ym2608_get_info(void *token, UINT32 state, sndinfo *info)
343 {
344 	switch (state)
345 	{
346 		/* --- the following bits of info are returned as 64-bit signed integers --- */
347 
348 		/* --- the following bits of info are returned as pointers to data or functions --- */
349 		case SNDINFO_PTR_SET_INFO:						info->set_info = ym2608_set_info;		break;
350 		case SNDINFO_PTR_START:							info->start = ym2608_start;				break;
351 		case SNDINFO_PTR_STOP:							info->stop = ym2608_stop;				break;
352 		case SNDINFO_PTR_RESET:							info->reset = ym2608_reset;				break;
353 
354 		/* --- the following bits of info are returned as NULL-terminated strings --- */
355 		case SNDINFO_STR_NAME:							info->s = "YM2608";						break;
356 		case SNDINFO_STR_CORE_FAMILY:					info->s = "Yamaha FM";					break;
357 		case SNDINFO_STR_CORE_VERSION:					info->s = "1.0";						break;
358 		case SNDINFO_STR_CORE_FILE:						info->s = __FILE__;						break;
359 		case SNDINFO_STR_CORE_CREDITS:					info->s = "Copyright (c) 2004, The MAME Team"; break;
360 	}
361 }
362 
363 #endif
364