1 // license:BSD-3-Clause
2 // copyright-holders:Derrick Renaud
3 /************************************************************************
4  * madalien Sound System Analog emulation
5  * Aug 2008, Derrick Renaud
6  ************************************************************************/
7 
8 #include "emu.h"
9 #include "includes/madalien.h"
10 #include "sound/discrete.h"
11 
12 
13 /* Discrete Sound Input Nodes */
14 /* see also "madalien.h" */
15 #define MADALIEN_8910_PORTA_1       NODE_03
16 #define MADALIEN_8910_PORTA_2       NODE_04
17 #define MADALIEN_8910_PORTA_3       NODE_05
18 #define MADALIEN_8910_PORTA_4       NODE_06
19 #define MADALIEN_8910_PORTA_5       NODE_07
20 #define MADALIEN_8910_PORTA_6       NODE_08
21 #define MADALIEN_8910_PORTA_8       NODE_09
22 
23 #define MADALIEN_8910_PORTB_1       NODE_10
24 #define MADALIEN_8910_PORTB_23      NODE_11
25 #define MADALIEN_8910_PORTB_45      NODE_12
26 #define MADALIEN_8910_PORTB_6       NODE_13
27 #define MADALIEN_8910_PORTB_7       NODE_14
28 
29 #define MADALIEN_8910_PSG_A         NODE_15
30 #define MADALIEN_8910_PSG_B         NODE_16
31 #define MADALIEN_8910_PSG_C         NODE_17
32 
33 
34 static const discrete_op_amp_filt_info madalien_psg_a_filter =
35 {
36 	RES_K(1)+ 270, 0, RES_K(10), 0, RES_K(100), CAP_U(.1), CAP_U(.1), 0, 0, 5, -5
37 };
38 
39 static const discrete_op_amp_filt_info madalien_psg_c_filter =
40 {
41 	RES_K(1)+ 270, 0, RES_K(10), 0, RES_K(100), CAP_U(.068), CAP_U(.068), 0, 0, 5, -5
42 };
43 
44 static const discrete_mixer_desc madalien_psg_mix =
45 {
46 	DISC_MIXER_IS_RESISTOR,
47 	{RES_K(10), RES_K(10), RES_K(10)},
48 	{0}, {0}, 0, 0, 0, 0, 0, 1
49 };
50 
51 static const discrete_555_desc madalien_555_1f =
52 {
53 	// the 555 will clock a 74161, which counts on rising edges
54 	DISC_555_TRIGGER_IS_LOGIC | DISC_555_OUT_DC | DISC_555_OUT_COUNT_R_X,
55 	5.0-.5,     // B+ voltage of 555 - diode drop
56 	DEFAULT_555_VALUES
57 };
58 
59 static const discrete_555_desc madalien_555_1c =
60 {
61 	// the 555 will clock a 74161, which counts on rising edges
62 	DISC_555_TRIGGER_IS_LOGIC | DISC_555_OUT_DC | DISC_555_OUT_COUNT_R_X,
63 	5,      // B+ voltage of 555
64 	DEFAULT_555_VALUES
65 };
66 
67 static const discrete_555_desc madalien_555_1l =
68 {
69 	DISC_555_TRIGGER_IS_LOGIC | DISC_555_OUT_DC | DISC_555_OUT_CAP,
70 	5,      // B+ voltage of 555
71 	DEFAULT_555_VALUES
72 };
73 
74 static const discrete_comp_adder_table madalien_555_1f_r_select =
75 {
76 	DISC_COMP_P_RESISTOR, 0, 2,
77 	{RES_K(22+1), RES_K(15+1)}
78 };
79 
80 static const discrete_comp_adder_table madalien_effect_1b_vol_r =
81 {
82 	DISC_COMP_P_RESISTOR, 0, 2,
83 	{270, RES_K(22) + 270}
84 };
85 
86 static const discrete_dac_r1_ladder madalien_effect1a_dac =
87 {
88 	4,
89 	{RES_K(22), RES_K(22), 0, RES_K(22)},
90 	0, 0, 0, 0
91 };
92 
93 static const discrete_dac_r1_ladder madalien_effect1b_dac =
94 {
95 	2,
96 	{RES_K(22), RES_K(22)},
97 	0, 0, 0, 0
98 };
99 
100 static const discrete_dac_r1_ladder madalien_effect2_dac =
101 {
102 	4,
103 	{0, RES_K(33), RES_K(22), RES_K(33)},
104 	0, 0, 0, 0
105 };
106 
107 // resistor effect of 555 internal resistors at pin 5
108 static const discrete_mixer_desc madalien_555_1c_cv =
109 {
110 	DISC_MIXER_IS_RESISTOR,
111 	{RES_K(1.5), RES_K(5)},
112 	{0}, {0}, 0, RES_K(10), 0, 0, 0, 1
113 };
114 
115 static const discrete_mixer_desc madalien_final_mix =
116 {
117 	DISC_MIXER_IS_RESISTOR,
118 	{RES_K(10), RES_K(10)/3, RES_K(10), RES_K(10),
119 		RES_K(22) + RES_K(22)/3,
120 		RES_K(22) + RES_K(22) + RES_K(22)/2,
121 		RES_K(33) + 1.0 / (1.0/RES_K(33) + 1.0/RES_K(22) + 1.0/RES_K(33))},
122 	{MADALIEN_8910_PORTA_1, 0, MADALIEN_8910_PORTA_5, MADALIEN_8910_PORTA_8, MADALIEN_8910_PORTB_1, NODE_59, 0},
123 	{0}, 0,
124 	RES_K(100),
125 	0, CAP_U(1), 0,
126 	32768.0/DEFAULT_TTL_V_LOGIC_1   // final gain
127 };
128 
129 DISCRETE_SOUND_START( madalien_discrete )
130 	/************************************************
131 	 * Input register mapping
132 	 ************************************************/
133 	DISCRETE_INPUT_DATA(MADALIEN_8910_PORTA)
134 	DISCRETE_INPUT_DATA(MADALIEN_8910_PORTB)
135 
136 	/************************************************
137 	 * Convert to individual bits
138 	 ************************************************/
139 	// Port A is used to turn filtering on/off.
140 	// 1 - player shot, siren, music
141 	// turn bit into 4066 Ron value of 270 ohms @ 5V
142 	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTA_1, MADALIEN_8910_PORTA, 0x01, 270, "01&2*")
143 	// 2 - player explosion
144 	DISCRETE_TRANSFORM2(MADALIEN_8910_PORTA_2, MADALIEN_8910_PORTA, 0x02, "01&")
145 	// 3 - rub wall
146 	DISCRETE_TRANSFORM2(MADALIEN_8910_PORTA_3, MADALIEN_8910_PORTA, 0x04, "01&")
147 	// 4 - is it even triggered?
148 	DISCRETE_TRANSFORM2(MADALIEN_8910_PORTA_4, MADALIEN_8910_PORTA, 0x08, "01&")
149 	// 5 - siren, music (out of phase copy of 1 for echo effect)
150 	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTA_5, MADALIEN_8910_PORTA, 0x10, 270, "01&2*")
151 	// 6 - enemy explosions
152 	DISCRETE_TRANSFORM2(MADALIEN_8910_PORTA_6, MADALIEN_8910_PORTA, 0x20, "01&")
153 	// 8 - enemy spin, beep
154 	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTA_8, MADALIEN_8910_PORTA, 0x80, 270, "01&2*")
155 
156 	//Port B controls motor sounds
157 	// 1,2,3 - Player motor volume
158 	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTB_1,  MADALIEN_8910_PORTB, 0x01, 270, "01&2*")
159 	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTB_23, MADALIEN_8910_PORTB, 0x06, 2, "01&2/")
160 	// 4,5 - Player motor speed
161 	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTB_45, MADALIEN_8910_PORTB, 0x18, 8, "01&2/")
162 	// 6 - Enemy motor enable
163 	DISCRETE_TRANSFORM2(MADALIEN_8910_PORTB_6,  MADALIEN_8910_PORTB, 0x20, "01&")
164 	// 7 - Enemy motor speed
165 	// convert bit 7 to voltage level
166 	// 2 diodes reduce voltage by 1V.
167 	DISCRETE_TRANSFORM3(MADALIEN_8910_PORTB_7, MADALIEN_8910_PORTB, 0x40, (DEFAULT_TTL_V_LOGIC_1 - 1) / 0x40, "01&2*")
168 
169 	/************************************************
170 	 * PSG input streams
171 	 ************************************************/
172 	// AY-3-8910 PSG have a 1Vpp level
173 	DISCRETE_INPUTX_STREAM(MADALIEN_8910_PSG_A, 0, 2.0/32768, .250)
174 	DISCRETE_INPUTX_STREAM(MADALIEN_8910_PSG_B, 1, 2.0/32768, .250)
175 	DISCRETE_INPUTX_STREAM(MADALIEN_8910_PSG_C, 2, 2.0/32768, .250)
176 
177 	/************************************************
178 	 * AY-3-8910 filtering
179 	 ************************************************/
180 	// top op-amp
181 	DISCRETE_ONOFF(NODE_20, MADALIEN_8910_PORTA_2, MADALIEN_8910_PSG_A)
182 	DISCRETE_OP_AMP_FILTER(NODE_21, 1, NODE_20, 0, DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &madalien_psg_a_filter)
183 
184 	// middle op-amp
185 	// pin 3
186 	DISCRETE_MULTIPLY(NODE_30, MADALIEN_8910_PSG_B, RES_K(3.3)/(RES_K(3.3)+RES_K(3.3)))
187 	DISCRETE_ONOFF(NODE_31, MADALIEN_8910_PORTA_4, NODE_30)
188 	// pin 2
189 	DISCRETE_TRANSFORM3(NODE_32, MADALIEN_8910_PSG_A, NODE_30, -RES_K(10)/RES_K(3.3), "01-2*1+")
190 	// pin 1
191 	DISCRETE_SWITCH(NODE_33, 1, MADALIEN_8910_PORTA_3, NODE_31, NODE_32)
192 	DISCRETE_CLAMP(NODE_34, NODE_33, -5, 5.0-1.5)
193 
194 	// bottom op-amp
195 	DISCRETE_ONOFF(NODE_40, MADALIEN_8910_PORTA_6, MADALIEN_8910_PSG_B)
196 	DISCRETE_OP_AMP_FILTER(NODE_41, 1, NODE_40, 0, DISC_OP_AMP_FILTER_IS_BAND_PASS_1M, &madalien_psg_c_filter)
197 
198 	DISCRETE_MIXER3(NODE_48, 1, NODE_21, NODE_33, NODE_41, &madalien_psg_mix)
199 
200 	/************************************************
201 	 * Player motor
202 	 ************************************************/
203 	DISCRETE_555_ASTABLE(NODE_50,   // cap is buffered by op-amp 2D.
204 		1,                          // always enabled
205 		RES_K(4.7),
206 		RES_K(22),
207 		CAP_U(2.2),
208 		&madalien_555_1l)
209 	// The speed frequencies seem strange but the components have been GuruVerified
210 	// There is not much change in selected frequency.  99Hz, 110.6Hz, 124Hz
211 	DISCRETE_COMP_ADDER(NODE_51, MADALIEN_8910_PORTB_45, &madalien_555_1f_r_select)
212 	DISCRETE_555_ASTABLE_CV(NODE_52,    // IC 1F pin 3 out
213 		MADALIEN_8910_PORTB_45,         // enabled by gate O2 pin 13
214 		NODE_51,
215 		RES_K(10),                      // per actual board
216 		CAP_U(.22),
217 		NODE_50,                        // IC 1F pin 5 in
218 		&madalien_555_1f)
219 	// convert reset to active high for module use
220 	DISCRETE_LOGIC_INVERT(NODE_53, MADALIEN_8910_PORTB_45)
221 	DISCRETE_COUNTER(NODE_54, 1,
222 		NODE_53,                        // pin 7 in
223 		NODE_52,                        // pin 1 in
224 		0, 15, 1, 0, DISC_CLK_BY_COUNT) // 4-bit binary up counter
225 	DISCRETE_DAC_R1(NODE_55, NODE_54, DEFAULT_TTL_V_LOGIC_1, &madalien_effect1a_dac)
226 	DISCRETE_DAC_R1(NODE_56, NODE_54, DEFAULT_TTL_V_LOGIC_1, &madalien_effect1b_dac)
227 	DISCRETE_RCFILTER(NODE_57, NODE_56, RES_K(22)/2 + RES_K(22), CAP_U(.033))
228 	DISCRETE_COMP_ADDER(NODE_59, MADALIEN_8910_PORTB_23, &madalien_effect_1b_vol_r)
229 
230 	/************************************************
231 	 * Enemy motor
232 	 ************************************************/
233 	DISCRETE_CRFILTER(NODE_60, MADALIEN_8910_PORTB_7, RES_K(100), CAP_U(4.7))
234 	// 2 diodes clamp it positive.
235 	DISCRETE_CLAMP(NODE_62, NODE_60, 0, 12)
236 	// the 0.047uF cap to ground just removes real world spikes.
237 	// it does not have to be simulated.
238 	DISCRETE_MIXER2(NODE_64, 1, NODE_62, 5, &madalien_555_1c_cv)
239 	DISCRETE_555_ASTABLE_CV(NODE_65,    // IC 1C pin 3 out
240 		MADALIEN_8910_PORTB_6,
241 		RES_K(47),
242 		RES_K(22),
243 		CAP_U(.033),
244 		NODE_64,                        // IC 1C pin 5 in
245 		&madalien_555_1c)
246 	// convert reset to active high for module use
247 	DISCRETE_LOGIC_INVERT(NODE_66, MADALIEN_8910_PORTB_6)
248 	DISCRETE_COUNTER(NODE_67, 1,
249 		NODE_66,                        // pin 7 in
250 		NODE_65,                        // pin 1 in
251 		0, 15, 1, 0, DISC_CLK_BY_COUNT) // 4-bit binary up counter
252 	DISCRETE_DAC_R1(NODE_68, NODE_67, DEFAULT_TTL_V_LOGIC_1, &madalien_effect2_dac)
253 
254 	/************************************************
255 	 * Mixer
256 	 ************************************************/
257 	DISCRETE_MIXER7(NODE_90, 1, MADALIEN_8910_PSG_A, NODE_48, MADALIEN_8910_PSG_B, MADALIEN_8910_PSG_C, NODE_56, NODE_57, NODE_68, &madalien_final_mix)
258 
259 	DISCRETE_OUTPUT(NODE_90, 1.1)
260 
261 DISCRETE_SOUND_END
262