1 // license:BSD-3-Clause
2 // copyright-holders:Ryan Holtz
3 /**********************************************************************
4 
5     SGI HAL2 Audio Controller emulation
6 
7 **********************************************************************/
8 
9 #include "emu.h"
10 #include "machine/hal2.h"
11 
12 #define LOG_UNKNOWN     (1 << 0U)
13 #define LOG_READS       (1 << 1U)
14 #define LOG_WRITES      (1 << 2U)
15 #define LOG_ALL         (LOG_UNKNOWN | LOG_READS | LOG_WRITES)
16 
17 #define VERBOSE         (0)
18 #include "logmacro.h"
19 
20 DEFINE_DEVICE_TYPE(SGI_HAL2, hal2_device, "hal2", "SGI HAL2")
21 
hal2_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)22 hal2_device::hal2_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
23 	: device_t(mconfig, SGI_HAL2, tag, owner, clock)
24 	, m_ldac(*this, "ldac")
25 	, m_rdac(*this, "rdac")
26 {
27 }
28 
device_start()29 void hal2_device::device_start()
30 {
31 	save_item(NAME(m_isr));
32 	save_item(NAME(m_iar));
33 	save_item(NAME(m_idr));
34 	save_item(NAME(m_codeca_ctrl));
35 	save_item(NAME(m_codeca_channel));
36 	save_item(NAME(m_codeca_clock));
37 	save_item(NAME(m_codeca_channel_count));
38 	save_item(NAME(m_codecb_ctrl));
39 	save_item(NAME(m_codecb_channel));
40 	save_item(NAME(m_codecb_clock));
41 	save_item(NAME(m_codecb_channel_count));
42 	save_item(NAME(m_bres_clock_sel));
43 	save_item(NAME(m_bres_clock_inc));
44 	save_item(NAME(m_bres_clock_modctrl));
45 	save_item(NAME(m_bres_clock_freq));
46 	save_item(NAME(m_curr_dac));
47 }
48 
device_reset()49 void hal2_device::device_reset()
50 {
51 	m_isr = 0;
52 	m_iar = 0;
53 	memset(m_idr, 0, sizeof(uint16_t) * 4);
54 	memset(m_codeca_ctrl, 0, sizeof(uint16_t) * 2);
55 	m_codeca_channel = 0;
56 	m_codeca_clock = 0;
57 	m_codeca_channel_count = 0;
58 	memset(m_codecb_ctrl, 0, sizeof(uint16_t) * 2);
59 	m_codecb_channel = 0;
60 	m_codecb_clock = 0;
61 	m_codecb_channel_count = 0;
62 	memset(m_bres_clock_sel, 0, sizeof(uint16_t) * 3);
63 	memset(m_bres_clock_inc, 0, sizeof(uint16_t) * 3);
64 	memset(m_bres_clock_modctrl, 0, sizeof(uint16_t) * 3);
65 	memset(m_bres_clock_freq, 0, sizeof(uint16_t) * 3);
66 	for (int i = 0; i < 3; i++)
67 	{
68 		m_bres_clock_rate[i] = attotime::zero;
69 	}
70 	m_curr_dac = 0;
71 }
72 
read(offs_t offset)73 uint16_t hal2_device::read(offs_t offset)
74 {
75 	switch (offset)
76 	{
77 	case STATUS_REG:
78 		LOGMASKED(LOG_READS, "%s: HAL2 Status Read: %08x\n", machine().describe_context(), m_isr);
79 		return m_isr;
80 	case REVISION_REG:
81 		LOGMASKED(LOG_READS, "%s: HAL2 Revision Read: 0x4010\n", machine().describe_context());
82 		return 0x4010;
83 
84 	case INDIRECT_DATA0_REG:
85 		LOGMASKED(LOG_WRITES, "%s: HAL2 Indirect Data Register 0 Read: %04x\n", machine().describe_context(), m_idr[0]);
86 		return m_idr[0];
87 
88 	case INDIRECT_DATA1_REG:
89 		LOGMASKED(LOG_WRITES, "%s: HAL2 Indirect Data Register 1 Read: %04x\n", machine().describe_context(), m_idr[1]);
90 		return m_idr[1];
91 
92 	case INDIRECT_DATA2_REG:
93 		LOGMASKED(LOG_WRITES, "%s: HAL2 Indirect Data Register 2 Read: %04x\n", machine().describe_context(), m_idr[2]);
94 		return m_idr[2];
95 
96 	case INDIRECT_DATA3_REG:
97 		LOGMASKED(LOG_WRITES, "%s: HAL2 Indirect Data Register 3 Read: %04x\n", machine().describe_context(), m_idr[3]);
98 		return m_idr[3];
99 	}
100 	LOGMASKED(LOG_READS | LOG_UNKNOWN, "%s: Unknown HAL2 read: %08x\n", machine().describe_context(), 0x1fbd8000 + offset*4);
101 	return 0;
102 }
103 
write(offs_t offset,uint16_t data)104 void hal2_device::write(offs_t offset, uint16_t data)
105 {
106 	switch (offset)
107 	{
108 	case STATUS_REG:
109 		LOGMASKED(LOG_WRITES, "%s: HAL2 Status Write: 0x%04x\n", machine().describe_context(), data);
110 		LOGMASKED(LOG_WRITES, "    HAL2 Global Reset %s\n", (data & ISR_GLOBAL_RESET) ? "Inactive" : "Active");
111 		LOGMASKED(LOG_WRITES, "    HAL2 Codec Reset %s\n", (data & ISR_CODEC_RESET) ? "Inactive" : "Active");
112 		m_isr &= ~0x1c;
113 		m_isr |= data & 0x1c;
114 		break;
115 	case INDIRECT_ADDRESS_REG:
116 		LOGMASKED(LOG_WRITES, "%s: HAL2 Indirect Address Register Write: %04x\n", machine().describe_context(), data);
117 		m_iar = data;
118 		switch (data & IAR_TYPE)
119 		{
120 		case 0x1000:
121 			LOGMASKED(LOG_WRITES, "    DMA Port\n");
122 			switch (data & IAR_NUM)
123 			{
124 			case 0x0100:
125 				LOGMASKED(LOG_WRITES, "        Synth In\n");
126 				break;
127 			case 0x0200:
128 				LOGMASKED(LOG_WRITES, "        AES In\n");
129 				break;
130 			case 0x0300:
131 				LOGMASKED(LOG_WRITES, "        AES Out\n");
132 				break;
133 			case 0x0400:
134 			{
135 				LOGMASKED(LOG_WRITES, "        Codec A (DAC) Out\n");
136 				const uint32_t param = (data & IAR_PARAM) >> IAR_PARAM_SHIFT;
137 				switch (param)
138 				{
139 					case 1:
140 						LOGMASKED(LOG_WRITES, "            Control 1\n");
141 						if (data & IAR_ACCESS_SEL)
142 						{
143 							m_idr[0] = m_codeca_ctrl[0];
144 						}
145 						else
146 						{
147 							m_codeca_ctrl[0] = m_idr[0];
148 							m_codeca_channel = m_idr[0] & 3;
149 							m_codeca_clock = (m_idr[0] >> 3) & 3;
150 							m_codeca_channel_count = (m_idr[0] >> 8) & 3;
151 						}
152 						break;
153 					case 2:
154 						LOGMASKED(LOG_WRITES, "            Control 2\n");
155 						if (data & IAR_ACCESS_SEL)
156 						{
157 							m_idr[0] = m_codeca_ctrl[1];
158 						}
159 						else
160 						{
161 							m_codeca_ctrl[1] = m_idr[0];
162 						}
163 						break;
164 					default:
165 						LOGMASKED(LOG_WRITES, "            Unknown Register\n");
166 						break;
167 				}
168 				break;
169 			}
170 			case 0x0500:
171 			{
172 				LOGMASKED(LOG_WRITES, "        Codec B (ADC) Out\n");
173 				const uint32_t param = (data & IAR_PARAM) >> IAR_PARAM_SHIFT;
174 				switch (param)
175 				{
176 					case 1:
177 						LOGMASKED(LOG_WRITES, "            Control 1\n");
178 						if (data & IAR_ACCESS_SEL)
179 						{
180 							m_idr[0] = m_codecb_ctrl[0];
181 						}
182 						else
183 						{
184 							m_codecb_ctrl[0] = m_idr[0];
185 							m_codecb_channel = m_idr[0] & 3;
186 							m_codecb_clock = (m_idr[0] >> 3) & 3;
187 							m_codecb_channel_count = (m_idr[0] >> 8) & 3;
188 						}
189 						break;
190 					case 2:
191 						LOGMASKED(LOG_WRITES, "            Control 2\n");
192 						if (data & IAR_ACCESS_SEL)
193 						{
194 							m_idr[0] = m_codecb_ctrl[1];
195 						}
196 						else
197 						{
198 							m_codecb_ctrl[1] = m_idr[0];
199 						}
200 						break;
201 					default:
202 						LOGMASKED(LOG_WRITES, "            Unknown Register\n");
203 						break;
204 				}
205 				break;
206 			}
207 			case 0x0600:
208 				LOGMASKED(LOG_WRITES, "        Synth Control\n");
209 				break;
210 			default:
211 				LOGMASKED(LOG_WRITES, "        Unknown\n");
212 				break;
213 			}
214 			break;
215 		case 0x2000:
216 		{
217 			LOGMASKED(LOG_WRITES, "    Bresenham\n");
218 			uint32_t clock_gen = (data & IAR_NUM) >> IAR_NUM_SHIFT;
219 			if (clock_gen >= 1 && clock_gen <= 3)
220 			{
221 				LOGMASKED(LOG_WRITES, "        Bresenham Clock Gen %d\n", clock_gen);
222 				clock_gen--;
223 				const uint32_t param = (data & IAR_PARAM) >> IAR_PARAM_SHIFT;
224 				if (param == 1)
225 				{
226 					LOGMASKED(LOG_WRITES, "            Control 1 (Clock Select)\n");
227 					if (data & IAR_ACCESS_SEL)
228 					{
229 						m_idr[0] = m_bres_clock_sel[clock_gen];
230 					}
231 					else
232 					{
233 						m_bres_clock_sel[clock_gen] = m_idr[0];
234 						switch (m_idr[0])
235 						{
236 							case 0:  LOGMASKED(LOG_WRITES, "                48kHz\n"); break;
237 							case 1:  LOGMASKED(LOG_WRITES, "                44.1kHz\n"); break;
238 							case 2:  LOGMASKED(LOG_WRITES, "                Off\n"); break;
239 							default: LOGMASKED(LOG_WRITES, "                Unknown (%d)\n", m_idr[0]); break;
240 						}
241 						update_clock_freq(clock_gen);
242 					}
243 				}
244 				else if (param == 2)
245 				{
246 					LOGMASKED(LOG_WRITES, "            Control 2 (Inc/Mod Ctrl)\n");
247 					if (data & IAR_ACCESS_SEL)
248 					{
249 						m_idr[0] = m_bres_clock_inc[clock_gen];
250 						m_idr[1] = m_bres_clock_modctrl[clock_gen];
251 					}
252 					else
253 					{
254 						m_bres_clock_inc[clock_gen] = m_idr[0];
255 						m_bres_clock_modctrl[clock_gen] = m_idr[1];
256 						LOGMASKED(LOG_WRITES, "                Inc:%04x, ModCtrl:%04x\n", m_idr[0], m_idr[1]);
257 						update_clock_freq(clock_gen);
258 					}
259 				}
260 				else
261 				{
262 					LOGMASKED(LOG_WRITES, "            Unknown Param\n");
263 				}
264 			}
265 			else
266 			{
267 				LOGMASKED(LOG_WRITES, "        Unknown\n");
268 			}
269 			break;
270 		}
271 
272 		case 0x3000:
273 			LOGMASKED(LOG_WRITES, "    Unix Timer\n");
274 			switch (data & IAR_NUM)
275 			{
276 			case 0x0100:
277 				LOGMASKED(LOG_WRITES, "        Unix Timer\n");
278 				break;
279 			default:
280 				LOGMASKED(LOG_WRITES, "        Unknown\n");
281 				break;
282 			}
283 			break;
284 
285 		case 0x9000:
286 			LOGMASKED(LOG_WRITES, "    Global DMA Control\n");
287 			switch (data & IAR_NUM)
288 			{
289 			case 0x0100:
290 				LOGMASKED(LOG_WRITES, "        DMA Control\n");
291 				break;
292 			default:
293 				LOGMASKED(LOG_WRITES, "        Unknown\n");
294 				break;
295 			}
296 			break;
297 		}
298 
299 		if (data & IAR_ACCESS_SEL)
300 			LOGMASKED(LOG_WRITES, "    Read\n");
301 		else
302 			LOGMASKED(LOG_WRITES, "    Write\n");
303 
304 		LOGMASKED(LOG_WRITES, "    Parameter: %01x\n", (data & IAR_PARAM) >> 2);
305 		return;
306 
307 	case INDIRECT_DATA0_REG:
308 		LOGMASKED(LOG_WRITES, "%s: HAL2 Indirect Data Register 0 Write: %04x\n", machine().describe_context(), data);
309 		m_idr[0] = data;
310 		return;
311 
312 	case INDIRECT_DATA1_REG:
313 		LOGMASKED(LOG_WRITES, "%s: HAL2 Indirect Data Register 1 Write: %04x\n", machine().describe_context(), data);
314 		m_idr[1] = data;
315 		return;
316 
317 	case INDIRECT_DATA2_REG:
318 		LOGMASKED(LOG_WRITES, "%s: HAL2 Indirect Data Register 2 Write: %04x\n", machine().describe_context(), data);
319 		m_idr[2] = data;
320 		return;
321 
322 	case INDIRECT_DATA3_REG:
323 		LOGMASKED(LOG_WRITES, "%s: HAL2 Indirect Data Register 3 Write: %04x\n", machine().describe_context(), data);
324 		m_idr[3] = data;
325 		return;
326 
327 	default:
328 		LOGMASKED(LOG_WRITES, "%s: Unknown HAL2 Write: %08x = %04x\n", machine().describe_context(), 0x1fbd8000 + offset*4, data);
329 		break;
330 	}
331 }
332 
update_clock_freq(int clock_gen)333 void hal2_device::update_clock_freq(int clock_gen)
334 {
335 	switch (m_bres_clock_sel[clock_gen])
336 	{
337 		case 0: // 48kHz
338 			m_bres_clock_freq[clock_gen] = 48000;
339 			break;
340 		case 1: // 44.1kHz
341 			m_bres_clock_freq[clock_gen] = 44100;
342 			break;
343 		default:
344 			m_bres_clock_freq[clock_gen] = 0;
345 			m_bres_clock_rate[clock_gen] = attotime::zero;
346 			return;
347 	}
348 
349 	const uint32_t mod = 0x10000 - ((m_bres_clock_modctrl[clock_gen] + 1) - m_bres_clock_inc[clock_gen]);
350 	if (mod == 0)
351 		m_bres_clock_rate[clock_gen] = attotime::from_ticks(1, m_bres_clock_freq[clock_gen] * m_bres_clock_inc[clock_gen]);
352 	else
353 		m_bres_clock_rate[clock_gen] = attotime::from_ticks(mod, m_bres_clock_freq[clock_gen] * m_bres_clock_inc[clock_gen]);
354 }
355 
get_rate(const uint32_t channel)356 attotime hal2_device::get_rate(const uint32_t channel)
357 {
358 	if ((channel == m_codeca_channel || channel == (3 - m_codeca_channel)) && m_codeca_clock > 0 && m_codeca_channel_count > 0)
359 		return m_bres_clock_rate[m_codeca_clock - 1] / m_codeca_channel_count;
360 	if ((channel == m_codecb_channel || channel == (3 - m_codecb_channel)) && m_codecb_clock > 0 && m_codecb_channel_count > 0)
361 		return m_bres_clock_rate[m_codecb_clock - 1] / m_codecb_channel_count;
362 	return attotime::zero;
363 }
364 
dma_write(uint32_t channel,int16_t data)365 void hal2_device::dma_write(uint32_t channel, int16_t data)
366 {
367 	if (channel >= 2)
368 		return;
369 
370 	if (m_curr_dac)
371 		m_rdac->write(data);
372 	else
373 		m_ldac->write(data);
374 
375 	m_curr_dac++;
376 	if (m_curr_dac == m_codeca_channel_count)
377 		m_curr_dac = 0;
378 }
379 
device_add_mconfig(machine_config & config)380 void hal2_device::device_add_mconfig(machine_config &config)
381 {
382 	SPEAKER(config, "lspeaker").front_left();
383 	SPEAKER(config, "rspeaker").front_right();
384 
385 	DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_ldac, 0);
386 	m_ldac->add_route(ALL_OUTPUTS, "lspeaker", 0.25);
387 
388 	DAC_16BIT_R2R_TWOS_COMPLEMENT(config, m_rdac, 0);
389 	m_rdac->add_route(ALL_OUTPUTS, "rspeaker", 0.25);
390 }
391