1 // license:BSD-3-Clause
2 // copyright-holders:Derrick Renaud
3 /************************************************************************
4  * m79amb Sound System Analog emulation
5  * Nov 2008, Derrick Renaud
6  ************************************************************************/
7 
8 #include "emu.h"
9 #include "includes/m79amb.h"
10 #include "sound/discrete.h"
11 
12 #define TIME_OF_9602(r, c)              (0.34 * (r) * (c) * (1.0 + 1.0 / (r)))
13 #define TIME_OF_9602_WITH_DIODE(r, c)   (0.3  * (r) * (c))
14 
15 
16 /* Discrete Sound Input Nodes */
17 #define M79AMB_BOOM_EN                  NODE_01
18 #define M79AMB_THUD_EN                  NODE_02
19 #define M79AMB_SHOT_EN                  NODE_03
20 #define M79AMB_MC_REV_EN                NODE_04
21 #define M79AMB_MC_CONTROL_EN            NODE_05
22 #define M79AMB_TANK_TRUCK_JEEP_EN       NODE_06
23 #define M79AMB_WHISTLE_A_EN             NODE_07
24 #define M79AMB_WHISTLE_B_EN             NODE_08
25 
26 /* Discrete Sound Output Nodes */
27 #define M79AMB_BOOM_SND                 NODE_11
28 #define M79AMB_THUD_SND                 NODE_12
29 #define M79AMB_SHOT_SND                 NODE_13
30 #define M79AMB_MC_SND                   NODE_14
31 #define M79AMB_TANK_TRUCK_JEEP_SND      NODE_15
32 #define M79AMB_WHISTLE_A_SND            NODE_16
33 #define M79AMB_WHISTLE_B_SND            NODE_17
34 
35 /* Parts List - Resistors */
36 #define M79AMB_R2       RES_K(5.6)
37 #define M79AMB_R6       220
38 #define M79AMB_R9       RES_K(4.7)
39 #define M79AMB_R10      RES_K(2.2)
40 #define M79AMB_R12      RES_K(5.6)
41 #define M79AMB_R16      330
42 #define M79AMB_R19      RES_K(4.7)
43 #define M79AMB_R20      RES_K(2.2)
44 #define M79AMB_R22      RES_K(3.3)
45 #define M79AMB_R26      100
46 #define M79AMB_R29      RES_K(4.7)
47 #define M79AMB_R30      RES_K(1.5)
48 #define M79AMB_R35      RES_K(470)
49 #define M79AMB_R36      RES_K(39)
50 #define M79AMB_R37      RES_K(82)
51 #define M79AMB_R38      100
52 #define M79AMB_R39      RES_K(10)
53 #define M79AMB_R41      RES_K(2.2)
54 #define M79AMB_R42      RES_K(10)
55 #define M79AMB_R43      220
56 #define M79AMB_R44      RES_K(39)
57 #define M79AMB_R45      RES_K(82)
58 #define M79AMB_R46      RES_K(10)
59 #define M79AMB_R48      RES_K(2.2)
60 #define M79AMB_R49      RES_K(1)
61 #define M79AMB_R51      RES_K(39)
62 #define M79AMB_R52      RES_K(82)
63 #define M79AMB_R53      100
64 #define M79AMB_R54      RES_K(10)
65 #define M79AMB_R57      RES_K(2.2)
66 #define M79AMB_R58      RES_K(2.2)
67 #define M79AMB_R59      RES_K(1)
68 #define M79AMB_R61      RES_K(39)
69 #define M79AMB_R62      RES_K(82)
70 #define M79AMB_R63      100
71 #define M79AMB_R64      RES_K(10)
72 #define M79AMB_R67      RES_K(2.2)
73 #define M79AMB_R68      RES_K(2.2)
74 #define M79AMB_R69      RES_K(1)
75 #define M79AMB_R76      RES_K(2.7)
76 #define M79AMB_R77      RES_K(47)
77 #define M79AMB_R78      RES_K(47)
78 #define M79AMB_R79      RES_K(15)
79 #define M79AMB_R80      RES_K(22)
80 #define M79AMB_R81      RES_K(100)
81 #define M79AMB_R82      RES_K(100)
82 #define M79AMB_R83      RES_K(3.3)
83 #define M79AMB_R84      RES_K(50)
84 #define M79AMB_R86      470
85 
86 /* Parts List - Capacitors */
87 #define M79AMB_C2       CAP_U(39)
88 #define M79AMB_C3       CAP_U(22)
89 #define M79AMB_C6       CAP_U(0.1)
90 #define M79AMB_C8       CAP_U(39)
91 #define M79AMB_C9       CAP_U(22)
92 #define M79AMB_C12      CAP_U(0.1)
93 #define M79AMB_C14      CAP_U(4.7)
94 #define M79AMB_C15      CAP_U(3.3)
95 #define M79AMB_C18      CAP_U(0.1)
96 #define M79AMB_C20      CAP_U(2.2)
97 #define M79AMB_C21      CAP_U(1)
98 #define M79AMB_C22      CAP_U(22)
99 #define M79AMB_C23      CAP_U(0.01)
100 #define M79AMB_C25      CAP_U(2.2)
101 #define M79AMB_C26      CAP_U(22)
102 #define M79AMB_C27      CAP_U(0.47)
103 #define M79AMB_C28      CAP_U(0.1)
104 #define M79AMB_C29      CAP_U(22)
105 #define M79AMB_C30      CAP_U(0.03)
106 #define M79AMB_C31      CAP_U(0.1)
107 #define M79AMB_C32      CAP_U(0.1)
108 #define M79AMB_C33      CAP_U(22)
109 #define M79AMB_C34      CAP_U(0.03)
110 #define M79AMB_C35      CAP_U(0.1)
111 #define M79AMB_C36      CAP_U(0.1)
112 #define M79AMB_C37      CAP_P(500)
113 #define M79AMB_C41      CAP_U(0.1)
114 #define M79AMB_C42      CAP_U(15)
115 
116 
117 static const discrete_mixer_desc m79amb_final_mix =
118 {
119 	DISC_MIXER_IS_OP_AMP,
120 	{
121 		M79AMB_R76 + M79AMB_R9,
122 		M79AMB_R77 + M79AMB_R19,
123 		M79AMB_R78 + M79AMB_R29,
124 		M79AMB_R79 + RES_2_PARALLEL(M79AMB_R41, M79AMB_R42 + M79AMB_R43),
125 		M79AMB_R80 + RES_2_PARALLEL(M79AMB_R48, M79AMB_R49),
126 		M79AMB_R81 + RES_2_PARALLEL(M79AMB_R59, M79AMB_R57 + M79AMB_R58),
127 		M79AMB_R82 + RES_2_PARALLEL(M79AMB_R69, M79AMB_R67 + M79AMB_R68)
128 	},
129 	{0},                /* no r_nodes */
130 	{M79AMB_C6, M79AMB_C12, M79AMB_C18, M79AMB_C23, M79AMB_C28, M79AMB_C32, M79AMB_C36},
131 	0,
132 	M79AMB_R83 + M79AMB_R84,
133 	M79AMB_C37,
134 	M79AMB_C42,
135 	0,
136 	1               /* gain */
137 };
138 
139 DISCRETE_SOUND_START( m79amb_discrete )
140 	/************************************************
141 	 * Input register mapping
142 	 ************************************************/
143 	DISCRETE_INPUT_PULSE(M79AMB_BOOM_EN, 0)
144 	DISCRETE_INPUT_PULSE(M79AMB_THUD_EN, 0)
145 	DISCRETE_INPUT_PULSE(M79AMB_SHOT_EN, 0)
DISCRETE_INPUT_LOGIC(M79AMB_MC_REV_EN)146 	DISCRETE_INPUT_LOGIC(M79AMB_MC_REV_EN)
147 	DISCRETE_INPUT_LOGIC(M79AMB_MC_CONTROL_EN)
148 	DISCRETE_INPUT_LOGIC(M79AMB_TANK_TRUCK_JEEP_EN)
149 	DISCRETE_INPUT_LOGIC(M79AMB_WHISTLE_A_EN)
150 	DISCRETE_INPUT_LOGIC(M79AMB_WHISTLE_B_EN)
151 
152 	/* Boom, Thud, Shot sounds need more accurate emulation */
153 
154 	/************************************************
155 	 * Boom
156 	 ************************************************/
157 	DISCRETE_ONESHOT(NODE_20,
158 				M79AMB_BOOM_EN,             /* TRIG */
159 				1,                          /* AMPL */
160 				TIME_OF_9602_WITH_DIODE(M79AMB_R2, M79AMB_C2),
161 				DISC_ONESHOT_REDGE | DISC_ONESHOT_RETRIG | DISC_OUT_ACTIVE_HIGH)
162 	DISCRETE_RCDISC2(NODE_21,
163 				NODE_20,                    /* Q1 base */
164 				0,                          /* Q1 off, C3 discharges */
165 				M79AMB_R9 + M79AMB_R10,     /* discharges through amp/filter circuit */
166 				12,                         /* Q1 on, C3 charges */
167 				M79AMB_R6,                  /* Q2 on  */
168 				M79AMB_C3)                  /* controls amplitude */
169 	DISCRETE_NOISE(M79AMB_BOOM_SND,
170 				1,                          /* ENAB */
171 				800,                        /* FREQ - Guess*/
172 				NODE_21,                    /* AMP  */
173 				0)                          /* BIAS - fake AC is fine*/
174 
175 	/************************************************
176 	 * Thud
177 	 ************************************************/
178 	DISCRETE_ONESHOT(NODE_30,
179 				M79AMB_THUD_EN,         /* TRIG */
180 				1,                      /* AMPL */
181 				TIME_OF_9602_WITH_DIODE(M79AMB_R12, M79AMB_C8),
182 				DISC_ONESHOT_REDGE | DISC_ONESHOT_RETRIG | DISC_OUT_ACTIVE_HIGH)
183 	DISCRETE_RCDISC2(NODE_31,
184 				NODE_30,                    /* Q4 base */
185 				0,                          /* Q4 off, C9 discharges */
186 				M79AMB_R19 + M79AMB_R20,    /* discharges through amp/filter circuit */
187 				12,                         /* Q4 on, C9 charges */
188 				M79AMB_R16,                 /* Q5 on  */
189 				M79AMB_C9)                  /* controls amplitude */
190 	DISCRETE_NOISE(M79AMB_THUD_SND,
191 				1,                          /* ENAB */
192 				500,                        /* FREQ - Guess*/
193 				NODE_31,                    /* AMP  */
194 				0)                          /* BIAS - fake AC is fine*/
195 
196 	/************************************************
197 	 * Shot
198 	 ************************************************/
199 	DISCRETE_ONESHOT(NODE_40,
200 				M79AMB_SHOT_EN,         /* TRIG */
201 				1,                      /* AMPL */
202 				TIME_OF_9602_WITH_DIODE(M79AMB_R22, M79AMB_C14),
203 				DISC_ONESHOT_REDGE | DISC_ONESHOT_RETRIG | DISC_OUT_ACTIVE_HIGH)
204 	DISCRETE_RCDISC2(NODE_41,
205 				NODE_40,                    /* Q7 base */
206 				0,                          /* Q7 off, C15 discharges */
207 				M79AMB_R29 + M79AMB_R30,    /* discharges through amp/filter circuit */
208 				12,                         /* Q7 on, C15 charges */
209 				M79AMB_R26,                 /* Q8 on  */
210 				M79AMB_C15)                 /* controls amplitude */
211 	DISCRETE_NOISE(M79AMB_SHOT_SND,
212 				1,                          /* ENAB */
213 				1000,                       /* FREQ - Guess*/
214 				NODE_41,                    /* AMP  */
215 				0)                          /* BIAS - fake AC is fine*/
216 
217 	/************************************************
218 	 * MC
219 	 ************************************************/
220 	/* not the best implementation of the pin 5 charge circuit, but it is within tolerance */
221 	DISCRETE_RCDISC2(NODE_50,
222 				M79AMB_MC_REV_EN,
223 				/* R35 can be ignored on discharge */
224 				RES_VOLTAGE_DIVIDER(M79AMB_R36 + M79AMB_R37, M79AMB_R38) * 12,  /* Q12 on  */
225 				RES_2_PARALLEL(M79AMB_R36 + M79AMB_R37, M79AMB_R38),            /* Q12 on  */
226 				12.0 * RES_VOLTAGE_DIVIDER(M79AMB_R36, M79AMB_R35),             /* Q12 off */
227 				RES_2_PARALLEL(M79AMB_R36, M79AMB_R35) + M79AMB_R37,            /* Q12 off */
228 				M79AMB_C20)
229 	/* cap charge to B+ ratio changes voltage on pin 5 */
230 	/* (iR36 + iR35 + iR37) * R36||R35||R37 where iR35 = 0/R35 = 0 */
231 	DISCRETE_TRANSFORM4(NODE_51, 12.0 / M79AMB_R36, NODE_50, M79AMB_R37, RES_3_PARALLEL(M79AMB_R36, M79AMB_R35, M79AMB_R37), "012/+3*")
232 	DISCRETE_566(NODE_52,                   /* IC U3, pin 4 */
233 				NODE_51,                    /* IC U3, pin 5 */
234 				M79AMB_R39, M79AMB_C21,
235 				12, 0, 12,                  /* VPOS,VNEG,VCHARGE */
236 				DISC_566_OUT_DC | DISC_566_OUT_TRIANGLE)
237 	DISCRETE_CRFILTER(NODE_53,
238 				NODE_52, M79AMB_R41 + M79AMB_R42 + M79AMB_R43, M79AMB_C22)
239 	DISCRETE_MULTIPLY(NODE_54, NODE_53, M79AMB_MC_CONTROL_EN)
240 	DISCRETE_GAIN(M79AMB_MC_SND, NODE_54, RES_VOLTAGE_DIVIDER(M79AMB_R41 + M79AMB_R42, 2200))//M79AMB_R43))
241 
242 	/************************************************
243 	 * Tank, Truck, Jeep
244 	 ************************************************/
245 	DISCRETE_566(NODE_60,                       /* IC U4, pin 4 */
246 				12.0 * RES_VOLTAGE_DIVIDER(M79AMB_R44, M79AMB_R45),     /* IC U5, pin 5 */
247 				M79AMB_R46, M79AMB_C25,
248 				12, 0, 12,                  /* VPOS,VNEG,VCHARGE */
249 				DISC_566_OUT_DC | DISC_566_OUT_TRIANGLE)
250 	DISCRETE_ONOFF(NODE_61,
251 				M79AMB_TANK_TRUCK_JEEP_EN,      /* Q16, Q17 */
252 				NODE_60)
253 	DISCRETE_CRFILTER(NODE_62,
254 				NODE_61, M79AMB_R48 + M79AMB_R49, M79AMB_C26)
255 	DISCRETE_GAIN(NODE_63, NODE_62, RES_VOLTAGE_DIVIDER(M79AMB_R48, M79AMB_R49))
256 	DISCRETE_RCFILTER(M79AMB_TANK_TRUCK_JEEP_SND,
257 				NODE_63, RES_2_PARALLEL(M79AMB_R48, M79AMB_R49), M79AMB_C27)
258 
259 	/************************************************
260 	 * Whisle A
261 	 ************************************************/
262 	DISCRETE_RCDISC2(NODE_70,
263 				M79AMB_WHISTLE_A_EN,
264 				RES_VOLTAGE_DIVIDER(M79AMB_R51 + M79AMB_R52, M79AMB_R53) * 12,  /* Q15 on  */
265 				RES_2_PARALLEL(M79AMB_R53, M79AMB_R51 + M79AMB_R52),            /* Q15 on  */
266 				12, M79AMB_R51 + M79AMB_R52,                                    /* Q15 off */
267 				M79AMB_C29)
268 	/* cap charge to B+ ratio changes voltage on pin 5 */
269 	DISCRETE_TRANSFORM3(NODE_71, 12, NODE_70, RES_VOLTAGE_DIVIDER(M79AMB_R51, M79AMB_R52), "01-2*1+")
270 	DISCRETE_566(NODE_72,                   /* IC U5, pin 4 */
271 				NODE_71,                    /* IC U5, pin 5 */
272 				M79AMB_R54, M79AMB_C30,
273 				12, 0, 12,                  /* VPOS,VNEG,VCHARGE */
274 				DISC_566_OUT_DC | DISC_566_OUT_TRIANGLE)
275 	DISCRETE_CRFILTER(NODE_73,
276 				NODE_72, M79AMB_R57 + M79AMB_R58 + M79AMB_R59, M79AMB_C31)
277 	DISCRETE_MULTIPLY(NODE_74, NODE_73, M79AMB_WHISTLE_A_EN) /* Q16, Q17 */
278 	DISCRETE_GAIN(M79AMB_WHISTLE_A_SND, NODE_74, RES_VOLTAGE_DIVIDER(M79AMB_R57 + M79AMB_R58, M79AMB_R59))
279 
280 	/************************************************
281 	 * Whisle B
282 	 ************************************************/
283 	DISCRETE_RCDISC2(NODE_80,
284 				M79AMB_WHISTLE_B_EN,
285 				RES_VOLTAGE_DIVIDER(M79AMB_R61 + M79AMB_R62, M79AMB_R63) * 12,  /* Q18 on  */
286 				RES_2_PARALLEL(M79AMB_R63, M79AMB_R61 + M79AMB_R62),            /* Q18 on  */
287 				12, M79AMB_R61 + M79AMB_R62,                                    /* Q18 off */
288 				M79AMB_C33)
289 	/* cap charge to B+ ratio changes voltage on pin 5 */
290 	DISCRETE_TRANSFORM3(NODE_81, 12, NODE_80, RES_VOLTAGE_DIVIDER(M79AMB_R61, M79AMB_R62), "01-2*1+")
291 	DISCRETE_566(NODE_82,                   /* IC U5, pin 4 */
292 				NODE_81,                    /* IC U5, pin 5 */
293 				M79AMB_R64, M79AMB_C34,
294 				12, 0, 12,                  /* VPOS,VNEG,VCHARGE */
295 				DISC_566_OUT_DC | DISC_566_OUT_TRIANGLE)
296 	DISCRETE_CRFILTER(NODE_83,
297 				NODE_82, M79AMB_R67 + M79AMB_R68 + M79AMB_R69, M79AMB_C35)
298 	DISCRETE_MULTIPLY(NODE_84, NODE_83, M79AMB_WHISTLE_B_EN) /* Q19, Q20*/
299 	DISCRETE_GAIN(M79AMB_WHISTLE_B_SND, NODE_84, RES_VOLTAGE_DIVIDER(M79AMB_R67 + M79AMB_R68, M79AMB_R69))
300 
301 	/************************************************
302 	 * Mixer
303 	 ************************************************/
304 	DISCRETE_MIXER7(NODE_90,                /* IC U7, pin 6 */
305 				1,                          /* ENAB */
306 				M79AMB_BOOM_SND,
307 				M79AMB_THUD_SND,
308 				M79AMB_SHOT_SND,
309 				M79AMB_MC_SND,
310 				M79AMB_TANK_TRUCK_JEEP_SND,
311 				M79AMB_WHISTLE_A_SND,
312 				M79AMB_WHISTLE_B_SND,
313 				&m79amb_final_mix)
314 	DISCRETE_RCFILTER(NODE_91,
315 				NODE_90, M79AMB_R86, M79AMB_C41)
316 
317 	DISCRETE_OUTPUT(NODE_91, 32000.0/5)
318 
319 DISCRETE_SOUND_END
320 
321 
322 /* the ports are guessed from operation */
323 /* the schematics do not show the actual hookup */
324 
325 void m79amb_state::m79amb_8000_w(uint8_t data)
326 {
327 	/* these values are not latched */
328 	/* they are pulsed when the port is addressed */
329 	/* the discrete system will just trigger from them */
330 	m_discrete->write(M79AMB_SHOT_EN, data & 0x01);
331 	m_discrete->write(M79AMB_BOOM_EN, data & 0x02);
332 	m_discrete->write(M79AMB_THUD_EN, data & 0x04);
333 }
334 
m79amb_8003_w(uint8_t data)335 void m79amb_state::m79amb_8003_w(uint8_t data)
336 {
337 	/* Self Test goes low on reset and lights LED */
338 	/* LED goes off on pass */
339 	m_self_test = BIT(data, 0);
340 	m_discrete->write(M79AMB_MC_REV_EN, data & 0x02);
341 	m_discrete->write(M79AMB_MC_CONTROL_EN, data & 0x04);
342 	m_discrete->write(M79AMB_TANK_TRUCK_JEEP_EN, data & 0x08);
343 	m_discrete->write(M79AMB_WHISTLE_B_EN, data & 0x10);
344 	m_discrete->write(M79AMB_WHISTLE_A_EN, data & 0x20);
345 }
346