1 // license:BSD-3-Clause
2 // copyright-holders:Derrick Renaud
3 /************************************************************************
4  * skyraid Sound System Analog emulation
5  * Sept 2009, Derrick Renaud
6  ************************************************************************/
7 
8 #include "emu.h"
9 #include "includes/skyraid.h"
10 
11 
12 /* Discrete Sound Input Nodes */
13 #define SKYRAID_PLANE_SWEEP_EN      NODE_01
14 #define SKYRAID_MISSILE_EN          NODE_02
15 #define SKYRAID_EXPLOSION_EN        NODE_03
16 #define SKYRAID_PLANE_ON_EN         NODE_04
17 #define SKYRAID_PLANE_ON__IC_E8     SKYRAID_PLANE_ON_EN
18 #define SKYRAID_ATTRACT_EN          NODE_05
19 
20 /* Discrete Sound Output Nodes */
21 #define SKYRAID_NOISE               NODE_10
22 #define SKYRAID_EXPLOSION_SND       NODE_11
23 #define SKYRAID_JET_A_SND           NODE_12
24 #define SKYRAID_JET_B_SND           NODE_13
25 #define SKYRAID_MSL_A_SND           NODE_14
26 #define SKYRAID_MSL_B_SND           NODE_15
27 #define SKYRAID_PLANE_SND           NODE_16
28 
29 /* Parts List - Resistors */
30 #define SKYRAID_R12     RES_K(1)
31 #define SKYRAID_R13     RES_K(10)
32 #define SKYRAID_R14     RES_K(100)
33 #define SKYRAID_R16     RES_K(10)
34 #define SKYRAID_R18     RES_K(10)
35 #define SKYRAID_R19     RES_K(10)
36 #define SKYRAID_R20     RES_K(47)
37 #define SKYRAID_R24     RES_M(10)
38 #define SKYRAID_R25     RES_M(3.9)
39 #define SKYRAID_R27     RES_M(1.5)
40 #define SKYRAID_R28     RES_M(1.5)
41 #define SKYRAID_R29     RES_M(4.7)
42 #define SKYRAID_R30     RES_M(1)
43 #define SKYRAID_R31     RES_M(1)
44 #define SKYRAID_R32     RES_M(4.7)
45 #define SKYRAID_R84     RES_K(22)
46 #define SKYRAID_R85     RES_K(100)
47 #define SKYRAID_R86     820
48 #define SKYRAID_R110    RES_K(330)
49 #define SKYRAID_R118    RES_K(470)
50 #define SKYRAID_R119    RES_K(10)
51 #define SKYRAID_R120    RES_K(220)
52 #define SKYRAID_R121    RES_K(1)
53 #define SKYRAID_R122    RES_K(150)
54 
55 /* Parts List - Capacitors */
56 #define SKYRAID_C44     CAP_U(4.7)
57 #define SKYRAID_C45     CAP_U(.0047)
58 #define SKYRAID_C46     CAP_U(.001)
59 #define SKYRAID_C48     CAP_U(.0047)
60 #define SKYRAID_C49     CAP_U(.1)
61 #define SKYRAID_C50     CAP_U(.001)
62 #define SKYRAID_C51     CAP_U(.01)
63 #define SKYRAID_C68     CAP_U(10)
64 #define SKYRAID_C85     CAP_U(.068)
65 #define SKYRAID_C86     CAP_U(.1)
66 #define SKYRAID_C93     CAP_U(.1)
67 
68 
69 static const discrete_lfsr_desc skyraid_lfsr =
70 {
71 	DISC_CLK_IS_FREQ,
72 	16,                 /* Bit Length */
73 	0,                  /* Reset Value */
74 	0,                  /* Use Bit 0 as XOR input 0 */
75 	14,                 /* Use Bit 14 as XOR input 1 */
76 	DISC_LFSR_XNOR,     /* Feedback stage1 is XNOR */
77 	DISC_LFSR_OR,       /* Feedback stage2 is just stage 1 output OR with external feed */
78 	DISC_LFSR_REPLACE,  /* Feedback stage3 replaces the shifted register contents */
79 	0x000001,           /* Everything is shifted into the first bit only */
80 	DISC_LFSR_FLAG_RESET_TYPE_H,    /* Output is not inverted */
81 	15                  /* Output bit */
82 };
83 
84 static const discrete_op_amp_filt_info skyraid_explosion_filter =
85 {
86 	SKYRAID_R85, 0, SKYRAID_R86, 0, SKYRAID_R110,   /* r1, r2, r3, r4, rF*/
87 	SKYRAID_C85, SKYRAID_C86, 0,    /* c1, c2, c3 */
88 	0, 12, -5,  /* vRef, vP, vN */
89 };
90 
91 static const discrete_dac_r1_ladder skyraid_plane_dac =
92 {
93 	2, {SKYRAID_R28, SKYRAID_R27},
94 	0, 0, 0, 0              /* no vBias, rBias, rGnd, cFilter */
95 };
96 
97 static const discrete_mixer_desc skyraid_mixer =
98 {
99 	DISC_MIXER_IS_RESISTOR,
100 	{SKYRAID_R120, SKYRAID_R32, SKYRAID_R29, SKYRAID_R30, SKYRAID_R31, RES_2_PARALLEL(SKYRAID_R28, SKYRAID_R27)},
101 	{0, 0, 0, 0, 0, SKYRAID_PLANE_ON__IC_E8},   /* r_nodes */
102 	{0}, 0, 0, 0, 0, 0, 1       /* no c, rI, rF, cF, cAmp, vRef, gain */
103 };
104 
105 
106 /************************************************************************
107  *
108  * Custom skyraid missle charge
109  *
110  * input[0]    - In1 (Logic)
111  * input[1]    - R1
112  * input[2]    - R2
113  * input[3]    - R3
114  * input[4]    - C
115  *
116  *              12V            5V
117  *               v              v
118  *               |              |
119  *               Z             ---
120  *               Z R1           ^   1N914
121  *               Z             / \  Diode
122  *               |            -----
123  *               |              |
124  *               +--------------+
125  *               |              |
126  *              ---             Z
127  *              --- C           Z R2
128  *               |              Z
129  *               |              |
130  *               +--------------+----> Node Output
131  *               |
132  *               Z
133  *               Z R3
134  *         O.C.  Z
135  *          |\   |
136  *   In1 >--| o--+
137  *          |/
138  *
139  ************************************************************************/
140 #define SKYRAID_MISSLE_CUSTOM_IN1       DISCRETE_INPUT(0)
141 #define SKYRAID_MISSLE_CUSTOM_R1        DISCRETE_INPUT(1)
142 #define SKYRAID_MISSLE_CUSTOM_R2        DISCRETE_INPUT(2)
143 #define SKYRAID_MISSLE_CUSTOM_R3        DISCRETE_INPUT(3)
144 #define SKYRAID_MISSLE_CUSTOM_C         DISCRETE_INPUT(4)
145 
146 DISCRETE_CLASS_STEP_RESET(skyraid_missle_custom_charge, 2,
147 		double m_v_charge[2];
148 		double m_v_cap;
149 		double m_exp[2];
150 );
151 
152 /* the high charge is clamped by the diode to 0.7V above the 5V line */
153 #define SKYRAID_MISSLE_CHARGE_PLUS  (5.0 + 0.7)
154 
DISCRETE_STEP(skyraid_missle_custom_charge)155 DISCRETE_STEP( skyraid_missle_custom_charge )
156 {
157 	int in_1 = (SKYRAID_MISSLE_CUSTOM_IN1 == 0) ? 0 : 1;
158 
159 	/* charge/discharge cap */
160 	m_v_cap += (m_v_charge[in_1] - m_v_cap) * m_exp[in_1];
161 
162 	set_output(0,  SKYRAID_MISSLE_CHARGE_PLUS - m_v_cap);
163 }
164 
DISCRETE_RESET(skyraid_missle_custom_charge)165 DISCRETE_RESET( skyraid_missle_custom_charge )
166 {
167 	/* everything is based on the input to the O.C. inverter */
168 
169 	/* the charging voltage across the cap */
170 	m_v_charge[0] = 0;
171 	m_v_charge[1] = SKYRAID_MISSLE_CHARGE_PLUS * RES_VOLTAGE_DIVIDER(SKYRAID_MISSLE_CUSTOM_R1 + SKYRAID_MISSLE_CUSTOM_R2, SKYRAID_MISSLE_CUSTOM_R3);
172 	m_v_charge[1] = SKYRAID_MISSLE_CHARGE_PLUS - m_v_charge[1];
173 	m_v_cap = 0;
174 
175 	/* precalculate charging exponents */
176 	/* discharge cap */
177 	m_exp[0] = RC_CHARGE_EXP(SKYRAID_MISSLE_CUSTOM_R2 * SKYRAID_MISSLE_CUSTOM_C);
178 	/* charge cap */
179 	m_exp[1] = RC_CHARGE_EXP(RES_2_PARALLEL(SKYRAID_MISSLE_CUSTOM_R1 + SKYRAID_MISSLE_CUSTOM_R2, SKYRAID_MISSLE_CUSTOM_R3) * SKYRAID_MISSLE_CUSTOM_C);
180 
181 	/* starts at full voltage until cap starts charging */
182 	set_output(0,  SKYRAID_MISSLE_CHARGE_PLUS);
183 }
184 
185 
186 
187 DISCRETE_SOUND_START( skyraid_discrete )
188 	/************************************************
189 	 * Input register mapping
190 	 ************************************************/
191 	/* convert the PLANE_SWEEP line to voltage*/
192 	DISCRETE_INPUTX_LOGIC(SKYRAID_PLANE_SWEEP_EN, DEFAULT_TTL_V_LOGIC_1 * RES_VOLTAGE_DIVIDER(SKYRAID_R25, SKYRAID_R24), 0, 0)
DISCRETE_INPUT_LOGIC(SKYRAID_MISSILE_EN)193 	DISCRETE_INPUT_LOGIC(SKYRAID_MISSILE_EN)
194 	DISCRETE_INPUT_LOGIC(SKYRAID_EXPLOSION_EN)
195 	/* convert PLANE_ON into 4066 Ron value of 270 ohms @ 5V */
196 	DISCRETE_INPUTX_LOGIC(SKYRAID_PLANE_ON__IC_E8, 270, 0, 0)
197 	DISCRETE_INPUT_LOGIC(SKYRAID_ATTRACT_EN)
198 
199 	/************************************************
200 	 * Noise Generator, Explosion sound
201 	 ************************************************/
202 	/* Note: the noise reset is not emulated 100% accurate */
203 	/* According to the schematics, Attract only clears the lower 8 bits. */
204 	/* I may modify the noise module in the future to properly emulate this, */
205 	/* but you will never hear the difference. */
206 	/* It only wrong for 8 cycles of the 555 while no sound is being generated. */
207 	DISCRETE_LFSR_NOISE(SKYRAID_NOISE,          /* IC F7, pin 13 */
208 		1,                                      /* ENAB */
209 		SKYRAID_ATTRACT_EN,                     /* RESET */
210 		1.49 / ((SKYRAID_R20 + 2 * SKYRAID_R19) * SKYRAID_C51),     /* CLK - 555 astable source */
211 		1, 0, 0.5, &skyraid_lfsr)               /* AMPL, FEED, BIAS */
212 
213 	DISCRETE_LOGIC_NOR(NODE_20, SKYRAID_EXPLOSION_EN, SKYRAID_NOISE)
214 	DISCRETE_RC_CIRCUIT_1(NODE_21,
215 		SKYRAID_EXPLOSION_EN, NODE_20,          /* INP0, INP1 */
216 		RES_2_PARALLEL(SKYRAID_R84, SKYRAID_R85 + SKYRAID_R86), SKYRAID_C68)
217 	DISCRETE_OP_AMP_FILTER(NODE_22,
218 		1,                                      /* ENAB */
219 		NODE_21, 0,                             /* INP0, INP1 */
220 		DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &skyraid_explosion_filter)  /* TYPE,INFO */
221 	/* IC E10, pin 14 gain and clipping */
222 	DISCRETE_GAIN(NODE_23, NODE_22, SKYRAID_R119 / SKYRAID_R121 + 1)
223 	DISCRETE_CLAMP(SKYRAID_EXPLOSION_SND, NODE_23, -5, 12.0 - 1.5)
224 
225 	/************************************************
226 	 * Jet, Plane sound
227 	 ************************************************/
228 	DISCRETE_RCFILTER(NODE_30,              /* IC J6, pin 5 */
229 		SKYRAID_PLANE_SWEEP_EN,             /* IN0 */
230 		RES_2_PARALLEL(SKYRAID_R25, SKYRAID_R24), SKYRAID_C49)
231 	DISCRETE_566(NODE_31,                   /* IC J6, pin 3 */
232 		NODE_30,                            /* VMOD */
233 		SKYRAID_R18, SKYRAID_C48,
234 		5, -5, 5,                           /* VPOS,VNEG,VCHARGE */
235 		DISC_566_OUT_COUNT_R)
236 	DISCRETE_LOGIC_SHIFT(NODE_32,           /* IC H7, J7 output */
237 		SKYRAID_NOISE,                      /* IC H7, J7 pins 1 & 2 */
238 		1, NODE_31, 16,                     /* RESET, CLK, SIZE */
239 		DISC_LOGIC_SHIFT__RESET_L | DISC_LOGIC_SHIFT__LEFT | DISC_CLK_BY_COUNT)
240 	/* move bits together for ease of use */
241 	DISCRETE_TRANSFORM4(NODE_33, NODE_32, 1, 1 << 14, 2, "01&02/3&|")
242 	DISCRETE_DAC_R1(SKYRAID_PLANE_SND,
243 		NODE_33,                            /* DATA */
244 		DEFAULT_TTL_V_LOGIC_1, &skyraid_plane_dac)
245 	DISCRETE_BIT_DECODE(SKYRAID_JET_A_SND, NODE_32, 0, DEFAULT_TTL_V_LOGIC_1)   /* IC H7, pin 3 */
246 	DISCRETE_BIT_DECODE(SKYRAID_JET_B_SND, NODE_32, 15, DEFAULT_TTL_V_LOGIC_1)  /* IC J7, pin 13 */
247 
248 	/************************************************
249 	 * Missle sound
250 	 ************************************************/
251 	DISCRETE_CUSTOM5(NODE_40, skyraid_missle_custom_charge, SKYRAID_MISSILE_EN, SKYRAID_R12, SKYRAID_R14, SKYRAID_R13, SKYRAID_C44, nullptr)
252 	DISCRETE_566(NODE_41,                   /* IC K6, pin 3 */
253 		NODE_40,                            /* VMOD */
254 		SKYRAID_R16, SKYRAID_C45,
255 		5, -5, SKYRAID_MISSLE_CHARGE_PLUS,  /* VPOS,VNEG,VCHARGE */
256 		DISC_566_OUT_COUNT_R)
257 	DISCRETE_LOGIC_SHIFT(NODE_42,           /* IC K7, L7 output */
258 		SKYRAID_NOISE,                      /* IC K7, L7 pins 1 & 2 */
259 		1, NODE_41, 16,                     /* RESET, CLK, SIZE */
260 		DISC_LOGIC_SHIFT__RESET_L | DISC_LOGIC_SHIFT__LEFT | DISC_CLK_BY_COUNT)
261 	DISCRETE_BIT_DECODE(SKYRAID_MSL_A_SND, NODE_42, 0, DEFAULT_TTL_V_LOGIC_1)   /* IC K7, pin 3 */
262 	DISCRETE_BIT_DECODE(SKYRAID_MSL_B_SND, NODE_42, 15, DEFAULT_TTL_V_LOGIC_1)  /* IC L7, pin 13 */
263 
264 	/************************************************
265 	 * Final Mix
266 	 ************************************************/
267 	DISCRETE_LOGIC_INVERT(NODE_91, SKYRAID_ATTRACT_EN)
268 	DISCRETE_MIXER6(NODE_92,
269 		NODE_91,                /* ENAB */
270 		SKYRAID_EXPLOSION_SND,
271 		SKYRAID_JET_A_SND,
272 		SKYRAID_JET_B_SND,
273 		SKYRAID_MSL_A_SND,
274 		SKYRAID_MSL_B_SND,
275 		SKYRAID_PLANE_SND,
276 		&skyraid_mixer)
277 	DISCRETE_CRFILTER(NODE_93,
278 		NODE_92,                /* IN0 */
279 		SKYRAID_R122 + RES_6_PARALLEL(SKYRAID_R120, SKYRAID_R32, SKYRAID_R29, SKYRAID_R30, SKYRAID_R31, RES_2_PARALLEL(SKYRAID_R27, SKYRAID_R28)),
280 		SKYRAID_C93)
281 	/* IC E10, pin 1 gain and clipping */
282 	DISCRETE_GAIN(NODE_94, NODE_93, - SKYRAID_R118 / (SKYRAID_R122 + RES_5_PARALLEL(SKYRAID_R120, SKYRAID_R32, SKYRAID_R29, SKYRAID_R30, SKYRAID_R31)))
283 	DISCRETE_CLAMP(NODE_95, NODE_94, -5, 12.0 - 1.5)
284 	DISCRETE_OUTPUT(NODE_95, 32700.0/8)
285 DISCRETE_SOUND_END
286 
287 
288 void skyraid_state::skyraid_sound_w(uint8_t data)
289 {
290 	/* BIT0 => PLANE SWEEP */
291 	/* BIT1 => MISSILE     */
292 	/* BIT2 => EXPLOSION   */
293 	/* BIT3 => START LAMP  */
294 	/* BIT4 => PLANE ON    */
295 	/* BIT5 => ATTRACT     */
296 
297 	m_discrete->write(SKYRAID_PLANE_SWEEP_EN, data & 0x01);
298 	m_discrete->write(SKYRAID_MISSILE_EN, data & 0x02);
299 	m_discrete->write(SKYRAID_EXPLOSION_EN, data & 0x04);
300 	m_led = !BIT(data, 3);
301 	m_discrete->write(SKYRAID_PLANE_ON_EN, data & 0x10);
302 	m_discrete->write(SKYRAID_ATTRACT_EN, data & 0x20);
303 }
304