1 // license:BSD-3-Clause
2 // copyright-holders:Nicola Salmoria
3 /***************************************************************************
4
5 This code is used by the following module:
6
7 timeplt.cpp
8 pooyan.cpp
9 rallyx.cpp (for locomotn)
10 tutankhm.cpp
11 rocnrope.cpp
12
13 ***************************************************************************/
14
15 #include "emu.h"
16 #include "audio/timeplt.h"
17
18 #include "machine/gen_latch.h"
19 #include "speaker.h"
20
21
22 DEFINE_DEVICE_TYPE(TIMEPLT_AUDIO, timeplt_audio_device, "timplt_audio", "Time Pilot Audio")
23 DEFINE_DEVICE_TYPE(LOCOMOTN_AUDIO, locomotn_audio_device, "locomotn_audio", "Loco-Motion Audio")
24
timeplt_audio_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)25 timeplt_audio_device::timeplt_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
26 : timeplt_audio_device(mconfig, TIMEPLT_AUDIO, tag, owner, clock)
27 {
28 }
29
locomotn_audio_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)30 locomotn_audio_device::locomotn_audio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
31 : timeplt_audio_device(mconfig, LOCOMOTN_AUDIO, tag, owner, clock)
32 {
33 }
34
timeplt_audio_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)35 timeplt_audio_device::timeplt_audio_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
36 : device_t(mconfig, type, tag, owner, clock)
37 , m_soundcpu(*this, "tpsound")
38 , m_soundlatch(*this, "soundlatch")
39 , m_filter_0(*this, "filter.0.%u", 0)
40 , m_filter_1(*this, "filter.1.%u", 0)
41 , m_last_irq_state(0)
42 {
43 }
44
45 //-------------------------------------------------
46 // device_start - device-specific startup
47 //-------------------------------------------------
48
device_start()49 void timeplt_audio_device::device_start()
50 {
51 m_last_irq_state = 0;
52 save_item(NAME(m_last_irq_state));
53 }
54
55
56 /*************************************
57 *
58 * Sound timer
59 *
60 *************************************/
61
62 /* The timer clock which feeds the upper 4 bits of */
63 /* AY-3-8910 port A is based on the same clock */
64 /* feeding the sound CPU Z80. It is a divide by */
65 /* 5120, formed by a standard divide by 512, */
66 /* followed by a divide by 10 using a 4 bit */
67 /* bi-quinary count sequence. (See LS90 data sheet */
68 /* for an example). */
69 /* */
70 /* Bit 4 comes from the output of the divide by 1024 */
71 /* 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 */
72 /* Bit 5 comes from the QC output of the LS90 producing a sequence of */
73 /* 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 */
74 /* Bit 6 comes from the QD output of the LS90 producing a sequence of */
75 /* 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 */
76 /* Bit 7 comes from the QA output of the LS90 producing a sequence of */
77 /* 0, 0, 0, 0, 0, 1, 1, 1, 1, 1 */
78
portB_r()79 uint8_t timeplt_audio_device::portB_r()
80 {
81 static const int timeplt_timer[10] =
82 {
83 0x00, 0x10, 0x20, 0x30, 0x40, 0x90, 0xa0, 0xb0, 0xa0, 0xd0
84 };
85
86 return timeplt_timer[(m_soundcpu->total_cycles() / 512) % 10];
87 }
88
89
90
91 /*************************************
92 *
93 * Filter controls
94 *
95 *************************************/
96
set_filter(filter_rc_device & device,int data)97 void timeplt_audio_device::set_filter(filter_rc_device &device, int data)
98 {
99 int C = 0;
100
101 if (data & 1)
102 C += 220000; /* 220000pF = 0.220uF */
103 if (data & 2)
104 C += 47000; /* 47000pF = 0.047uF */
105
106 device.filter_rc_set_RC(filter_rc_device::LOWPASS, 1000, 5100, 0, CAP_P(C));
107 }
108
109
filter_w(offs_t offset,uint8_t data)110 void timeplt_audio_device::filter_w(offs_t offset, uint8_t data)
111 {
112 set_filter(*m_filter_1[0], (offset >> 0) & 3);
113 set_filter(*m_filter_1[1], (offset >> 2) & 3);
114 set_filter(*m_filter_1[2], (offset >> 4) & 3);
115 set_filter(*m_filter_0[0], (offset >> 6) & 3);
116 set_filter(*m_filter_0[1], (offset >> 8) & 3);
117 set_filter(*m_filter_0[2], (offset >> 10) & 3);
118 }
119
120
121
122 /*************************************
123 *
124 * External interfaces
125 *
126 *************************************/
127
sound_data_w(uint8_t data)128 void timeplt_audio_device::sound_data_w(uint8_t data)
129 {
130 m_soundlatch->write(data);
131 }
132
133
WRITE_LINE_MEMBER(timeplt_audio_device::sh_irqtrigger_w)134 WRITE_LINE_MEMBER(timeplt_audio_device::sh_irqtrigger_w)
135 {
136 if (m_last_irq_state == 0 && state)
137 {
138 /* setting bit 0 low then high triggers IRQ on the sound CPU */
139 m_soundcpu->set_input_line_and_vector(0, HOLD_LINE, 0xff); // Z80
140 }
141
142 m_last_irq_state = state;
143 }
144
145
WRITE_LINE_MEMBER(timeplt_audio_device::mute_w)146 WRITE_LINE_MEMBER(timeplt_audio_device::mute_w)
147 {
148 // controls pin 6 (DC audio mute) of LA4460 amplifier
149 machine().sound().system_mute(state);
150 }
151
152
153
154 /*************************************
155 *
156 * Memory maps
157 *
158 *************************************/
159
timeplt_sound_map(address_map & map)160 void timeplt_audio_device::timeplt_sound_map(address_map &map)
161 {
162 map(0x0000, 0x2fff).rom();
163 map(0x3000, 0x33ff).mirror(0x0c00).ram();
164 map(0x4000, 0x4000).mirror(0x0fff).rw("ay1", FUNC(ay8910_device::data_r), FUNC(ay8910_device::data_w));
165 map(0x5000, 0x5000).mirror(0x0fff).w("ay1", FUNC(ay8910_device::address_w));
166 map(0x6000, 0x6000).mirror(0x0fff).rw("ay2", FUNC(ay8910_device::data_r), FUNC(ay8910_device::data_w));
167 map(0x7000, 0x7000).mirror(0x0fff).w("ay2", FUNC(ay8910_device::address_w));
168 map(0x8000, 0xffff).w(FUNC(timeplt_audio_device::filter_w));
169 }
170
171
locomotn_sound_map(address_map & map)172 void locomotn_audio_device::locomotn_sound_map(address_map &map)
173 {
174 map(0x0000, 0x1fff).rom();
175 map(0x2000, 0x23ff).mirror(0x0c00).ram();
176 map(0x3000, 0x3fff).w(FUNC(locomotn_audio_device::filter_w));
177 map(0x4000, 0x4000).mirror(0x0fff).rw("ay1", FUNC(ay8910_device::data_r), FUNC(ay8910_device::data_w));
178 map(0x5000, 0x5000).mirror(0x0fff).w("ay1", FUNC(ay8910_device::address_w));
179 map(0x6000, 0x6000).mirror(0x0fff).rw("ay2", FUNC(ay8910_device::data_r), FUNC(ay8910_device::data_w));
180 map(0x7000, 0x7000).mirror(0x0fff).w("ay2", FUNC(ay8910_device::address_w));
181 }
182
183
184 /*************************************
185 *
186 * Machine drivers
187 *
188 *************************************/
189
device_add_mconfig(machine_config & config)190 void timeplt_audio_device::device_add_mconfig(machine_config &config)
191 {
192 /* basic machine hardware */
193 Z80(config, m_soundcpu, DERIVED_CLOCK(1, 8));
194 m_soundcpu->set_addrmap(AS_PROGRAM, &timeplt_audio_device::timeplt_sound_map);
195
196 /* sound hardware */
197 SPEAKER(config, "mono").front_center();
198
199 GENERIC_LATCH_8(config, m_soundlatch);
200
201 ay8910_device &ay1(AY8910(config, "ay1", DERIVED_CLOCK(1, 8)));
202 ay1.port_a_read_callback().set(m_soundlatch, FUNC(generic_latch_8_device::read));
203 ay1.port_b_read_callback().set(FUNC(timeplt_audio_device::portB_r));
204 ay1.add_route(0, "filter.0.0", 0.60);
205 ay1.add_route(1, "filter.0.1", 0.60);
206 ay1.add_route(2, "filter.0.2", 0.60);
207
208 ay8910_device &ay2(AY8910(config, "ay2", DERIVED_CLOCK(1, 8)));
209 ay2.add_route(0, "filter.1.0", 0.60);
210 ay2.add_route(1, "filter.1.1", 0.60);
211 ay2.add_route(2, "filter.1.2", 0.60);
212
213 for (required_device<filter_rc_device> &filter : m_filter_0)
214 FILTER_RC(config, filter).add_route(ALL_OUTPUTS, "mono", 1.0);
215
216 for (required_device<filter_rc_device> &filter : m_filter_1)
217 FILTER_RC(config, filter).add_route(ALL_OUTPUTS, "mono", 1.0);
218 }
219
220
device_add_mconfig(machine_config & config)221 void locomotn_audio_device::device_add_mconfig(machine_config &config)
222 {
223 timeplt_audio_device::device_add_mconfig(config);
224
225 /* basic machine hardware */
226 m_soundcpu->set_addrmap(AS_PROGRAM, &locomotn_audio_device::locomotn_sound_map);
227 }
228