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