1 /*
2 	SN76489 emulation
3 	by Maxim in 2001 and 2002
4 	converted from my original Delphi implementation
5 
6 	I'm a C newbie so I'm sure there are loads of stupid things
7 	in here which I'll come back to some day and redo
8 
9 	Includes:
10 	- Super-high quality tone channel "oversampling" by calculating fractional positions on transitions
11 	- Noise output pattern reverse engineered from actual SMS output
12 	- Volume levels taken from actual SMS output
13 
14 	07/08/04  Charles MacDonald
15 	Modified for use with SMS Plus:
16 	- Added support for multiple PSG chips.
17 	- Added reset/config/update routines.
18 	- Added context management routines.
19 	- Removed SN76489_GetValues().
20 	- Removed some unused variables.
21 */
22 
23 #include <stdlib.h> // malloc/free
24 #include <float.h> // for FLT_MIN
25 #include <string.h> // for memcpy
26 #include "mamedef.h"
27 #include "sn76489.h"
28 #include "panning.h"
29 
30 #define NoiseInitialState 0x8000  /* Initial state of shift register */
31 #define PSG_CUTOFF        0x6     /* Value below which PSG does not output */
32 
33 static const int PSGVolumeValues[16] = {
34 /*	// These values are taken from a real SMS2's output
35 	{892,892,892,760,623,497,404,323,257,198,159,123,96,75,60,0}, // I can't remember why 892... :P some scaling I did at some point
36 	// these values are true volumes for 2dB drops at each step (multiply previous by 10^-0.1)
37 	1516,1205,957,760,603,479,381,303,240,191,152,120,96,76,60,0*/
38 // The MAME core uses 0x2000 as maximum volume (0x1000 for bipolar output)
39 	4096, 3254, 2584, 2053, 1631, 1295, 1029, 817, 649, 516, 410, 325, 258, 205, 163, 0
40 };
41 
42 /*static SN76489_Context SN76489[MAX_SN76489];*/
43 static SN76489_Context* LastChipInit = NULL;
44 //static unsigned short int FNumLimit;
45 
46 
SN76489_Init(int PSGClockValue,int SamplingRate)47 SN76489_Context* SN76489_Init( int PSGClockValue, int SamplingRate)
48 {
49 	int i;
50 	SN76489_Context* chip = (SN76489_Context*)malloc(sizeof(SN76489_Context));
51 	if(chip)
52 	{
53 		chip->dClock=(float)(PSGClockValue & 0x7FFFFFF)/16/SamplingRate;
54 
55 		SN76489_SetMute(chip, MUTE_ALLON);
56 		SN76489_Config(chip, /*MUTE_ALLON,*/ FB_SEGAVDP, SRW_SEGAVDP, 1);
57 
58 		for( i = 0; i <= 3; i++ )
59 			centre_panning(chip->panning[i]);
60 		//SN76489_Reset(chip);
61 
62 		if ((PSGClockValue & 0x80000000) && LastChipInit != NULL)
63 		{
64 			// Activate special NeoGeoPocket Mode
65 			LastChipInit->NgpFlags = 0x80 | 0x00;
66 			chip->NgpFlags = 0x80 | 0x01;
67 			chip->NgpChip2 = LastChipInit;
68 			LastChipInit->NgpChip2 = chip;
69 			LastChipInit = NULL;
70 		}
71 		else
72 		{
73 			chip->NgpFlags = 0x00;
74 			chip->NgpChip2 = NULL;
75 			LastChipInit = chip;
76 		}
77 	}
78 	return chip;
79 }
80 
SN76489_Reset(SN76489_Context * chip)81 void SN76489_Reset(SN76489_Context* chip)
82 {
83 	int i;
84 
85 	chip->PSGStereo = 0xFF;
86 
87 	for( i = 0; i <= 3; i++ )
88 	{
89 		/* Initialise PSG state */
90 		chip->Registers[2*i] = 1;		 /* tone freq=1 */
91 		chip->Registers[2*i+1] = 0xf;	 /* vol=off */
92 		chip->NoiseFreq = 0x10;
93 
94 		/* Set counters to 0 */
95 		chip->ToneFreqVals[i] = 0;
96 
97 		/* Set flip-flops to 1 */
98 		chip->ToneFreqPos[i] = 1;
99 
100 		/* Set intermediate positions to do-not-use value */
101 		chip->IntermediatePos[i] = FLT_MIN;
102 
103 		/* Set panning to centre */
104 		//centre_panning( chip->panning[i] );
105 	}
106 
107 	chip->LatchedRegister = 0;
108 
109 	/* Initialise noise generator */
110 	chip->NoiseShiftRegister = NoiseInitialState;
111 
112 	/* Zero clock */
113 	chip->Clock = 0;
114 }
115 
SN76489_Shutdown(SN76489_Context * chip)116 void SN76489_Shutdown(SN76489_Context* chip)
117 {
118 	free(chip);
119 }
120 
SN76489_Config(SN76489_Context * chip,int feedback,int sr_width,int boost_noise)121 void SN76489_Config(SN76489_Context* chip, /*int mute,*/ int feedback, int sr_width, int boost_noise)
122 {
123 	//chip->Mute = mute;
124 	chip->WhiteNoiseFeedback = feedback;
125 	chip->SRWidth = sr_width;
126 }
127 
128 /*
129 void SN76489_SetContext(int which, uint8 *data)
130 {
131 	memcpy( &SN76489[which], data, sizeof(SN76489_Context) );
132 }
133 
134 void SN76489_GetContext(int which, uint8 *data)
135 {
136 	memcpy( data, &SN76489[which], sizeof(SN76489_Context) );
137 }
138 
139 uint8 *SN76489_GetContextPtr(int which)
140 {
141 	return (uint8 *)&SN76489[which];
142 }
143 
144 int SN76489_GetContextSize(void)
145 {
146 	return sizeof(SN76489_Context);
147 }
148 */
SN76489_Write(SN76489_Context * chip,int data)149 void SN76489_Write(SN76489_Context* chip, int data)
150 {
151 	if ( data & 0x80 )
152 	{
153 		/* Latch/data byte  %1 cc t dddd */
154 		chip->LatchedRegister = ( data >> 4 ) & 0x07;
155 		chip->Registers[chip->LatchedRegister] =
156 			( chip->Registers[chip->LatchedRegister] & 0x3f0 ) /* zero low 4 bits */
157 			| ( data & 0xf );                            /* and replace with data */
158 	} else {
159 		/* Data byte        %0 - dddddd */
160 		if ( !( chip->LatchedRegister % 2 ) && ( chip->LatchedRegister < 5 ) )
161 			/* Tone register */
162 			chip->Registers[chip->LatchedRegister] =
163 				( chip->Registers[chip->LatchedRegister] & 0x00f) /* zero high 6 bits */
164 				| ( ( data & 0x3f ) << 4 );                 /* and replace with data */
165 		else
166 			/* Other register */
167 			chip->Registers[chip->LatchedRegister]=data&0x0f; /* Replace with data */
168 	}
169 	switch (chip->LatchedRegister) {
170 	case 0:
171 	case 2:
172 	case 4: /* Tone channels */
173 		if ( chip->Registers[chip->LatchedRegister] == 0 )
174 			chip->Registers[chip->LatchedRegister] = 1; /* Zero frequency changed to 1 to avoid div/0 */
175 		break;
176 	case 6: /* Noise */
177 		chip->NoiseShiftRegister = NoiseInitialState;        /* reset shift register */
178 		chip->NoiseFreq = 0x10 << ( chip->Registers[6] & 0x3 ); /* set noise signal generator frequency */
179 		break;
180 	}
181 }
182 
SN76489_GGStereoWrite(SN76489_Context * chip,int data)183 void SN76489_GGStereoWrite(SN76489_Context* chip, int data)
184 {
185 	chip->PSGStereo=data;
186 }
187 
188 //void SN76489_Update(SN76489_Context* chip, INT16 **buffer, int length)
SN76489_Update(SN76489_Context * chip,INT32 ** buffer,int length)189 void SN76489_Update(SN76489_Context* chip, INT32 **buffer, int length)
190 {
191 	int i, j;
192 	int NGPMode;
193 	SN76489_Context* chip2;
194 	SN76489_Context* chip_t;
195 	SN76489_Context* chip_n;
196 
197 	NGPMode = (chip->NgpFlags >> 7) & 0x01;
198 	if (! NGPMode)
199 	{
200 		chip2 = NULL;
201 		chip_t = chip_n = chip;
202 	}
203 	else
204 	{
205 		chip2 = (SN76489_Context*)chip->NgpChip2;
206 		if (! (chip->NgpFlags & 0x01))
207 		{
208 			chip_t = chip;
209 			chip_n = chip2;
210 		}
211 		else
212 		{
213 			chip_t = chip2;
214 			chip_n = chip;
215 		}
216 	}
217 
218 	for( j = 0; j < length; j++ )
219 	{
220 		/* Tone channels */
221 		for ( i = 0; i <= 2; ++i )
222 			if ( (chip_t->Mute >> i) & 1 )
223 			{
224 				if ( chip_t->IntermediatePos[i] != FLT_MIN )
225 					/* Intermediate position (antialiasing) */
226 					chip->Channels[i] = (short)( PSGVolumeValues[chip->Registers[2 * i + 1]] * chip_t->IntermediatePos[i] );
227 				else
228 					/* Flat (no antialiasing needed) */
229 					chip->Channels[i]= PSGVolumeValues[chip->Registers[2 * i + 1]] * chip_t->ToneFreqPos[i];
230 			}
231 			else
232 				/* Muted channel */
233 				chip->Channels[i] = 0;
234 
235 		/* Noise channel */
236 		if ( (chip_t->Mute >> 3) & 1 )
237 		{
238 			//chip->Channels[3] = PSGVolumeValues[chip->Registers[7]] * ( chip_n->NoiseShiftRegister & 0x1 ) * 2; /* double noise volume */
239 			// Now the noise is bipolar, too. -Valley Bell
240 			chip->Channels[3] = PSGVolumeValues[chip->Registers[7]] * (( chip_n->NoiseShiftRegister & 0x1 ) * 2 - 1);
241 			// due to the way the white noise works here, it seems twice as loud as it should be
242 			if (chip->Registers[6] & 0x4 )
243 				chip->Channels[3] >>= 1;
244 		}
245 		else
246 			chip->Channels[i] = 0;
247 
248 		// Build stereo result into buffer
249 		buffer[0][j] = 0;
250 		buffer[1][j] = 0;
251 		if (! chip->NgpFlags)
252 		{
253 			// For all 4 channels
254 			for ( i = 0; i <= 3; ++i )
255 			{
256 				if ( ( ( chip->PSGStereo >> i ) & 0x11 ) == 0x11 )
257 				{
258 					// no GG stereo for this channel
259 					if ( chip->panning[i][0] == 1.0f )
260 					{
261 						buffer[0][j] += chip->Channels[i]; // left
262 						buffer[1][j] += chip->Channels[i]; // right
263 					}
264 					else
265 					{
266 						buffer[0][j] += (INT32)( chip->panning[i][0] * chip->Channels[i] ); // left
267 						buffer[1][j] += (INT32)( chip->panning[i][1] * chip->Channels[i] ); // right
268 					}
269 				}
270 				else
271 				{
272 					// GG stereo overrides panning
273 					buffer[0][j] += ( chip->PSGStereo >> (i+4) & 0x1 ) * chip->Channels[i]; // left
274 					buffer[1][j] += ( chip->PSGStereo >>  i    & 0x1 ) * chip->Channels[i]; // right
275 				}
276 			}
277 		}
278 		else
279 		{
280 			if (! (chip->NgpFlags & 0x01))
281 			{
282 				// For all 3 tone channels
283 				for (i = 0; i < 3; i ++)
284 				{
285 					buffer[0][j] += (chip->PSGStereo >> (i+4) & 0x1 ) * chip ->Channels[i]; // left
286 					buffer[1][j] += (chip->PSGStereo >>  i    & 0x1 ) * chip2->Channels[i]; // right
287 				}
288 			}
289 			else
290 			{
291 				// noise channel
292 				i = 3;
293 				buffer[0][j] += (chip->PSGStereo >> (i+4) & 0x1 ) * chip2->Channels[i]; // left
294 				buffer[1][j] += (chip->PSGStereo >>  i    & 0x1 ) * chip ->Channels[i]; // right
295 			}
296 		}
297 
298 		/* Increment clock by 1 sample length */
299 		chip->Clock += chip->dClock;
300 		chip->NumClocksForSample = (int)chip->Clock;  /* truncate */
301 		chip->Clock -= chip->NumClocksForSample;      /* remove integer part */
302 
303 		/* Decrement tone channel counters */
304 		for ( i = 0; i <= 2; ++i )
305 			chip->ToneFreqVals[i] -= chip->NumClocksForSample;
306 
307 		/* Noise channel: match to tone2 or decrement its counter */
308 		if ( chip->NoiseFreq == 0x80 )
309 			chip->ToneFreqVals[3] = chip->ToneFreqVals[2];
310 		else
311 			chip->ToneFreqVals[3] -= chip->NumClocksForSample;
312 
313 		/* Tone channels: */
314 		for ( i = 0; i <= 2; ++i ) {
315 			if ( chip->ToneFreqVals[i] <= 0 ) {   /* If the counter gets below 0... */
316 				if (chip->Registers[i*2]>=PSG_CUTOFF) {
317 					/* For tone-generating values, calculate how much of the sample is + and how much is - */
318 					/* This is optimised into an even more confusing state than it was in the first place... */
319 					chip->IntermediatePos[i] = ( chip->NumClocksForSample - chip->Clock + 2 * chip->ToneFreqVals[i] ) * chip->ToneFreqPos[i] / ( chip->NumClocksForSample + chip->Clock );
320 					/* Flip the flip-flop */
321 					chip->ToneFreqPos[i] = -chip->ToneFreqPos[i];
322 				} else {
323 					/* stuck value */
324 					chip->ToneFreqPos[i] = 1;
325 					chip->IntermediatePos[i] = FLT_MIN;
326 				}
327 				chip->ToneFreqVals[i] += chip->Registers[i*2] * ( chip->NumClocksForSample / chip->Registers[i*2] + 1 );
328 			}
329 			else
330 				/* signal no antialiasing needed */
331 				chip->IntermediatePos[i] = FLT_MIN;
332 		}
333 
334 		/* Noise channel */
335 		if ( chip->ToneFreqVals[3] <= 0 ) {
336 			/* If the counter gets below 0... */
337 			/* Flip the flip-flop */
338 			chip->ToneFreqPos[3] = -chip->ToneFreqPos[3];
339 			if (chip->NoiseFreq != 0x80)
340 				/* If not matching tone2, decrement counter */
341 				chip->ToneFreqVals[3] += chip->NoiseFreq * ( chip->NumClocksForSample / chip->NoiseFreq + 1 );
342 			if (chip->ToneFreqPos[3] == 1) {
343 				/* On the positive edge of the square wave (only once per cycle) */
344 				int Feedback;
345 				if ( chip->Registers[6] & 0x4 ) {
346 					/* White noise */
347 					/* Calculate parity of fed-back bits for feedback */
348 					switch (chip->WhiteNoiseFeedback) {
349 						/* Do some optimised calculations for common (known) feedback values */
350 					case 0x0003: /* SC-3000, BBC %00000011 */
351 					case 0x0009: /* SMS, GG, MD  %00001001 */
352 						/* If two bits fed back, I can do Feedback=(nsr & fb) && (nsr & fb ^ fb) */
353 						/* since that's (one or more bits set) && (not all bits set) */
354 						Feedback = ( ( chip->NoiseShiftRegister & chip->WhiteNoiseFeedback )
355 							&& ( (chip->NoiseShiftRegister & chip->WhiteNoiseFeedback ) ^ chip->WhiteNoiseFeedback ) );
356 						break;
357 					default:
358 						/* Default handler for all other feedback values */
359 						/* XOR fold bits into the final bit */
360 						Feedback = chip->NoiseShiftRegister & chip->WhiteNoiseFeedback;
361 						Feedback ^= Feedback >> 8;
362 						Feedback ^= Feedback >> 4;
363 						Feedback ^= Feedback >> 2;
364 						Feedback ^= Feedback >> 1;
365 						Feedback &= 1;
366 						break;
367 					}
368 				} else	  /* Periodic noise */
369 					Feedback=chip->NoiseShiftRegister&1;
370 
371 				chip->NoiseShiftRegister=(chip->NoiseShiftRegister>>1) | (Feedback << (chip->SRWidth-1));
372 			}
373 		}
374 	}
375 }
376 
377 /*void SN76489_UpdateOne(SN76489_Context* chip, int *l, int *r)
378 {
379   INT16 tl,tr;
380   INT16 *buff[2] = { &tl, &tr };
381   SN76489_Update( chip, buff, 1 );
382   *l = tl;
383   *r = tr;
384 }*/
385 
386 
387 /*int  SN76489_GetMute(SN76489_Context* chip)
388 {
389   return chip->Mute;
390 }*/
391 
SN76489_SetMute(SN76489_Context * chip,int val)392 void SN76489_SetMute(SN76489_Context* chip, int val)
393 {
394   chip->Mute=val;
395 }
396 
SN76489_SetPanning(SN76489_Context * chip,int ch0,int ch1,int ch2,int ch3)397 void SN76489_SetPanning(SN76489_Context* chip, int ch0, int ch1, int ch2, int ch3)
398 {
399 	calc_panning( chip->panning[0], ch0 );
400 	calc_panning( chip->panning[1], ch1 );
401 	calc_panning( chip->panning[2], ch2 );
402 	calc_panning( chip->panning[3], ch3 );
403 }
404