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