1 /***************************************************************************
2 
3   sn76496.c
4 
5   Routines to emulate the Texas Instruments SN76489 / SN76496 programmable
6   tone /noise generator. Also known as (or at least compatible with) TMS9919.
7 
8   Noise emulation is not accurate due to lack of documentation. The noise
9   generator uses a shift register with a XOR-feedback network, but the exact
10   layout is unknown. It can be set for either period or white noise; again,
11   the details are unknown.
12 
13 ***************************************************************************/
14 
15 #include "driver.h"
16 
17 
18 #define MAX_OUTPUT 0x7fff
19 
20 #define STEP 0x10000
21 
22 
23 /* Formulas for noise generator */
24 /* bit0 = output */
25 
26 /* noise feedback for white noise mode (verified on real SN76489 by John Kortink) */
27 #define FB_WNOISE 0x14002	/* (16bits) bit16 = bit0(out) ^ bit2 ^ bit15 */
28 
29 /* noise feedback for periodic noise mode */
30 /*#define FB_PNOISE 0x10000 // 16bit rorate */
31 #define FB_PNOISE 0x08000   /* JH 981127 - fixes Do Run Run */
32 
33 /*
34 0x08000 is definitely wrong. The Master System conversion of Marble Madness
35 uses periodic noise as a baseline. With a 15-bit rotate, the bassline is
36 out of tune.
37 The 16-bit rotate has been confirmed against a real PAL Sega Master System 2.
38 Hope that helps the System E stuff, more news on the PSG as and when!
39 */
40 
41 /* noise generator start preset (for periodic noise) */
42 #define NG_PRESET 0x0f35
43 
44 
45 struct SN76496
46 {
47 	int Channel;
48 	int SampleRate;
49 	unsigned int UpdateStep;
50 	int VolTable[16];	/* volume table         */
51 	int Register[8];	/* registers */
52 	int LastRegister;	/* last register written */
53 	int Volume[4];		/* volume of voice 0-2 and noise */
54 	unsigned int RNG;		/* noise generator      */
55 	int NoiseFB;		/* noise feedback mask */
56 	int Period[4];
57 	int Count[4];
58 	int Output[4];
59 };
60 
61 
62 static struct SN76496 sn[MAX_76496];
63 
64 
65 
SN76496Write(int chip,int data)66 static void SN76496Write(int chip,int data)
67 {
68 	struct SN76496 *R = &sn[chip];
69 
70 
71 	/* update the output buffer before changing the registers */
72 	stream_update(R->Channel,0);
73 
74 	if (data & 0x80)
75 	{
76 		int r = (data & 0x70) >> 4;
77 		int c = r/2;
78 
79 		R->LastRegister = r;
80 		R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
81 		switch (r)
82 		{
83 			case 0:	/* tone 0 : frequency */
84 			case 2:	/* tone 1 : frequency */
85 			case 4:	/* tone 2 : frequency */
86 				R->Period[c] = R->UpdateStep * R->Register[r];
87 				if (R->Period[c] == 0) R->Period[c] = R->UpdateStep;
88 				if (r == 4)
89 				{
90 					/* update noise shift frequency */
91 					if ((R->Register[6] & 0x03) == 0x03)
92 						R->Period[3] = 2 * R->Period[2];
93 				}
94 				break;
95 			case 1:	/* tone 0 : volume */
96 			case 3:	/* tone 1 : volume */
97 			case 5:	/* tone 2 : volume */
98 			case 7:	/* noise  : volume */
99 				R->Volume[c] = R->VolTable[data & 0x0f];
100 				break;
101 			case 6:	/* noise  : frequency, mode */
102 				{
103 					int n = R->Register[6];
104 					R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE;
105 					n &= 3;
106 					/* N/512,N/1024,N/2048,Tone #3 output */
107 					R->Period[3] = (n == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+n));
108 
109 					/* reset noise shifter */
110 					R->RNG = NG_PRESET;
111 					R->Output[3] = R->RNG & 1;
112 				}
113 				break;
114 		}
115 	}
116 	else
117 	{
118 		int r = R->LastRegister;
119 		int c = r/2;
120 
121 		switch (r)
122 		{
123 			case 0:	/* tone 0 : frequency */
124 			case 2:	/* tone 1 : frequency */
125 			case 4:	/* tone 2 : frequency */
126 				R->Register[r] = (R->Register[r] & 0x0f) | ((data & 0x3f) << 4);
127 				R->Period[c] = R->UpdateStep * R->Register[r];
128 				if (R->Period[c] == 0) R->Period[c] = R->UpdateStep;
129 				if (r == 4)
130 				{
131 					/* update noise shift frequency */
132 					if ((R->Register[6] & 0x03) == 0x03)
133 						R->Period[3] = 2 * R->Period[2];
134 				}
135 				break;
136 		}
137 	}
138 }
139 
140 
WRITE_HANDLER(SN76496_0_w)141 WRITE_HANDLER( SN76496_0_w ) {	SN76496Write(0,data); }
WRITE_HANDLER(SN76496_1_w)142 WRITE_HANDLER( SN76496_1_w ) {	SN76496Write(1,data); }
WRITE_HANDLER(SN76496_2_w)143 WRITE_HANDLER( SN76496_2_w ) {	SN76496Write(2,data); }
WRITE_HANDLER(SN76496_3_w)144 WRITE_HANDLER( SN76496_3_w ) {	SN76496Write(3,data); }
145 
146 
147 
SN76496Update(int chip,INT16 * buffer,int length)148 static void SN76496Update(int chip,INT16 *buffer,int length)
149 {
150 	int i;
151 	struct SN76496 *R = &sn[chip];
152 
153 
154 	/* If the volume is 0, increase the counter */
155 	for (i = 0;i < 4;i++)
156 	{
157 		if (R->Volume[i] == 0)
158 		{
159 			/* note that I do count += length, NOT count = length + 1. You might think */
160 			/* it's the same since the volume is 0, but doing the latter could cause */
161 			/* interferencies when the program is rapidly modulating the volume. */
162 			if (R->Count[i] <= length*STEP) R->Count[i] += length*STEP;
163 		}
164 	}
165 
166 	while (length > 0)
167 	{
168 		int vol[4];
169 		unsigned int out;
170 		int left;
171 
172 
173 		/* vol[] keeps track of how long each square wave stays */
174 		/* in the 1 position during the sample period. */
175 		vol[0] = vol[1] = vol[2] = vol[3] = 0;
176 
177 		for (i = 0;i < 3;i++)
178 		{
179 			if (R->Output[i]) vol[i] += R->Count[i];
180 			R->Count[i] -= STEP;
181 			/* Period[i] is the half period of the square wave. Here, in each */
182 			/* loop I add Period[i] twice, so that at the end of the loop the */
183 			/* square wave is in the same status (0 or 1) it was at the start. */
184 			/* vol[i] is also incremented by Period[i], since the wave has been 1 */
185 			/* exactly half of the time, regardless of the initial position. */
186 			/* If we exit the loop in the middle, Output[i] has to be inverted */
187 			/* and vol[i] incremented only if the exit status of the square */
188 			/* wave is 1. */
189 			while (R->Count[i] <= 0)
190 			{
191 				R->Count[i] += R->Period[i];
192 				if (R->Count[i] > 0)
193 				{
194 					R->Output[i] ^= 1;
195 					if (R->Output[i]) vol[i] += R->Period[i];
196 					break;
197 				}
198 				R->Count[i] += R->Period[i];
199 				vol[i] += R->Period[i];
200 			}
201 			if (R->Output[i]) vol[i] -= R->Count[i];
202 		}
203 
204 		left = STEP;
205 		do
206 		{
207 			int nextevent;
208 
209 
210 			if (R->Count[3] < left) nextevent = R->Count[3];
211 			else nextevent = left;
212 
213 			if (R->Output[3]) vol[3] += R->Count[3];
214 			R->Count[3] -= nextevent;
215 			if (R->Count[3] <= 0)
216 			{
217 				if (R->RNG & 1) R->RNG ^= R->NoiseFB;
218 				R->RNG >>= 1;
219 				R->Output[3] = R->RNG & 1;
220 				R->Count[3] += R->Period[3];
221 				if (R->Output[3]) vol[3] += R->Period[3];
222 			}
223 			if (R->Output[3]) vol[3] -= R->Count[3];
224 
225 			left -= nextevent;
226 		} while (left > 0);
227 
228 		out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] +
229 				vol[2] * R->Volume[2] + vol[3] * R->Volume[3];
230 
231 		if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP;
232 
233 		*(buffer++) = out / STEP;
234 
235 		length--;
236 	}
237 }
238 
239 
240 
SN76496_set_clock(int chip,int clock)241 static void SN76496_set_clock(int chip,int clock)
242 {
243 	struct SN76496 *R = &sn[chip];
244 
245 
246 	/* the base clock for the tone generators is the chip clock divided by 16; */
247 	/* for the noise generator, it is clock / 256. */
248 	/* Here we calculate the number of steps which happen during one sample */
249 	/* at the given sample rate. No. of events = sample rate / (clock/16). */
250 	/* STEP is a multiplier used to turn the fraction into a fixed point */
251 	/* number. */
252 	R->UpdateStep = ((double)STEP * R->SampleRate * 16) / clock;
253 }
254 
255 
256 
SN76496_set_gain(int chip,int gain)257 static void SN76496_set_gain(int chip,int gain)
258 {
259 	struct SN76496 *R = &sn[chip];
260 	int i;
261 	double out;
262 
263 
264 	gain &= 0xff;
265 
266 	/* increase max output basing on gain (0.2 dB per step) */
267 	out = MAX_OUTPUT / 3;
268 	while (gain-- > 0)
269 		out *= 1.023292992;	/* = (10 ^ (0.2/20)) */
270 
271 	/* build volume table (2dB per step) */
272 	for (i = 0;i < 15;i++)
273 	{
274 		/* limit volume to avoid clipping */
275 		if (out > MAX_OUTPUT / 3) R->VolTable[i] = MAX_OUTPUT / 3;
276 		else R->VolTable[i] = out;
277 
278 		out /= 1.258925412;	/* = 10 ^ (2/20) = 2dB */
279 	}
280 	R->VolTable[15] = 0;
281 }
282 
283 
284 
SN76496_init(const struct MachineSound * msound,int chip,int clock,int volume,int sample_rate)285 static int SN76496_init(const struct MachineSound *msound,int chip,int clock,int volume,int sample_rate)
286 {
287 	int i;
288 	struct SN76496 *R = &sn[chip];
289 	char name[40];
290 
291 
292 	sprintf(name,"SN76496 #%d",chip);
293 	R->Channel = stream_init(name,volume,sample_rate,chip,SN76496Update);
294 
295 	if (R->Channel == -1)
296 		return 1;
297 
298 	R->SampleRate = sample_rate;
299 	SN76496_set_clock(chip,clock);
300 
301 	for (i = 0;i < 4;i++) R->Volume[i] = 0;
302 
303 	R->LastRegister = 0;
304 	for (i = 0;i < 8;i+=2)
305 	{
306 		R->Register[i] = 0;
307 		R->Register[i + 1] = 0x0f;	/* volume = 0 */
308 	}
309 
310 	for (i = 0;i < 4;i++)
311 	{
312 		R->Output[i] = 0;
313 		R->Period[i] = R->Count[i] = R->UpdateStep;
314 	}
315 	R->RNG = NG_PRESET;
316 	R->Output[3] = R->RNG & 1;
317 
318 	return 0;
319 }
320 
321 
322 
SN76496_sh_start(const struct MachineSound * msound)323 int SN76496_sh_start(const struct MachineSound *msound)
324 {
325 	int chip;
326 	const struct SN76496interface *intf = msound->sound_interface;
327 
328 
329 	for (chip = 0;chip < intf->num;chip++)
330 	{
331 		if (SN76496_init(msound,chip,intf->baseclock[chip],intf->volume[chip] & 0xff,Machine->sample_rate) != 0)
332 			return 1;
333 
334 		SN76496_set_gain(chip,(intf->volume[chip] >> 8) & 0xff);
335 	}
336 	return 0;
337 }
338