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