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