1 // license:BSD-3-Clause
2 // copyright-holders:Derrick Renaud
3 /************************************************************************
4  * copsnrob Sound System Analog emulation
5  * Nov 2010, Derrick Renaud
6  ************************************************************************/
7 #include "emu.h"
8 #include "includes/copsnrob.h"
9 #include "sound/discrete.h"
10 #include "speaker.h"
11 
12 
13 /* Discrete Sound Input Nodes */
14 #define COPSNROB_MOTOR0_INV         NODE_01
15 #define COPSNROB_MOTOR1_INV         NODE_02
16 #define COPSNROB_MOTOR2_INV         NODE_03
17 #define COPSNROB_MOTOR3_INV         NODE_04
18 #define COPSNROB_ZINGS_INV          NODE_05
19 #define COPSNROB_FIRES_INV          NODE_06
20 #define COPSNROB_CRASH_INV          NODE_07
21 #define COPSNROB_SCREECH_INV        NODE_08
22 #define COPSNROB_AUDIO_ENABLE       NODE_09
23 
24 /* Discrete Sound Output Nodes */
25 #define COPSNROB_MOTOR0_SND         NODE_11
26 #define COPSNROB_MOTOR1_SND         NODE_12
27 #define COPSNROB_MOTOR2_SND         NODE_13
28 #define COPSNROB_MOTOR3_SND         NODE_14
29 #define COPSNROB_FZ_SND             NODE_15
30 #define COPSNROB_CRASH_SND          NODE_16
31 #define COPSNROB_SCREECH_SND        NODE_17
32 #define COPSNROB_NOISE_1            NODE_18
33 #define COPSNROB_NOISE_2            NODE_18_01
34 
35 /* Parts List - Resistors */
36 #define COPSNROB_R16            RES_K(10)
37 #define COPSNROB_R18            RES_K(100)
38 #define COPSNROB_R19            RES_K(100)
39 #define COPSNROB_R20            RES_K(100)
40 #define COPSNROB_R21            RES_K(47)
41 #define COPSNROB_R25            RES_K(47)
42 #define COPSNROB_R26            RES_K(150)
43 #define COPSNROB_R27            RES_K(22)
44 #define COPSNROB_R28            RES_K(18)
45 #define COPSNROB_R33            RES_K(10)
46 #define COPSNROB_R35            RES_K(10)
47 #define COPSNROB_R36            RES_K(15)
48 #define COPSNROB_R37            RES_K(4.7)
49 #define COPSNROB_R38            RES_K(15)
50 #define COPSNROB_R39            RES_K(10)
51 #define COPSNROB_R41            RES_K(33)
52 #define COPSNROB_R42            RES_K(33)
53 #define COPSNROB_R47            RES_K(10)
54 #define COPSNROB_R48            RES_K(1)
55 #define COPSNROB_R49            RES_K(47)
56 #define COPSNROB_R50            RES_K(47)
57 #define COPSNROB_R53            RES_K(47)
58 #define COPSNROB_R54            RES_K(22)
59 #define COPSNROB_R55            RES_K(47)
60 #define COPSNROB_R56            RES_K(470)
61 #define COPSNROB_R57            RES_K(820)
62 #define COPSNROB_R58            RES_K(68)
63 #define COPSNROB_R59            RES_K(1)
64 #define COPSNROB_R64            RES_K(47)
65 #define COPSNROB_R65            RES_K(4.7)
66 #define COPSNROB_R66            RES_K(1.5)
67 #define COPSNROB_R69            RES_K(330)
68 #define COPSNROB_R70            RES_K(330)
69 #define COPSNROB_R71            RES_K(100)
70 #define COPSNROB_R72            RES_K(100)
71 #define COPSNROB_R73            RES_K(47)
72 #define COPSNROB_R74            RES_K(1)
73 #define COPSNROB_R75            RES_K(1)
74 #define COPSNROB_R76            RES_K(12)
75 #define COPSNROB_R77            RES_K(33)
76 #define COPSNROB_R78            RES_K(100)
77 #define COPSNROB_R79            RES_K(2.2)
78 #define COPSNROB_R80            RES_K(1)
79 #define COPSNROB_R81            RES_K(8.2)
80 #define COPSNROB_R82            RES_K(3.9)
81 #define COPSNROB_R83            RES_K(27)
82 #define COPSNROB_R84            RES_K(15)
83 #define COPSNROB_R85            (330)
84 #define COPSNROB_R86            RES_K(330)
85 #define COPSNROB_R87            (820)
86 #define COPSNROB_R88            RES_K(1)
87 #define COPSNROB_R89            RES_K(1)
88 #define COPSNROB_R92            RES_K(100)
89 #define COPSNROB_R93            RES_K(100)
90 #define COPSNROB_R94            RES_K(10)
91 
92 /* Parts List - Capacitors */
93 #define COPSNROB_C3             CAP_U(100)
94 #define COPSNROB_C12            CAP_U(0.1)
95 #define COPSNROB_C13            CAP_U(0.1)
96 #define COPSNROB_C17            CAP_U(0.001)
97 #define COPSNROB_C19            CAP_U(10)
98 #define COPSNROB_C20            CAP_U(0.01)
99 #define COPSNROB_C23            CAP_U(0.1)
100 #define COPSNROB_C24            CAP_U(0.22)
101 #define COPSNROB_C28            CAP_U(1)
102 #define COPSNROB_C30            CAP_U(0.01)
103 #define COPSNROB_C31            CAP_U(0.1)
104 #define COPSNROB_C32            CAP_U(5)
105 #define COPSNROB_C33            CAP_U(10)
106 #define COPSNROB_C36            CAP_U(100)
107 #define COPSNROB_C39            CAP_U(0.1)
108 #define COPSNROB_C37            CAP_U(0.1)
109 #define COPSNROB_C40            CAP_U(0.1)
110 #define COPSNROB_C41            CAP_U(0.03)
111 #define COPSNROB_C42            CAP_U(0.047)
112 #define COPSNROB_C43            CAP_U(0.047)
113 #define COPSNROB_C55            CAP_U(0.1)
114 #define COPSNROB_C58            CAP_U(0.1)
115 #define COPSNROB_C59            CAP_U(0.1)
116 
117 /* Timing values */
118 #define COPSNROB_2V             (15750/2/2) /* has to be verified */
119 
120 
121 static const discrete_555_desc copsnrob_motor23_555_1 =
122 {
123 	DISC_555_OUT_SQW,
124 	5, DEFAULT_555_VALUES
125 };
126 
127 static const discrete_555_desc copsnrob_motor23_555_2 =
128 {
129 	DISC_555_OUT_ENERGY | DISC_555_TRIGGER_IS_VOLTAGE,
130 	5, DEFAULT_555_VALUES
131 };
132 
133 static const discrete_op_amp_filt_info copsnrob_motor23_filter =
134 {
135 	COPSNROB_R28, 0, COPSNROB_R87, 0, COPSNROB_R86,                 /* r1, r2, r3, r4, rF */
136 	COPSNROB_C42, COPSNROB_C43, 0,                                  /* c1, c2, c3 */
137 	5.0 * RES_VOLTAGE_DIVIDER(COPSNROB_R88, COPSNROB_R89), 5, 0     /* vRef, vP, vN */
138 };
139 
140 static const discrete_dac_r1_ladder copsnrob_crash_dac =
141 {
142 	4,                                                      /* ladderLength */
143 	{COPSNROB_R81, COPSNROB_R82, COPSNROB_R79, COPSNROB_R80},
144 	0, 0, 0, COPSNROB_C58                                   /* vBias, rBias, rGnd, cFilter */
145 };
146 
147 static const discrete_mixer_desc copsnrob_final_mixer01 =
148 {
149 	DISC_MIXER_IS_RESISTOR,
150 	{COPSNROB_R21, COPSNROB_R25, COPSNROB_R33, COPSNROB_R70, COPSNROB_R71},
151 	{0}, {0}, 0, COPSNROB_R35, 0, COPSNROB_C59,             /* r_node{}, c{}, rI, rF, cF, cAmp */
152 	0, 1                                                    /* vRef, gain */
153 };
154 
155 static const discrete_dac_r1_ladder copsnrob_motor01_cc_dac =
156 {
157 	1,                                      /* ladderLength */
158 	{COPSNROB_R56},
159 	5.0 - 0.5, COPSNROB_R58, COPSNROB_R57, COPSNROB_C33 /* vBias; rBias; rGnd; cFilter */
160 };
161 
162 static const discrete_dac_r1_ladder copsnrob_motor01_out_dac =
163 {
164 	4,                                      /* ladderLength */
165 	{COPSNROB_R20, COPSNROB_R18, 0, COPSNROB_R19},
166 	0, 0, 0, COPSNROB_C12                   /* vBias; rBias; rGnd; cFilter */
167 };
168 
169 static const discrete_mixer_desc copsnrob_final_mixer23 =
170 {
171 	DISC_MIXER_IS_RESISTOR,
172 	{COPSNROB_R93, COPSNROB_R92, COPSNROB_R72, COPSNROB_R69, COPSNROB_R16},
173 	{0}, {0}, 0, COPSNROB_R94, 0, COPSNROB_C55,             /* r_node{}, c{}, rI, rF, cF, cAmp */
174 	0, 1                                                    /* vRef, gain */
175 };
176 
177 static const discrete_dac_r1_ladder copsnrob_motor23_cv_dac =
178 {
179 	1,                                      /* ladderLength */
180 	{COPSNROB_R65},
181 	5, RES_K(5), RES_K(10), COPSNROB_C36    /* vBias; rBias; rGnd; cFilter */
182 };
183 
184 static const discrete_555_cc_desc copsnrob_motor01_555cc =
185 {
186 	DISC_555_OUT_COUNT_R | DISCRETE_555_CC_TO_DISCHARGE_PIN,
187 	5,                          /* v_pos */
188 	DEFAULT_555_CC_SOURCE,
189 	1,                          /* v_out_high - ignored */
190 	0.6                         /* v_cc_junction */
191 };
192 
193 
194 #define COPSNROB_MOTOR01_BASE_NODE      NODE_20
195 #define COPSNROB_MOTOR23_BASE_NODE      NODE_30
196 #define COPSNROB_NODE(_base, _num, _offset)     NODE_RELATIVE(_base, _num * 100 + _offset)
197 #define COPSNROB_MOTOR01_NODE(_num, _offset)    COPSNROB_NODE(COPSNROB_MOTOR01_BASE_NODE, _num, _offset)
198 #define COPSNROB_MOTOR23_NODE(_num, _offset)    COPSNROB_NODE(COPSNROB_MOTOR23_BASE_NODE, _num, _offset)
199 
200 
201 /************************************************
202  * MOTOR0/1 Definition Start
203  ************************************************/
204 #define COPSNROB_MOTOR01(_output, _input, _num)                                                 \
205 		/* simulate the RC connected to the transistor with a DAC */                                \
206 	DISCRETE_DAC_R1(COPSNROB_MOTOR01_NODE(_num, 0),                                             \
207 		_input, 4.2, &copsnrob_motor01_cc_dac)                      /* DATA; VDATA - TTL with light load */     \
208 	DISCRETE_555_CC(COPSNROB_MOTOR01_NODE(_num, 1),                 /* IC F2, pin 10 from IC F3, pin 9 */       \
209 		1,                                                          /* RESET - IC F3, pin 10 */     \
210 		COPSNROB_MOTOR01_NODE(_num, 0),                             /* VIN */                       \
211 		COPSNROB_R53, COPSNROB_C20, 0, 0, COPSNROB_R39,             /* R; C; RBIAS; RGND; RDIS */   \
212 		&copsnrob_motor01_555cc)                                                                \
213 	/* IC D2, pin 12 and IC E3, pin 5 make a /4 counter */                                      \
214 	DISCRETE_COUNTER(COPSNROB_MOTOR01_NODE(_num, 2),                /* IC E3, pin 5 */          \
215 		1, 0,                                                       /* ENAB; RESET */           \
216 		COPSNROB_MOTOR01_NODE(_num, 1),                             /* IC D2, pin 1 */          \
217 		0, 3, DISC_COUNT_UP, 0, DISC_CLK_BY_COUNT)                  /* MIN; MAX; DIR; INIT0; CLKTYPE */ \
218 	DISCRETE_COUNTER_7492(COPSNROB_MOTOR01_NODE(_num, 3),           /* IC E3, pins 11, 9, & 8 */\
219 		1, 0,                                                       /* ENAB; RESET */           \
220 		COPSNROB_MOTOR01_NODE(_num, 1),                             /* IC E3, pin 14 */         \
221 		DISC_CLK_BY_COUNT)                                          /* CLKTYPE */               \
222 	DISCRETE_TRANSFORM3(COPSNROB_MOTOR01_NODE(_num, 4),                                         \
223 		COPSNROB_MOTOR01_NODE(_num, 2),                             /* INP0 */                  \
224 		COPSNROB_MOTOR01_NODE(_num, 3), 2,                          /* INP1, INP2 */            \
225 		"02&2/12*+")                                                /* get bits ready for DAC */\
226 	DISCRETE_DAC_R1(_output,                                                                    \
227 		COPSNROB_MOTOR01_NODE(_num, 4), 4.2, &copsnrob_motor01_out_dac)     /* DATA; VDATA - TTL with light load */
228 
229 /************************************************
230  * MOTOR0/1 Definition Start
231  ************************************************/
232 
233 
234 /************************************************
235  * MOTOR2/3 Definition Start
236  ************************************************/
237 #define COPSNROB_MOTOR23(_output, _input, _num)                                                 \
238 		/* simulate the RC connected to the 555 CV pin with a DAC */                                \
239 	DISCRETE_DAC_R1(COPSNROB_MOTOR23_NODE(_num, 0),                                             \
240 		_input, 4.2, &copsnrob_motor23_cv_dac)                      /* DATA; VDATA - TTL with light load */     \
241 	DISCRETE_555_ASTABLE_CV(COPSNROB_MOTOR23_NODE(_num, 1),         /* IC J2, pin 5 */          \
242 		1,                                                          /* RESET */                 \
243 		COPSNROB_R64, COPSNROB_R42, COPSNROB_C24,                                               \
244 		COPSNROB_MOTOR23_NODE(_num, 0),                             /* CTRLV - IC J2, pin 3 */  \
245 		&copsnrob_motor23_555_1)                                                                \
246 	DISCRETE_CRFILTER_VREF(COPSNROB_MOTOR23_NODE(_num, 2),                                      \
247 		COPSNROB_MOTOR23_NODE(_num, 1),                                 /* IN0 */               \
248 		RES_3_PARALLEL(COPSNROB_R27, RES_K(10), RES_K(5)), COPSNROB_C17,    /* R is in parallel with 555 internal R */  \
249 		5.0 * RES_VOLTAGE_DIVIDER(RES_2_PARALLEL(COPSNROB_R27, RES_K(10)), RES_K(5)))   /* VREF */  \
250 	DISCRETE_555_MSTABLE(COPSNROB_MOTOR23_NODE(_num, 3),            /* IC J3, pin 9 */          \
251 		1,                                                          /* RESET */                 \
252 		COPSNROB_MOTOR23_NODE(_num, 2),                             /* IC J3, pin 8 */          \
253 		COPSNROB_R41, COPSNROB_C23,                                                             \
254 		&copsnrob_motor23_555_2)                                                                \
255 	DISCRETE_OP_AMP_FILTER(_output,                                 /* IC L4, pin 7 */          \
256 		1,                                                          /* ENAB */                  \
257 		COPSNROB_MOTOR23_NODE(_num, 3), 0,                          /* INP0; INP1 */            \
258 		DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &copsnrob_motor23_filter)
259 /************************************************
260  * MOTOR2/3 Definition End
261  ************************************************/
262 
263 
264 /************************************************
265  * CUSTOM_NOISE Definition Start
266  * - output is energy
267  ************************************************/
268 #define COPSNROB_CUSTOM_NOISE__FREQ     DISCRETE_INPUT(0)
269 
270 DISCRETE_CLASS_STEP_RESET(copsnrob_custom_noise, 2,
271 	int     m_flip_flop;
272 	int     m_noise1_had_xtime;
273 	int     m_noise2_had_xtime;
274 	uint8_t   m_high_byte;
275 	uint8_t   m_low_byte;
276 	double  m_t_used;
277 	double  m_t1;
278 );
279 
280 #define COPSNROB_CUSTOM_NOISE_HIGH  4.2
281 
DISCRETE_STEP(copsnrob_custom_noise)282 DISCRETE_STEP(copsnrob_custom_noise)
283 {
284 	double  t_used = m_t_used;
285 	double  t1 = m_t1;
286 	double  x_time = 0;
287 	uint8_t   low_byte = m_low_byte;
288 	uint8_t   high_byte = m_high_byte;
289 	uint8_t   xnor_out;                           /* IC F2, pin 2 */
290 	int     last_noise1_bit = (low_byte >> 4) & 0x01;
291 	int     last_noise2_bit = (low_byte >> 5) & 0x01;
292 
293 	t_used += this->sample_time();
294 
295 	/* This clock will never run faster then the sample rate,
296 	 * so we do not bother to check.
297 	 */
298 	if (t_used > t1)
299 	{
300 		/* calculate the overshoot time */
301 		t_used -= t1;
302 		m_flip_flop ^= 1;
303 		/* clocks on low to high */
304 		if (m_flip_flop)
305 		{
306 			int new_noise_bit;
307 
308 			/* shift */
309 			xnor_out = (((low_byte >> 6) & 0x01) ^ (high_byte & 0x01)) ^ 0x01;
310 			low_byte = (low_byte << 1) | ((high_byte >> 7) & 0x01);
311 			high_byte = (high_byte << 1) | xnor_out;
312 			if (high_byte == 0xff)      /* IC H1, pin 8 */
313 				high_byte = 0;
314 			m_low_byte = low_byte;
315 			m_high_byte = high_byte;
316 
317 			/* Convert last switch time to a ratio */
318 			x_time = t_used / this->sample_time();
319 			/* use x_time if bit changed */
320 			new_noise_bit = (low_byte >> 4) & 0x01;
321 			if (last_noise1_bit != new_noise_bit)
322 			{
323 				set_output(0,  COPSNROB_CUSTOM_NOISE_HIGH * (new_noise_bit ? x_time : (1.0 - x_time)));
324 				m_noise1_had_xtime = 1;
325 			}
326 			new_noise_bit = (low_byte >> 5) & 0x01;
327 			if (last_noise2_bit != new_noise_bit)
328 			{
329 				set_output(1, COPSNROB_CUSTOM_NOISE_HIGH * (new_noise_bit ? x_time : (1.0 - x_time)));
330 				m_noise2_had_xtime = 1;
331 			}
332 		}
333 	}
334 	else
335 	{
336 		/* see if we need to move from x_time state to full state */
337 		if (m_noise1_had_xtime)
338 		{
339 			set_output(0, COPSNROB_CUSTOM_NOISE_HIGH * last_noise1_bit);
340 			m_noise1_had_xtime = 0;
341 		}
342 		if (m_noise2_had_xtime)
343 		{
344 			set_output(1, COPSNROB_CUSTOM_NOISE_HIGH * last_noise2_bit);
345 			m_noise2_had_xtime = 0;
346 		}
347 	}
348 
349 	m_t_used = t_used;
350 }
351 
DISCRETE_RESET(copsnrob_custom_noise)352 DISCRETE_RESET(copsnrob_custom_noise)
353 {
354 	m_t1 = 0.5 / COPSNROB_CUSTOM_NOISE__FREQ ;
355 	m_flip_flop = 0;
356 	m_low_byte = 0;
357 	m_high_byte = 0;
358 	m_noise1_had_xtime = 0;
359 	m_noise2_had_xtime = 0;
360 	m_t_used = 0;
361 }
362 
363 /************************************************
364  * CUSTOM_NOISE Definition End
365  ************************************************/
366 
367 
368 /************************************************
369  * CUSTOM_ZINGS_555_MONOSTABLE Definition Start
370  * - output is energy
371  ************************************************/
372 #define COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__TRIG  DISCRETE_INPUT(0)
373 #define COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__R     DISCRETE_INPUT(1)
374 #define COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__C     DISCRETE_INPUT(2)
375 
376 DISCRETE_CLASS_STEP_RESET(copsnrob_zings_555_monostable, 1,
377 	double  m_rc;
378 	double  m_exponent;
379 	double  m_v_cap;
380 	int     m_flip_flop;
381 );
382 
DISCRETE_STEP(copsnrob_zings_555_monostable)383 DISCRETE_STEP(copsnrob_zings_555_monostable)
384 {
385 	const double v_threshold = 5.0 * 2 / 3;
386 	const double v_out_high = 5.0 - 0.5;    /* light load */
387 
388 	int     ff_set = COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__TRIG < (5.0 / 3) ? 1 : 0;
389 	int     flip_flop = m_flip_flop;
390 	double  v_cap = m_v_cap;
391 	double  x_time = 0;
392 
393 	/* From testing a real IC */
394 	/* Trigger going low overides everything.  It forces the FF/Output high.
395 	 * If Threshold is high, the output will still go high as long as trigger is low.
396 	 * The output will then go low when trigger rises above it's 1/3VCC value.
397 	 * If threshold is below it's 2/3VCC value, the output will remain high.
398 	 */
399 	if (ff_set)
400 	{
401 		flip_flop = 1;
402 		m_flip_flop = flip_flop;
403 	}
404 
405 	if (flip_flop)
406 	{
407 		double  v_diff = v_out_high - v_cap;
408 
409 		/* charge */
410 		v_cap += v_diff * m_exponent;
411 		/* no state change if trigger is low */
412 		if (!ff_set && (v_cap > v_threshold))
413 		{
414 			double rc = m_rc;
415 
416 			flip_flop = 0;
417 			m_flip_flop = flip_flop;
418 			/* calculate overshoot */
419 			x_time = rc * log(1.0 / (1.0 - ((v_cap - v_threshold) / v_diff)));
420 			/* discharge the overshoot */
421 			v_cap = v_threshold;
422 			v_cap -= v_cap * RC_CHARGE_EXP_DT(rc, x_time);
423 			x_time /= this->sample_time();
424 		}
425 	}
426 	else
427 	{
428 		/* Optimization - already discharged */
429 		if (v_cap == 0)
430 			return;
431 		/* discharge */
432 		v_cap -= v_cap * m_exponent;
433 		/* Optimization - close enough to 0 to be 0 */
434 		if (v_cap < 0.000001)
435 			v_cap = 0;
436 	}
437 	m_v_cap = v_cap;
438 
439 	if (x_time > 0)
440 		set_output(0, v_out_high * x_time);
441 	else if (flip_flop)
442 		set_output(0, v_out_high);
443 	else
444 		set_output(0, 0.0);
445 }
446 
DISCRETE_RESET(copsnrob_zings_555_monostable)447 DISCRETE_RESET(copsnrob_zings_555_monostable)
448 {
449 	m_rc = COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__R * COPSNROB_CUSTOM_ZINGS_555_MONOSTABLE__C;
450 	m_exponent = RC_CHARGE_EXP(m_rc);
451 	m_v_cap = 0;
452 	m_flip_flop = 0;
453 	set_output(0, 0.0);
454 }
455 
456 /************************************************
457  * CUSTOM_ZINGS_555_MONOSTABLE Definition End
458  ************************************************/
459 
460 
461 /************************************************
462  * CUSTOM_ZINGS_555_ASTABLE Definition Start
463  * - output is energy
464  ************************************************/
465 #define COPSNROB_CUSTOM_ZINGS_555_ASTABLE__RESET    DISCRETE_INPUT(0)
466 #define COPSNROB_CUSTOM_ZINGS_555_ASTABLE__R1       DISCRETE_INPUT(1)
467 #define COPSNROB_CUSTOM_ZINGS_555_ASTABLE__R2       DISCRETE_INPUT(2)
468 #define COPSNROB_CUSTOM_ZINGS_555_ASTABLE__C1       DISCRETE_INPUT(3)
469 #define COPSNROB_CUSTOM_ZINGS_555_ASTABLE__C2       DISCRETE_INPUT(4)
470 
471 #define COPSNROB_CUSTOM_ZINGS_555_ASTABLE__HIGH     4.5
472 
473 DISCRETE_CLASS_STEP_RESET(copsnrob_zings_555_astable, 1,
474 	double  m_r2c2;
475 	double  m_r_total_cv;
476 	double  m_exponent1;
477 	double  m_exponent2;
478 	double  m_v_cap1;
479 	double  m_v_cap2;
480 	int     m_flip_flop;
481 );
482 
DISCRETE_STEP(copsnrob_zings_555_astable)483 DISCRETE_STEP(copsnrob_zings_555_astable)
484 {
485 	double  v_trigger, v_threshold;
486 	double  v1 = COPSNROB_CUSTOM_ZINGS_555_ASTABLE__RESET;
487 	double  v_cap1 = m_v_cap1;
488 	double  v_cap2 = m_v_cap2;
489 	double  dt = 0;
490 	int     reset_active = (v1 < 0.7) ? 1 : 0;
491 	int     flip_flop = m_flip_flop;
492 
493 	/* calculate voltage at CV pin */
494 	/* start by adding currents */
495 	double v_cv = 5.0 / RES_K(5);
496 	v_cv += v1 / COPSNROB_CUSTOM_ZINGS_555_ASTABLE__R1;
497 	/* convert to voltage */
498 	v_cv *= m_r_total_cv;
499 
500 	/* The reset voltage also charges the CV cap */
501 	double v_diff1 = v_cv - v_cap1;
502 	/* optimization - if charged close enough to voltage */
503 	if (fabs(v_diff1) < 0.000001)
504 		v_cap1 = v_cv;
505 	else
506 		v_cap1 += v_diff1 * m_exponent1;
507 	m_v_cap1 = v_cap1;
508 
509 	if (reset_active)
510 	{
511 		if (flip_flop)
512 			m_flip_flop = 0;
513 		/* we still need to discharge C2 */
514 		/* Optimization - only discharge if needed */
515 		if (v_cap2 != 0)
516 		{
517 			/* discharge */
518 			v_cap2 -= v_cap2 * m_exponent2;
519 			/* Optimization - close enough to 0 to be 0 */
520 			if (v_cap2 < 0.000001)
521 				set_output(0, 0.0);
522 			else
523 				set_output(0, v_cap2);
524 		}
525 		return;
526 	}
527 
528 	v_threshold = v_cap1 * 2 / 3;
529 	v_trigger = v_cap1 / 3;
530 
531 	/* This oscillator will never create a frequency greater then 1/2 the sample rate,
532 	 * so we won't worry about missing samples */
533 	/* No need to optimize the charge circuit.  It always charges/discharges to a voltage
534 	 * greater then it will ever reach. */
535 	if (flip_flop)
536 	{
537 		/* charge */
538 		double v_diff2 = COPSNROB_CUSTOM_ZINGS_555_ASTABLE__HIGH - v_cap2;
539 		v_cap2 += v_diff2 * m_exponent2;
540 		if (v_cap2 > v_threshold)
541 		{
542 			double r2c2 = m_r2c2;
543 
544 			m_flip_flop = 0;
545 			/* calculate overshoot */
546 			dt = r2c2 * log(1.0 / (1.0 - ((v_cap2 - v_threshold) / v_diff2)));
547 			/* discharge the overshoot */
548 			v_cap2 = v_threshold;
549 			v_cap2 -= v_cap2 * RC_CHARGE_EXP_DT(r2c2, dt);
550 		}
551 	}
552 	else
553 	{
554 		/* discharge */
555 		double v_diff2 = v_cap2;
556 		v_cap2 -= v_diff2 * m_exponent2;
557 		if (v_cap2 < v_trigger)
558 		{
559 			double r2c2 = m_r2c2;
560 
561 			m_flip_flop = 1;
562 			/* calculate overshoot */
563 			dt = r2c2 * log(1.0 / (1.0 - ((v_trigger - v_cap2) / v_diff2)));
564 			/* charge the overshoot */
565 			v_cap2 = v_trigger;
566 			v_cap2 += (COPSNROB_CUSTOM_ZINGS_555_ASTABLE__HIGH - v_cap2) * RC_CHARGE_EXP_DT(r2c2, dt);
567 		}
568 	}
569 	if (v_cap2 > 0)
570 		m_v_cap2 = v_cap2;
571 	else
572 		m_v_cap2 = 0.0;
573 	set_output(0, m_v_cap2);
574 }
575 
DISCRETE_RESET(copsnrob_zings_555_astable)576 DISCRETE_RESET(copsnrob_zings_555_astable)
577 {
578 	m_r_total_cv = RES_3_PARALLEL(COPSNROB_CUSTOM_ZINGS_555_ASTABLE__R1, RES_K(10), RES_K(5));
579 	m_r2c2 = COPSNROB_CUSTOM_ZINGS_555_ASTABLE__R2 * COPSNROB_CUSTOM_ZINGS_555_ASTABLE__C2;
580 	m_exponent1 = RC_CHARGE_EXP(COPSNROB_CUSTOM_ZINGS_555_ASTABLE__R1 * COPSNROB_CUSTOM_ZINGS_555_ASTABLE__C1);
581 	m_exponent2 = RC_CHARGE_EXP(m_r2c2);
582 	m_v_cap1 = 0;
583 	m_flip_flop = 0;
584 	m_v_cap2 = 0.0;     /* charge on C2 */
585 }
586 
587 
588 /************************************************
589  * CUSTOM_ZINGS_555_ASTABLE Definition End
590  ************************************************/
591 
592 
593 static DISCRETE_SOUND_START(copsnrob_discrete)
594 
595 	/************************************************
596 	 * Input register mapping
597 	 ************************************************/
DISCRETE_INPUT_LOGIC(COPSNROB_MOTOR0_INV)598 	DISCRETE_INPUT_LOGIC(COPSNROB_MOTOR0_INV)
599 	DISCRETE_INPUT_LOGIC(COPSNROB_MOTOR1_INV)
600 	DISCRETE_INPUT_LOGIC(COPSNROB_MOTOR2_INV)
601 	DISCRETE_INPUT_LOGIC(COPSNROB_MOTOR3_INV)
602 /* !! DISABLED UNTIL ADDRESS IS FOUND !! */
603 //  DISCRETE_INPUTX_LOGIC(COPSNROB_ZINGS_INV, 4, 0, 0)
604 //  DISCRETE_INPUT_LOGIC(COPSNROB_FIRES_INV)
605 	DISCRETE_INPUT_NOT(COPSNROB_CRASH_INV)                  /* inverted for counter use */
606 	DISCRETE_INPUT_LOGIC(COPSNROB_SCREECH_INV)
607 	DISCRETE_INPUT_NOT(COPSNROB_AUDIO_ENABLE)               /* IC A1, pins 2 & 12 */
608 
609 /* These inputs are disabled until their address triggers are determined.
610  * Then these constants can be removed.
611  */
612 	DISCRETE_CONSTANT(COPSNROB_ZINGS_INV, 4)    /* data bit will be normally high, when it goes low it triggers the one-shot which has a minimum on time of 0.2s */
613 	DISCRETE_CONSTANT(COPSNROB_FIRES_INV, 4)    /* data bit will be normally high */
614 
615 	/************************************************
616 	 * MOTOR0/1
617 	 ************************************************/
618 	COPSNROB_MOTOR01(COPSNROB_MOTOR0_SND, COPSNROB_MOTOR0_INV, 0)
619 	COPSNROB_MOTOR01(COPSNROB_MOTOR1_SND, COPSNROB_MOTOR1_INV, 1)
620 
621 	/************************************************
622 	 * MOTOR2/3
623 	 ************************************************/
624 	COPSNROB_MOTOR23(COPSNROB_MOTOR2_SND, COPSNROB_MOTOR2_INV, 0)
625 	COPSNROB_MOTOR23(COPSNROB_MOTOR3_SND, COPSNROB_MOTOR3_INV, 1)
626 
627 	/************************************************
628 	 * CRASH
629 	 ************************************************/
630 	DISCRETE_CUSTOM1(COPSNROB_NOISE_1,  copsnrob_custom_noise,                  /* IC J2, pin 10 */
631 		COPSNROB_2V,                                        /* CLK */
632 		nullptr)
633 	/* COPSNROB_NOISE_2 derived from sub out of above custom module - IC J2, pin 11 */
634 	/* We use the measured 555 timer frequency (IC M3) for speed */
635 	DISCRETE_COUNTER(NODE_40,                               /* IC L2 */
636 		NODE_41,                                            /* ENAB - IC L2, pin 14 */
637 		COPSNROB_CRASH_INV,                                 /* RESET - IC L2, pin 11 */
638 		92,                                                 /* IC L2, pin 4 - freq measured */
639 		0, 15, DISC_COUNT_DOWN, 15, DISC_CLK_IS_FREQ)       /* MIN; MAX; DIR; INIT0; CLKTYPE */
640 	DISCRETE_TRANSFORM2(NODE_41,                            /* IC M2, pin 3 - goes high at count 0 */
641 		NODE_40, 0, "01=!")                                 /* -we will invert it for use by the counter module */
642 	DISCRETE_SWITCH(NODE_42,                                /* IC L3 */
643 		1, COPSNROB_NOISE_2, 0, NODE_40)                    /* ENAB; SWITCH; INP0; INP1 */
644 	DISCRETE_DAC_R1(COPSNROB_CRASH_SND,
645 		NODE_42, 3.8,                                       /* DATA; VDATA */
646 		&copsnrob_crash_dac)
647 
648 	/************************************************
649 	 * SCREECH
650 	 ************************************************/
651 		DISCRETE_CONSTANT(COPSNROB_SCREECH_SND, 0)
652 
653 	/************************************************
654 	 * FZ (Fires, Zings)
655 	 ************************************************/
656 	DISCRETE_CUSTOM3(NODE_60, copsnrob_zings_555_monostable,                            /* IC D3, pin 5 */
657 		/* We can ignore R47 & R48 */
658 		COPSNROB_ZINGS_INV,                             /* IC D3, pin 6 */
659 		COPSNROB_R38, COPSNROB_C19,
660 		nullptr)
661 	DISCRETE_CUSTOM5(NODE_61, copsnrob_zings_555_astable,                           /* IC D3, pin 8 & 12 */
662 		NODE_60,                                        /* IC D3, pin 10 */
663 		COPSNROB_R36, COPSNROB_R37,
664 		COPSNROB_C3, COPSNROB_C13,
665 		nullptr)
666 	/* FIX - do a better implemetation of IC L4 */
667 	DISCRETE_CRFILTER_VREF(NODE_62,                     /* IC L4, pin 9 */
668 		NODE_61,                                        /* IN0 */
669 		COPSNROB_R26, COPSNROB_C39,
670 		5.0 * RES_VOLTAGE_DIVIDER(COPSNROB_R74, COPSNROB_R75))  /* VREF */
671 	DISCRETE_GAIN(COPSNROB_FZ_SND,                      /* IC L4, pin 8 */
672 		NODE_62,
673 		COPSNROB_R73 / COPSNROB_R26)
674 
675 	/************************************************
676 	 * MIXER
677 	 ************************************************/
678 		DISCRETE_MIXER5(NODE_90,                                /* IC B3, pin 3 */
679 		COPSNROB_AUDIO_ENABLE,                              /* ENAB */
680 		COPSNROB_MOTOR1_SND, COPSNROB_MOTOR0_SND, COPSNROB_FZ_SND, COPSNROB_SCREECH_SND, COPSNROB_CRASH_SND,
681 		&copsnrob_final_mixer01)
682 		DISCRETE_MIXER5(NODE_91,                                /* IC P3, pin 3 */
683 		COPSNROB_AUDIO_ENABLE,                              /* ENAB */
684 		COPSNROB_MOTOR3_SND, COPSNROB_MOTOR2_SND, COPSNROB_CRASH_SND, COPSNROB_SCREECH_SND, COPSNROB_FZ_SND,
685 		&copsnrob_final_mixer23)
686 		DISCRETE_OUTPUT(NODE_90, 32767.0*3.5)
687 		DISCRETE_OUTPUT(NODE_91, 32767.0*3.5)
688 DISCRETE_SOUND_END
689 
690 
691 WRITE_LINE_MEMBER(copsnrob_state::one_start_w)
692 {
693 	/* One Start */
694 	m_leds[0] = state ? 0 :1;
695 }
696 
697 
copsnrob_audio(machine_config & config)698 void copsnrob_state::copsnrob_audio(machine_config &config)
699 {
700 	/* sound hardware */
701 	SPEAKER(config, "lspeaker").front_left();
702 	SPEAKER(config, "rspeaker").front_right();
703 
704 	discrete_sound_device &discrete(DISCRETE(config, "discrete", copsnrob_discrete));
705 	discrete.add_route(0, "lspeaker", 1.0);
706 	discrete.add_route(1, "rspeaker", 1.0);
707 
708 	f9334_device &latch(F9334(config, "latch")); // H3 on audio board
709 	latch.q_out_cb<0>().set("discrete", FUNC(discrete_device::write_line<COPSNROB_MOTOR3_INV>));
710 	latch.q_out_cb<1>().set("discrete", FUNC(discrete_device::write_line<COPSNROB_MOTOR2_INV>));
711 	latch.q_out_cb<2>().set("discrete", FUNC(discrete_device::write_line<COPSNROB_MOTOR1_INV>));
712 	latch.q_out_cb<3>().set("discrete", FUNC(discrete_device::write_line<COPSNROB_MOTOR0_INV>));
713 	latch.q_out_cb<4>().set("discrete", FUNC(discrete_device::write_line<COPSNROB_SCREECH_INV>));
714 	latch.q_out_cb<5>().set("discrete", FUNC(discrete_device::write_line<COPSNROB_CRASH_INV>));
715 	latch.q_out_cb<6>().set(FUNC(copsnrob_state::one_start_w));
716 	latch.q_out_cb<7>().set("discrete", FUNC(discrete_device::write_line<COPSNROB_AUDIO_ENABLE>));
717 }
718