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