1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4
5 segaspeech.cpp
6
7 Sega Speech board for early G-80 games.
8
9 ***************************************************************************/
10
11 #include "emu.h"
12 #include "segaspeech.h"
13
14 #include "sound/sp0250.h"
15 #include "includes/segag80r.h"
16 #include "includes/segag80v.h"
17 #include "audio/nl_segaspeech.h"
18
19 #define VERBOSE 0
20 #include "logmacro.h"
21
22 #define ENABLE_NETLIST_FILTERING (0)
23
24
25 /***************************************************************************
26 CONSTANTS
27 ***************************************************************************/
28
29 #define SPEECH_MASTER_CLOCK 3120000
30
31
32
33 /***************************************************************************
34 SPEECH BOARD
35 ***************************************************************************/
36
37 DEFINE_DEVICE_TYPE(SEGA_SPEECH_BOARD, sega_speech_device, "sega_speech_device", "Sega Speech Sound Board")
38
sega_speech_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)39 sega_speech_device::sega_speech_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
40 device_t(mconfig, SEGA_SPEECH_BOARD, tag, owner, clock),
41 device_mixer_interface(mconfig, *this),
42 m_speech(*this, "data"),
43 m_cpu(*this, "cpu"),
44 m_drq(0),
45 m_latch(0),
46 m_t0(0),
47 m_p2(0)
48 {
49 }
50
51 //-------------------------------------------------
52 // device_start - device-specific startup
53 //-------------------------------------------------
54
device_start()55 void sega_speech_device::device_start()
56 {
57 save_item(NAME(m_latch));
58 save_item(NAME(m_t0));
59 save_item(NAME(m_p2));
60 save_item(NAME(m_drq));
61 }
62
63
64 /*************************************
65 *
66 * i8035 port accessors
67 *
68 *************************************/
69
READ_LINE_MEMBER(sega_speech_device::t0_r)70 READ_LINE_MEMBER( sega_speech_device::t0_r )
71 {
72 return m_t0;
73 }
74
READ_LINE_MEMBER(sega_speech_device::t1_r)75 READ_LINE_MEMBER( sega_speech_device::t1_r )
76 {
77 //printf("%s: t1_r=%d\n", machine().scheduler().time().as_string(), m_drq);
78 return m_drq;
79 }
80
p1_r()81 uint8_t sega_speech_device::p1_r()
82 {
83 return m_latch & 0x7f;
84 }
85
rom_r(offs_t offset)86 uint8_t sega_speech_device::rom_r(offs_t offset)
87 {
88 return m_speech->base()[0x100 * (m_p2 & 0x3f) + offset];
89 }
90
p1_w(uint8_t data)91 void sega_speech_device::p1_w(uint8_t data)
92 {
93 if (!(data & 0x80))
94 m_t0 = 0;
95 }
96
p2_w(uint8_t data)97 void sega_speech_device::p2_w(uint8_t data)
98 {
99 m_p2 = data;
100 }
101
102
103
104 /*************************************
105 *
106 * i8035 port accessors
107 *
108 *************************************/
109
WRITE_LINE_MEMBER(sega_speech_device::drq_w)110 WRITE_LINE_MEMBER(sega_speech_device::drq_w)
111 {
112 //printf("%s: DRQ=%d\n", machine().scheduler().time().as_string(), state);
113 m_drq = (state == ASSERT_LINE);
114 }
115
116
117
118 /*************************************
119 *
120 * External access
121 *
122 *************************************/
123
TIMER_CALLBACK_MEMBER(sega_speech_device::delayed_speech_w)124 TIMER_CALLBACK_MEMBER( sega_speech_device::delayed_speech_w )
125 {
126 int data = param;
127 u8 old = m_latch;
128
129 /* all 8 bits are latched */
130 m_latch = data;
131
132 /* the high bit goes directly to the INT line */
133 m_cpu->set_input_line(INPUT_LINE_IRQ0, (data & 0x80) ? CLEAR_LINE : ASSERT_LINE);
134
135 /* a clock on the high bit clocks a 1 into T0 */
136 if (!(old & 0x80) && (data & 0x80))
137 m_t0 = 1;
138 }
139
140
data_w(uint8_t data)141 void sega_speech_device::data_w(uint8_t data)
142 {
143 machine().scheduler().synchronize(timer_expired_delegate(FUNC(sega_speech_device::delayed_speech_w), this), data);
144 }
145
146
control_w(uint8_t data)147 void sega_speech_device::control_w(uint8_t data)
148 {
149 // bit 3 controls channel #1 of a CD4053 to enable/disable
150 // speech output
151 this->set_input_gain(0, BIT(data, 3) ? 1.0 : 0.0);
152
153 // bit 4 controls channel #2, but the source is unconnected
154
155 // bit 5 controls channel #3, which comes from off-board
156 // and has a pot to control the incoming volume; at least on
157 // Star Trek, this is the audio from the Universal Sound Board
158 this->set_input_gain(1, BIT(data, 5) ? 1.0 : 0.0);
159
160 LOG("Speech control = %X\n", data);
161 }
162
163
164 /*************************************
165 *
166 * Speech board address maps
167 *
168 *************************************/
169
speech_map(address_map & map)170 void sega_speech_device::speech_map(address_map &map)
171 {
172 map(0x0000, 0x07ff).mirror(0x0800).rom();
173 }
174
175
speech_portmap(address_map & map)176 void sega_speech_device::speech_portmap(address_map &map)
177 {
178 map(0x00, 0xff).r(FUNC(sega_speech_device::rom_r));
179 map(0x00, 0xff).w("sp0250", FUNC(sp0250_device::write));
180 }
181
182
183 /*************************************
184 *
185 * Speech board machine drivers
186 *
187 *************************************/
188
device_add_mconfig(machine_config & config)189 void sega_speech_device::device_add_mconfig(machine_config &config)
190 {
191 // CPU for the speech board
192 i8035_device &audiocpu(I8035(config, "cpu", SPEECH_MASTER_CLOCK)); // divide by 15 in CPU
193 audiocpu.set_addrmap(AS_PROGRAM, &sega_speech_device::speech_map);
194 audiocpu.set_addrmap(AS_IO, &sega_speech_device::speech_portmap);
195 audiocpu.p1_in_cb().set(FUNC(sega_speech_device::p1_r));
196 audiocpu.p1_out_cb().set(FUNC(sega_speech_device::p1_w));
197 audiocpu.p2_out_cb().set(FUNC(sega_speech_device::p2_w));
198 audiocpu.t0_in_cb().set(FUNC(sega_speech_device::t0_r));
199 audiocpu.t1_in_cb().set(FUNC(sega_speech_device::t1_r));
200
201 // speech chip
202 sp0250_device &speech(SP0250(config, "sp0250", SPEECH_MASTER_CLOCK));
203 speech.drq().set(FUNC(sega_speech_device::drq_w));
204 #if (ENABLE_NETLIST_FILTERING)
205 speech.set_pwm_mode();
206 speech.add_route(ALL_OUTPUTS, "sound_nl", 1.0, 0);
207
208 // netlist filtering
209 NETLIST_SOUND(config, "sound_nl", SPEECH_MASTER_CLOCK/2)
210 .set_source(NETLIST_NAME(segaspeech))
211 .add_route(ALL_OUTPUTS, *this, 1.0);
212
213 NETLIST_STREAM_INPUT(config, "sound_nl:cin0", 0, "I_SP0250.IN").set_mult_offset(1.0 / 32767.0, 0);
214
215 NETLIST_STREAM_OUTPUT(config, "sound_nl:cout0", 0, "OUTPUT").set_mult_offset(75000.0, 0.0);
216 #else
217 speech.add_route(ALL_OUTPUTS, *this, 1.0);
218 #endif
219 }
220