1 /****************************************************************************
2  *
3  * Phoenix sound hardware simulation - still very ALPHA!
4  *
5  * If you find errors or have suggestions, please mail me.
6  * Juergen Buchmueller <pullmoll@t-online.de>
7  *
8  ****************************************************************************/
9 
10 
11 #include <math.h>
12 #include "driver.h"
13 
14 /****************************************************************************
15  * 4006
16  * Dual 4-bit and dual 5-bit serial-in serial-out shift registers.
17  *
18  *			+----------+
19  *		1D5 |1	+--+ 14| VCC
20  *	   /1Q4 |2		 13| 1Q1
21  *		CLK |3		 12| 2Q0
22  *		2D4 |4	4006 11| 2Q0
23  *		3D4 |5		 10| 3Q0
24  *		4D5 |6		  9| 4Q0
25  *		GND |7		  8| 4Q1
26  *			+----------+
27  *
28  * [This information is part of the GIICM]
29  *
30  * Pin 8 and 9 are connected to an EXOR gate and the inverted
31  * output (EXNOR) is fed back to pin 1 (and the pseudo polynome output).
32  *
33  *		1D5 		 1Q1  2D4		2Q0  3D4	   3Q0	4D5 	 4Q1 4Q0
34  *		+--+--+--+--+--+  +--+--+--+--+  +--+--+--+--+	+--+--+--+--+--+
35  *	 +->| 0| 1| 2| 3| 4|->| 5| 6| 7| 8|->| 9|10|11|12|->|13|14|15|16|17|
36  *	 |	+--+--+--+--+--+  +--+--+--+--+  +--+--+--+--+	+--+--+--+--+--+
37  *	 |											 ____			  |  |
38  *	 |											/	 |------------+  |
39  *	 +-----------------------------------------|EXNOR|				 |
40  *												\____|---------------+
41  *
42  ****************************************************************************/
43 
44 #define VMIN    0
45 #define VMAX	32767
46 
47 static int sound_latch_a;
48 static int sound_latch_b;
49 
50 static int channel;
51 
52 static int tone1_vco1_cap;
53 static int tone1_level;
54 static int tone2_level;
55 
56 static UINT32 *poly18 = NULL;
57 
tone1_vco1(int samplerate)58 static INLINE int tone1_vco1(int samplerate)
59 {
60     static int output, counter, level;
61 	/*
62 	 * L447 (NE555): Ra=47k, Rb=100k, C = 0.01uF, 0.48uF, 1.01uF or 1.48uF
63      * charge times = 0.639*(Ra+Rb)*C = 0.0092s, 0.0451s, 0.0949s, 0.1390s
64      * discharge times = 0.639*Rb*C = 0.0064s, 0.0307s, 0.0645s, 0.0946s
65      */
66     #define C18a    0.01e-6
67 	#define C18b	0.48e-6
68 	#define C18c	1.01e-6
69 	#define C18d	1.48e-6
70 	#define R40 	47000
71 	#define R41 	100000
72     static int rate[2][4] = {
73 		{
74 			VMAX*2/3/(0.693*(R40+R41)*C18a),
75 			VMAX*2/3/(0.693*(R40+R41)*C18b),
76 			VMAX*2/3/(0.693*(R40+R41)*C18c),
77 			VMAX*2/3/(0.693*(R40+R41)*C18d)
78 		},
79 		{
80 			VMAX*2/3/(0.693*R41*C18a),
81 			VMAX*2/3/(0.693*R41*C18b),
82 			VMAX*2/3/(0.693*R41*C18c),
83 			VMAX*2/3/(0.693*R41*C18d)
84         }
85 	};
86 	if( output )
87 	{
88 		if (level > VMAX*1/3)
89 		{
90 			counter -= rate[1][tone1_vco1_cap];
91 			if( counter <= 0 )
92 			{
93 				int steps = -counter / samplerate + 1;
94 				counter += steps * samplerate;
95 				if( (level -= steps) <= VMAX*1/3 )
96 				{
97 					level = VMAX*1/3;
98                     output = 0;
99 				}
100 			}
101 		}
102 	}
103 	else
104 	{
105 		if (level < VMAX*2/3)
106 		{
107 			counter -= rate[0][tone1_vco1_cap];
108 			if( counter <= 0 )
109 			{
110                 int steps = -counter / samplerate + 1;
111 				counter += steps * samplerate;
112 				if( (level += steps) >= VMAX*2/3 )
113 				{
114 					level = VMAX*2/3;
115 					output = 1;
116 				}
117 			}
118 		}
119 	}
120 	return output;
121 }
122 
tone1_vco2(int samplerate)123 static INLINE int tone1_vco2(int samplerate)
124 {
125 	static int output, counter, level;
126 
127 	/*
128 	 * L517 (NE555): Ra=570k, Rb=570k, C=10uF
129 	 * charge time = 0.639*(Ra+Rb)*C = 7.9002s
130 	 * discharge time = 0.639*Rb*C = 3.9501s
131 	 */
132 	#define C20 10.0e-6
133 	#define R43 570000
134 	#define R44 570000
135 
136 	if( output )
137 	{
138 		if (level > VMIN)
139 		{
140 			counter -= (int)(VMAX*2/3 / (0.693 * R44 * C20));
141 			if( counter <= 0 )
142 			{
143 				int steps = -counter / samplerate + 1;
144 				counter += steps * samplerate;
145 				if( (level -= steps) <= VMAX*1/3 )
146 				{
147 					level = VMAX*1/3;
148 					output = 0;
149 				}
150 			}
151 		}
152 	}
153 	else
154 	{
155 		if (level < VMAX)
156 		{
157 			counter -= (int)(VMAX*2/3 / (0.693 * (R43 + R44) * C20));
158 			if( counter <= 0 )
159 			{
160 				int steps = -counter / samplerate + 1;
161 				counter += steps * samplerate;
162 				if( (level += steps) >= VMAX*2/3 )
163 				{
164 					level = VMAX*2/3;
165 					output = 1;
166 				}
167 			}
168 		}
169 	}
170 
171 	return output;
172 }
173 
tone1_vco(int samplerate,int vco1,int vco2)174 static INLINE int tone1_vco(int samplerate, int vco1, int vco2)
175 {
176 	static int counter, level, rate, charge;
177 	int voltage;
178 
179 	if (level != charge)
180     {
181         /* charge or discharge C22 */
182         counter -= rate;
183         while( counter <= 0 )
184         {
185             counter += samplerate;
186             if( level < charge )
187             {
188 				if( ++level == charge )
189                     break;
190             }
191             else
192             {
193 				if( --level == charge )
194                     break;
195             }
196         }
197     }
198 
199     if( vco2 )
200 	{
201 		#define C22 100.0e-6
202 		#define R42 10000
203 		#define R45 51000
204 		#define R46 51000
205 		#define RP	27777	/* R42+R46 parallel with R45 */
206 		if( vco1 )
207 		{
208 			/*		R42 10k
209 			 * +5V -/\/\/------------+
210 			 *			   5V		 |
211 			 * +5V -/\/\/--+--/\/\/--+--> V/C
212 			 *	   R45 51k | R46 51k
213 			 *			  ---
214 			 *			  --- 100u
215 			 *			   |
216 			 *			  0V
217 			 */
218 			charge = VMAX;
219 			rate = (int)((charge - level) / (RP * C22));
220 			voltage = level + (VMAX-level) * R46 / (R46 + R42);
221 		}
222 		else
223 		{
224 			/*		R42 10k
225 			 *	0V -/\/\/------------+
226 			 *			  2.7V		 |
227 			 * +5V -/\/\/--+--/\/\/--+--> V/C
228 			 *	   R45 51k | R46 51k
229 			 *			  ---
230 			 *			  --- 100u
231 			 *			   |
232 			 *			  0V
233              */
234 			/* simplification: charge = (R42 + R46) / (R42 + R45 + R46); */
235             charge = VMAX * 27 / 50;
236 			if (charge >= level)
237 				rate = (int)((charge - level) / (R45 * C22));
238 			else
239 				rate = (int)((level - charge) / ((R46+R42) * C22));
240 			voltage = level * R42 / (R46 + R42);
241 		}
242 	}
243 	else
244 	{
245 		if( vco1 )
246 		{
247 			/*		R42 10k
248 			 * +5V -/\/\/------------+
249 			 *			  2.3V		 |
250 			 *	0V -/\/\/--+--/\/\/--+--> V/C
251 			 *	   R45 51k | R46 51k
252 			 *			  ---
253 			 *			  --- 100u
254 			 *			   |
255 			 *			  0V
256 			 */
257 			/* simplification: charge = VMAX * R45 / (R42 + R45 + R46); */
258             charge = VMAX * 23 / 50;
259 			if (charge >= level)
260 				rate = (int)((charge - level) / ((R42 + R46) * C22));
261 			else
262 				rate = (int)((level - charge) / (R45 * C22));
263 			voltage = level + (VMAX - level) * R46 / (R42 + R46);
264 		}
265 		else
266 		{
267 			/*		R42 10k
268 			 *	0V -/\/\/------------+
269 			 *			   0V		 |
270 			 *	0V -/\/\/--+--/\/\/--+--> V/C
271 			 *	   R45 51k | R46 51k
272 			 *			  ---
273 			 *			  --- 100u
274 			 *			   |
275 			 *			  0V
276 			 */
277 			charge = VMIN;
278 			rate = (int)((level - charge) / (RP * C22));
279 			voltage = level * R42 / (R46 + R42);
280 		}
281 	}
282 
283 	/* L507 (NE555): Ra=20k, Rb=20k, C=0.001uF
284 	 * frequency 1.44/((Ra+2*Rb)*C) = 24kHz
285 	 */
286 	return 24000*1/3 + 24000*2/3 * voltage / 32768;
287 }
288 
tone1(int samplerate)289 static INLINE int tone1(int samplerate)
290 {
291 	static int counter, divisor, output;
292 	int vco1 = tone1_vco1(samplerate);
293 	int vco2 = tone1_vco2(samplerate);
294 	int frequency = tone1_vco(samplerate, vco1, vco2);
295 
296 	if( (sound_latch_a & 15) != 15 )
297 	{
298 		counter -= frequency;
299 		while( counter <= 0 )
300 		{
301 			counter += samplerate;
302 			if( ++divisor == 16 )
303 			{
304 				divisor = sound_latch_a & 15;
305 				output ^= 1;
306 			}
307 		}
308 	}
309 
310 	return output ? tone1_level : -tone1_level;
311 }
312 
tone2_vco(int samplerate)313 static INLINE int tone2_vco(int samplerate)
314 {
315 	static int counter, level;
316 
317 	/*
318 	 * This is how the tone2 part of the circuit looks like.
319 	 * I was having a hard time to guesstimate the results
320 	 * and they might still be wrong :(
321 	 *
322 	 *							+12V
323 	 *							 |
324 	 *							 / R23
325 	 *							 \ 100k
326 	 *							 /
327 	 * !bit4	| /|	R22 	 |
328 	 * 0V/5V >--|< |---/\/\/-----+-------+---> V C7
329 	 *			| \|	47k 	 |		 |
330 	 *			D4				 |		_|_
331 	 *					   6.8u --- 	\ / D5
332 	 *					   C7	--- 	---
333 	 *							 |		 |
334 	 *							 |		 |
335 	 *	  0V >-------------------+-/\/\/-+
336 	 *							 R24 33k
337 	 *
338 	 * V C7 min:
339 	 * 0.7V + (12V - 0.7V) * 19388 / (100000 + 19388) = 2.54V
340 	 * V C7 max:
341 	 * 0.7V + (12V - 0.7V) * 33000 / (100000 + 33000) +
342 	 *		  (12V - 5.7V) * 47000 / (100000 + 47000) = 5.51V
343      */
344 
345     #define C7  6.8e-6
346     #define R23 100000
347 	#define R22 47000
348 	#define R24 33000
349 	#define R22pR24 19388
350 
351 	#define C7_MIN (VMAX * 254 / 500)
352 	#define C7_MAX (VMAX * 551 / 500)
353 	#define C7_DIFF (C7_MAX - C7_MIN)
354 
355 	if( (sound_latch_b & 0x10) == 0 )
356 	{
357 		counter -= (C7_MAX - level) * 12 / (R23 * C7) / 5;
358 		if( counter <= 0 )
359 		{
360 			int n = (-counter / samplerate) + 1;
361 			counter += n * samplerate;
362 			if( (level += n) > C7_MAX)
363 				level = C7_MAX;
364 		}
365 	}
366 	else
367 	{
368 		counter -= (level - C7_MIN) * 12 / (R22pR24 * C7) / 5;
369 		if( counter <= 0 )
370 		{
371 			int n = (-counter / samplerate) + 1;
372 			counter += n * samplerate;
373 			if( (level -= n) < C7_MIN)
374 				level = C7_MIN;
375 		}
376 	}
377 	/*
378 	 * L487 (NE555):
379 	 * Ra = R25 (47k), Rb = R26 (47k), C = C8 (0.001uF)
380 	 * frequency 1.44/((Ra+2*Rb)*C) = 10212 Hz
381 	 */
382 	return 10212 * level / 32768;
383 }
384 
tone2(int samplerate)385 static INLINE int tone2(int samplerate)
386 {
387 	static int counter, divisor, output;
388 	int frequency = tone2_vco(samplerate);
389 
390 	if( (sound_latch_b & 15) != 15 )
391 	{
392 		counter -= frequency;
393 		while( counter <= 0 )
394 		{
395 			counter += samplerate;
396 			if( ++divisor == 16 )
397 			{
398 				divisor = sound_latch_b & 15;
399 				output ^= 1;
400 			}
401 		}
402 	}
403 	return output ? tone2_level : -tone2_level;
404 }
405 
update_c24(int samplerate)406 static INLINE int update_c24(int samplerate)
407 {
408 	static int counter, level;
409 	/*
410 	 * Noise frequency control (Port B):
411 	 * Bit 6 lo charges C24 (6.8u) via R51 (330) and when
412 	 * bit 6 is hi, C24 is discharged through R52 (20k)
413 	 * in approx. 20000 * 6.8e-6 = 0.136 seconds
414 	 */
415 	#define C24 6.8e-6
416 	#define R49 1000
417     #define R51 330
418 	#define R52 20000
419 	if( sound_latch_a & 0x40 )
420 	{
421 		if (level > VMIN)
422 		{
423 			counter -= (int)((level - VMIN) / (R52 * C24));
424 			if( counter <= 0 )
425 			{
426 				int n = -counter / samplerate + 1;
427 				counter += n * samplerate;
428 				if( (level -= n) < VMIN)
429 					level = VMIN;
430 			}
431 		}
432     }
433 	else
434 	{
435 		if (level < VMAX)
436 		{
437 			counter -= (int)((VMAX - level) / ((R51+R49) * C24));
438 			if( counter <= 0 )
439 			{
440 				int n = -counter / samplerate + 1;
441 				counter += n * samplerate;
442 				if( (level += n) > VMAX)
443 					level = VMAX;
444 			}
445 		}
446     }
447 	return VMAX - level;
448 }
449 
update_c25(int samplerate)450 static INLINE int update_c25(int samplerate)
451 {
452 	static int counter, level;
453 	/*
454 	 * Bit 7 hi charges C25 (6.8u) over a R50 (1k) and R53 (330) and when
455 	 * bit 7 is lo, C25 is discharged through R54 (47k)
456 	 * in about 47000 * 6.8e-6 = 0.3196 seconds
457 	 */
458 	#define C25 6.8e-6
459 	#define R50 1000
460     #define R53 330
461 	#define R54 47000
462 
463 	if( sound_latch_a & 0x80 )
464 	{
465 		if (level < VMAX)
466 		{
467 			counter -= (int)((VMAX - level) / ((R50+R53) * C25));
468 			if( counter <= 0 )
469 			{
470 				int n = -counter / samplerate + 1;
471 				counter += n * samplerate;
472 				if( (level += n) > VMAX )
473 					level = VMAX;
474 			}
475 		}
476 	}
477 	else
478 	{
479 		if (level > VMIN)
480 		{
481 			counter -= (int)((level - VMIN) / (R54 * C25));
482 			if( counter <= 0 )
483 			{
484 				int n = -counter / samplerate + 1;
485 				counter += n * samplerate;
486 				if( (level -= n) < VMIN )
487 					level = VMIN;
488 			}
489 		}
490 	}
491 	return level;
492 }
493 
494 
noise(int samplerate)495 static INLINE int noise(int samplerate)
496 {
497 	static int counter, polyoffs, polybit, lowpass_counter, lowpass_polybit;
498 	int vc24 = update_c24(samplerate);
499 	int vc25 = update_c25(samplerate);
500 	int sum = 0, level, frequency;
501 
502 	/*
503 	 * The voltage levels are added and control I(CE) of transistor TR1
504 	 * (NPN) which then controls the noise clock frequency (linearily?).
505 	 * level = voltage at the output of the op-amp controlling the noise rate.
506 	 */
507 	if( vc24 < vc25 )
508 		level = vc24 + (vc25 - vc24) / 2;
509 	else
510 		level = vc25 + (vc24 - vc25) / 2;
511 
512 	frequency = 588 + 6325 * level / 32768;
513 
514     /*
515 	 * NE555: Ra=47k, Rb=1k, C=0.05uF
516 	 * minfreq = 1.44 / ((47000+2*1000) * 0.05e-6) = approx. 588 Hz
517 	 * R71 (2700 Ohms) parallel to R73 (47k Ohms) = approx. 2553 Ohms
518 	 * maxfreq = 1.44 / ((2553+2*1000) * 0.05e-6) = approx. 6325 Hz
519 	 */
520 	counter -= frequency;
521 	if( counter <= 0 )
522 	{
523 		int n = (-counter / samplerate) + 1;
524 		counter += n * samplerate;
525 		polyoffs = (polyoffs + n) & 0x3ffff;
526 		polybit = (poly18[polyoffs>>5] >> (polyoffs & 31)) & 1;
527 	}
528 	if (!polybit)
529 		sum += vc24;
530 
531 	/* 400Hz crude low pass filter: this is only a guess!! */
532 	lowpass_counter -= 400;
533 	if( lowpass_counter <= 0 )
534 	{
535 		lowpass_counter += samplerate;
536 		lowpass_polybit = polybit;
537 	}
538 	if (!lowpass_polybit)
539 		sum += vc25;
540 
541 	return sum;
542 }
543 
phoenix_sound_update(int param,INT16 * buffer,int length)544 static void phoenix_sound_update(int param, INT16 *buffer, int length)
545 {
546 	int samplerate = Machine->sample_rate;
547 
548 	while( length-- > 0 )
549 	{
550 		int sum = 0;
551 		sum = (tone1(samplerate) + tone2(samplerate) + noise(samplerate)) / 4;
552       MAME_CLAMP_SAMPLE(sum);
553 		*buffer++ = sum;
554 	}
555 }
556 
WRITE_HANDLER(phoenix_sound_control_a_w)557 WRITE_HANDLER( phoenix_sound_control_a_w )
558 {
559 	if( data == sound_latch_a )
560 		return;
561 
562 	stream_update(channel,0);
563 	sound_latch_a = data;
564 
565 	tone1_vco1_cap = (sound_latch_a >> 4) & 3;
566 	if( sound_latch_a & 0x20 )
567 		tone1_level = VMAX * 10000 / (10000+10000);
568 	else
569 		tone1_level = VMAX;
570 }
571 
WRITE_HANDLER(phoenix_sound_control_b_w)572 WRITE_HANDLER( phoenix_sound_control_b_w )
573 {
574 	if( data == sound_latch_b )
575 		return;
576 
577 	stream_update(channel,0);
578 	sound_latch_b = data;
579 
580 	if( sound_latch_b & 0x20 )
581 		tone2_level = VMAX * 10 / 11;
582 	else
583 		tone2_level = VMAX;
584 
585 	/* eventually change the tune that the MM6221AA is playing */
586 	mm6221aa_tune_w(0, sound_latch_b >> 6);
587 }
588 
phoenix_sh_start(const struct MachineSound * msound)589 int phoenix_sh_start(const struct MachineSound *msound)
590 {
591 	int i, j;
592 	UINT32 shiftreg;
593 
594 	poly18 = (UINT32 *)auto_malloc((1ul << (18-5)) * sizeof(UINT32));
595 
596 	if( !poly18 )
597 		return 1;
598 
599     shiftreg = 0;
600 	for( i = 0; i < (1ul << (18-5)); i++ )
601 	{
602 		UINT32 bits = 0;
603 		for( j = 0; j < 32; j++ )
604 		{
605 			bits = (bits >> 1) | (shiftreg << 31);
606 			if( ((shiftreg >> 16) & 1) == ((shiftreg >> 17) & 1) )
607 				shiftreg = (shiftreg << 1) | 1;
608 			else
609 				shiftreg <<= 1;
610 		}
611 		poly18[i] = bits;
612 	}
613 
614 	channel = stream_init("Custom", 50, Machine->sample_rate, 0, phoenix_sound_update);
615 	if( channel == -1 )
616 		return 1;
617 
618 	return 0;
619 }
620 
phoenix_sh_stop(void)621 void phoenix_sh_stop(void)
622 {
623 }
624 
phoenix_sh_update(void)625 void phoenix_sh_update(void)
626 {
627 	stream_update(channel, 0);
628 }
629