1 #include <stdlib.h>
2 #include <string.h>
3 #include "ibm.h"
4 #include "device.h"
5
6 #include "sound_opl.h"
7 #include "sound_ym7128.h"
8 #include "dma.h"
9 #include "io.h"
10 #include "pic.h"
11 #include "pit.h"
12 #include "sound.h"
13 #include "timer.h"
14 #include "nvr.h"
15
16 #include "filters.h"
17
18 typedef struct adgold_t
19 {
20 int adgold_irq_status;
21
22 uint8_t adgold_eeprom[0x19];
23
24 uint8_t adgold_status;
25 int adgold_38x_state, adgold_38x_addr;
26 uint8_t adgold_38x_regs[0x19];
27
28 int adgold_mma_addr;
29 uint8_t adgold_mma_regs[2][0xe];
30
31 int adgold_mma_enable[2];
32 uint8_t adgold_mma_fifo[2][256];
33 int adgold_mma_fifo_start[2], adgold_mma_fifo_end[2];
34 uint8_t adgold_mma_status;
35
36 int16_t adgold_mma_out[2];
37 int adgold_mma_intpos[2];
38
39 int adgold_mma_timer_count;
40
41 struct
42 {
43 int timer0_latch, timer0_count;
44 int timerbase_latch, timerbase_count;
45 int timer1_latch, timer1_count;
46 int timer2_latch, timer2_count, timer2_read;
47
48 int voice_count[2], voice_latch[2];
49 } adgold_mma;
50
51 opl_t opl;
52 ym7128_t ym7128;
53
54 int fm_vol_l, fm_vol_r;
55 int samp_vol_l, samp_vol_r;
56 int vol_l, vol_r;
57 int treble, bass;
58
59 int16_t opl_buffer[MAXSOUNDBUFLEN * 2];
60 int16_t mma_buffer[2][MAXSOUNDBUFLEN];
61
62 int pos;
63
64 int surround_enabled;
65 } adgold_t;
66
67 static int attenuation[0x40];
68 static int bass_attenuation[0x10] =
69 {
70 (int)(1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/
71 (int)(1.995 * 16384),
72 (int)(1.995 * 16384),
73 (int)(1.413 * 16384), /*9 dB*/
74 (int)(1 * 16384), /*6 dB*/
75 (int)(0.708 * 16384), /*3 dB*/
76 (int)(0 * 16384), /*0 dB*/
77 (int)(0.708 * 16384), /*3 dB*/
78 (int)(1 * 16384), /*6 dB*/
79 (int)(1.413 * 16384), /*9 dB*/
80 (int)(1.995 * 16384), /*12 dB*/
81 (int)(2.819 * 16384), /*15 dB*/
82 (int)(2.819 * 16384),
83 (int)(2.819 * 16384),
84 (int)(2.819 * 16384),
85 (int)(2.819 * 16384)
86 };
87
88 static int bass_cut[6] =
89 {
90 (int)(0.126 * 16384), /*-12 dB*/
91 (int)(0.126 * 16384), /*-12 dB*/
92 (int)(0.126 * 16384), /*-12 dB*/
93 (int)(0.178 * 16384), /*-9 dB*/
94 (int)(0.251 * 16384), /*-6 dB*/
95 (int)(0.354 * 16384) /*-3 dB - filter output is at +6 dB*/
96 };
97
98 static int treble_attenuation[0x10] =
99 {
100 (int)(1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/
101 (int)(1.995 * 16384),
102 (int)(1.995 * 16384),
103 (int)(1.413 * 16384), /*9 dB*/
104 (int)(1 * 16384), /*6 dB*/
105 (int)(0.708 * 16384), /*3 dB*/
106 (int)(0 * 16384), /*0 dB*/
107 (int)(0.708 * 16384), /*3 dB*/
108 (int)(1 * 16384), /*6 dB*/
109 (int)(1.413 * 16384), /*9 dB*/
110 (int)(1.995 * 16384), /*12 dB*/
111 (int)(1.995 * 16384),
112 (int)(1.995 * 16384),
113 (int)(1.995 * 16384),
114 (int)(1.995 * 16384),
115 (int)(1.995 * 16384)
116 };
117
118 static int treble_cut[6] =
119 {
120 (int)(0.126 * 16384), /*-12 dB*/
121 (int)(0.126 * 16384), /*-12 dB*/
122 (int)(0.126 * 16384), /*-12 dB*/
123 (int)(0.178 * 16384), /*-9 dB*/
124 (int)(0.251 * 16384), /*-6 dB*/
125 (int)(0.354 * 16384) /*-3 dB - filter output is at +6 dB*/
126 };
127
128 void adgold_timer_poll();
129 void adgold_update(adgold_t *adgold);
130
adgold_update_irq_status(adgold_t * adgold)131 void adgold_update_irq_status(adgold_t *adgold)
132 {
133 uint8_t temp = 0xf;
134
135 if (!(adgold->adgold_mma_regs[0][8] & 0x10) && (adgold->adgold_mma_status & 0x10)) /*Timer 0*/
136 temp &= ~2;
137 if (!(adgold->adgold_mma_regs[0][8] & 0x20) && (adgold->adgold_mma_status & 0x20)) /*Timer 1*/
138 temp &= ~2;
139 if (!(adgold->adgold_mma_regs[0][8] & 0x40) && (adgold->adgold_mma_status & 0x40)) /*Timer 2*/
140 temp &= ~2;
141
142 if ((adgold->adgold_mma_status & 0x01) && !(adgold->adgold_mma_regs[0][0xc] & 2))
143 temp &= ~2;
144 if ((adgold->adgold_mma_status & 0x02) && !(adgold->adgold_mma_regs[1][0xc] & 2))
145 temp &= ~2;
146 adgold->adgold_status = temp;
147
148 if ((adgold->adgold_status ^ 0xf) && !adgold->adgold_irq_status)
149 {
150 // pclog("adgold irq %02X\n", adgold->adgold_status);
151 picint(0x80);
152 }
153
154 adgold->adgold_irq_status = adgold->adgold_status ^ 0xf;
155 }
156
adgold_getsamp_dma(adgold_t * adgold,int channel)157 void adgold_getsamp_dma(adgold_t *adgold, int channel)
158 {
159 int temp;
160
161 if ((adgold->adgold_mma_regs[channel][0xc] & 0x60) && (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= 127))
162 return;
163
164 temp = dma_channel_read(1);
165 // pclog("adgold DMA1 return %02X %i L\n", temp, channel);
166 if (temp == DMA_NODATA) return;
167 adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp;
168 adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255;
169 if (adgold->adgold_mma_regs[channel][0xc] & 0x60)
170 {
171 temp = dma_channel_read(1);
172 // pclog("adgold DMA1 return %02X %i H\n", temp, channel);
173 adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp;
174 adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255;
175 }
176 if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= adgold->adgold_mma_intpos[channel])
177 {
178 adgold->adgold_mma_status &= ~(0x01 << channel);
179 adgold_update_irq_status(adgold);
180 }
181 }
182
adgold_write(uint16_t addr,uint8_t val,void * p)183 void adgold_write(uint16_t addr, uint8_t val, void *p)
184 {
185 adgold_t *adgold = (adgold_t *)p;
186 // if (addr > 0x389) pclog("adgold_write : addr %04X val %02X %04X:%04X\n", addr, val, CS, pc);
187 switch (addr & 7)
188 {
189 case 0: case 1:
190 opl3_write(addr, val, &adgold->opl);
191 break;
192
193 case 2:
194 if (val == 0xff)
195 {
196 adgold->adgold_38x_state = 1;
197 return;
198 }
199 if (val == 0xfe)
200 {
201 adgold->adgold_38x_state = 0;
202 return;
203 }
204 if (adgold->adgold_38x_state) /*Write to control chip*/
205 adgold->adgold_38x_addr = val;
206 else
207 opl3_write(addr, val, &adgold->opl);
208 break;
209 case 3:
210 if (adgold->adgold_38x_state)
211 {
212 if (adgold->adgold_38x_addr >= 0x19) break;
213 switch (adgold->adgold_38x_addr)
214 {
215 case 0x00: /*Control/ID*/
216 if (val & 1)
217 memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19);
218 if (val & 2)
219 memcpy(adgold->adgold_eeprom, adgold->adgold_38x_regs, 0x19);
220 break;
221
222 case 0x04: /*Final output volume left*/
223 adgold->adgold_38x_regs[0x04] = val;
224 adgold->vol_l = attenuation[val & 0x3f];
225 break;
226 case 0x05: /*Final output volume right*/
227 adgold->adgold_38x_regs[0x05] = val;
228 adgold->vol_r = attenuation[val & 0x3f];
229 break;
230 case 0x06: /*Bass*/
231 adgold->adgold_38x_regs[0x06] = val;
232 adgold->bass = val & 0xf;
233 break;
234 case 0x07: /*Treble*/
235 adgold->adgold_38x_regs[0x07] = val;
236 adgold->treble = val & 0xf;
237 break;
238
239 case 0x09: /*FM volume left*/
240 adgold->adgold_38x_regs[0x09] = val;
241 adgold->fm_vol_l = (int)(int8_t)(val - 128);
242 break;
243 case 0x0a: /*FM volume right*/
244 adgold->adgold_38x_regs[0x0a] = val;
245 adgold->fm_vol_r = (int)(int8_t)(val - 128);
246 break;
247 case 0x0b: /*Sample volume left*/
248 adgold->adgold_38x_regs[0x0b] = val;
249 adgold->samp_vol_l = (int)(int8_t)(val - 128);
250 break;
251 case 0x0c: /*Sample volume right*/
252 adgold->adgold_38x_regs[0x0c] = val;
253 adgold->samp_vol_r = (int)(int8_t)(val - 128);
254 break;
255
256 case 0x18: /*Surround*/
257 adgold->adgold_38x_regs[0x18] = val;
258 ym7128_write(&adgold->ym7128, val);
259 break;
260
261 default:
262 adgold->adgold_38x_regs[adgold->adgold_38x_addr] = val;
263 break;
264 }
265 }
266 else
267 opl3_write(addr, val, &adgold->opl);
268 break;
269 case 4: case 6:
270 adgold->adgold_mma_addr = val;
271 break;
272 case 5:
273 if (adgold->adgold_mma_addr >= 0xf) break;
274 switch (adgold->adgold_mma_addr)
275 {
276 case 0x2:
277 adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff00) | val;
278 break;
279 case 0x3:
280 adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff) | (val << 8);
281 break;
282 case 0x4:
283 adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xf00) | val;
284 break;
285 case 0x5:
286 adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xff) | ((val & 0xf) << 8);
287 adgold->adgold_mma.timer1_latch = val >> 4;
288 break;
289 case 0x6:
290 adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff00) | val;
291 break;
292 case 0x7:
293 adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff) | (val << 8);
294 break;
295
296 case 0x8:
297 if ((val & 1) && !(adgold->adgold_mma_regs[0][8] & 1)) /*Reload timer 0*/
298 adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch;
299
300 if ((val & 2) && !(adgold->adgold_mma_regs[0][8] & 2)) /*Reload timer 1*/
301 adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch;
302
303 if ((val & 4) && !(adgold->adgold_mma_regs[0][8] & 4)) /*Reload timer 2*/
304 adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch;
305
306 if ((val & 8) && !(adgold->adgold_mma_regs[0][8] & 8)) /*Reload base timer*/
307 adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch;
308 break;
309
310 case 0x9:
311 switch (val & 0x18)
312 {
313 case 0x00: adgold->adgold_mma.voice_latch[0] = 12; break; /*44100 Hz*/
314 case 0x08: adgold->adgold_mma.voice_latch[0] = 24; break; /*22050 Hz*/
315 case 0x10: adgold->adgold_mma.voice_latch[0] = 48; break; /*11025 Hz*/
316 case 0x18: adgold->adgold_mma.voice_latch[0] = 72; break; /* 7350 Hz*/
317 }
318 if (val & 0x80)
319 {
320 adgold->adgold_mma_enable[0] = 0;
321 adgold->adgold_mma_fifo_end[0] = adgold->adgold_mma_fifo_start[0] = 0;
322 adgold->adgold_mma_status &= ~0x01;
323 adgold_update_irq_status(adgold);
324 }
325 if ((val & 0x01)) /*Start playback*/
326 {
327 if (!(adgold->adgold_mma_regs[0][0x9] & 1))
328 adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0];
329
330 // pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255, adgold->adgold_mma_fifo_end[0], adgold->adgold_mma_fifo_start[0], adgold->adgold_mma_regs[0][0xc]);
331 if (adgold->adgold_mma_regs[0][0xc] & 1)
332 {
333 if (adgold->adgold_mma_regs[0][0xc] & 0x80)
334 {
335 // pclog("adgold start interleaved %i %i
336 adgold->adgold_mma_enable[1] = 1;
337 adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1];
338
339 while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128)
340 {
341 adgold_getsamp_dma(adgold, 0);
342 adgold_getsamp_dma(adgold, 1);
343 }
344 if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0])
345 {
346 adgold->adgold_mma_status &= ~0x01;
347 adgold_update_irq_status(adgold);
348 }
349 if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1])
350 {
351 adgold->adgold_mma_status &= ~0x02;
352 adgold_update_irq_status(adgold);
353 }
354 }
355 else
356 {
357 while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128)
358 {
359 adgold_getsamp_dma(adgold, 0);
360 }
361 if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0])
362 {
363 adgold->adgold_mma_status &= ~0x01;
364 adgold_update_irq_status(adgold);
365 }
366 }
367 }
368 // pclog("adgold end\n");
369 }
370 adgold->adgold_mma_enable[0] = val & 0x01;
371 break;
372
373 case 0xb:
374 if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128)
375 {
376 adgold->adgold_mma_fifo[0][adgold->adgold_mma_fifo_end[0]] = val;
377 adgold->adgold_mma_fifo_end[0] = (adgold->adgold_mma_fifo_end[0] + 1) & 255;
378 if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0])
379 {
380 adgold->adgold_mma_status &= ~0x01;
381 adgold_update_irq_status(adgold);
382 }
383 }
384 break;
385
386 case 0xc:
387 adgold->adgold_mma_intpos[0] = (7 - ((val >> 2) & 7)) * 8;
388 break;
389 }
390 adgold->adgold_mma_regs[0][adgold->adgold_mma_addr] = val;
391 break;
392 case 7:
393 if (adgold->adgold_mma_addr >= 0xf) break;
394 switch (adgold->adgold_mma_addr)
395 {
396 case 0x9:
397 adgold_update(adgold);
398 switch (val & 0x18)
399 {
400 case 0x00: adgold->adgold_mma.voice_latch[1] = 12; break; /*44100 Hz*/
401 case 0x08: adgold->adgold_mma.voice_latch[1] = 24; break; /*22050 Hz*/
402 case 0x10: adgold->adgold_mma.voice_latch[1] = 48; break; /*11025 Hz*/
403 case 0x18: adgold->adgold_mma.voice_latch[1] = 72; break; /* 7350 Hz*/
404 }
405 if (val & 0x80)
406 {
407 adgold->adgold_mma_enable[1] = 0;
408 adgold->adgold_mma_fifo_end[1] = adgold->adgold_mma_fifo_start[1] = 0;
409 adgold->adgold_mma_status &= ~0x02;
410 adgold_update_irq_status(adgold);
411 }
412 if ((val & 0x01)) /*Start playback*/
413 {
414 if (!(adgold->adgold_mma_regs[1][0x9] & 1))
415 adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1];
416
417 // pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255, adgold->adgold_mma_fifo_end[1], adgold->adgold_mma_fifo_start[1], adgold->adgold_mma_regs[1][0xc]);
418 if (adgold->adgold_mma_regs[1][0xc] & 1)
419 {
420 while (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128)
421 {
422 adgold_getsamp_dma(adgold, 1);
423 }
424 }
425 // pclog("adgold end\n");
426 }
427 adgold->adgold_mma_enable[1] = val & 0x01;
428 break;
429
430 case 0xb:
431 if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128)
432 {
433 adgold->adgold_mma_fifo[1][adgold->adgold_mma_fifo_end[1]] = val;
434 adgold->adgold_mma_fifo_end[1] = (adgold->adgold_mma_fifo_end[1] + 1) & 255;
435 if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1])
436 {
437 adgold->adgold_mma_status &= ~0x02;
438 adgold_update_irq_status(adgold);
439 }
440 }
441 break;
442
443 case 0xc:
444 adgold->adgold_mma_intpos[1] = (7 - ((val >> 2) & 7)) * 8;
445 break;
446 }
447 adgold->adgold_mma_regs[1][adgold->adgold_mma_addr] = val;
448 break;
449 }
450 }
451
adgold_read(uint16_t addr,void * p)452 uint8_t adgold_read(uint16_t addr, void *p)
453 {
454 adgold_t *adgold = (adgold_t *)p;
455 uint8_t temp;
456
457 switch (addr & 7)
458 {
459 case 0: case 1:
460 temp = opl3_read(addr, &adgold->opl);
461 break;
462
463 case 2:
464 if (adgold->adgold_38x_state) /*Read from control chip*/
465 temp = adgold->adgold_status;
466 else
467 temp = opl3_read(addr, &adgold->opl);
468 break;
469
470 case 3:
471 if (adgold->adgold_38x_state)
472 {
473 if (adgold->adgold_38x_addr >= 0x19) temp = 0xff;
474 switch (adgold->adgold_38x_addr)
475 {
476 case 0x00: /*Control/ID*/
477 if (adgold->surround_enabled)
478 temp = 0x50; /*16-bit ISA, surround module, no telephone/CDROM*/
479 else
480 temp = 0x70; /*16-bit ISA, no telephone/surround/CD-ROM*/
481 break;
482
483 default:
484 temp = adgold->adgold_38x_regs[adgold->adgold_38x_addr];
485 }
486 }
487 else
488 temp = opl3_read(addr, &adgold->opl);
489 break;
490
491 case 4: case 6:
492 temp = adgold->adgold_mma_status;
493 adgold->adgold_mma_status = 0; /*JUKEGOLD expects timer status flags to auto-clear*/
494 adgold_update_irq_status(adgold);
495 break;
496 case 5:
497 if (adgold->adgold_mma_addr >= 0xf) temp = 0xff;
498 switch (adgold->adgold_mma_addr)
499 {
500 case 6: /*Timer 2 low*/
501 adgold->adgold_mma.timer2_read = adgold->adgold_mma.timer2_count;
502 temp = adgold->adgold_mma.timer2_read & 0xff;
503 break;
504 case 7: /*Timer 2 high*/
505 temp = adgold->adgold_mma.timer2_read >> 8;
506 break;
507
508 default:
509 temp = adgold->adgold_mma_regs[0][adgold->adgold_mma_addr];
510 break;
511 }
512 break;
513 case 7:
514 if (adgold->adgold_mma_addr >= 0xf) temp = 0xff;
515 temp = adgold->adgold_mma_regs[1][adgold->adgold_mma_addr];
516 break;
517 }
518 // if (addr > 0x389) pclog("adgold_read : addr %04X %02X\n", addr, temp);
519 return temp;
520 }
521
adgold_update(adgold_t * adgold)522 void adgold_update(adgold_t *adgold)
523 {
524 for (; adgold->pos < sound_pos_global; adgold->pos++)
525 {
526 adgold->mma_buffer[0][adgold->pos] = adgold->mma_buffer[1][adgold->pos] = 0;
527
528 if (adgold->adgold_mma_regs[0][9] & 0x20)
529 adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[0] / 2;
530 if (adgold->adgold_mma_regs[0][9] & 0x40)
531 adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[0] / 2;
532
533 if (adgold->adgold_mma_regs[1][9] & 0x20)
534 adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[1] / 2;
535 if (adgold->adgold_mma_regs[1][9] & 0x40)
536 adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[1] / 2;
537 }
538 }
539
adgold_mma_poll(adgold_t * adgold,int channel)540 void adgold_mma_poll(adgold_t *adgold, int channel)
541 {
542 int16_t dat;
543
544 adgold_update(adgold);
545
546 if (adgold->adgold_mma_fifo_start[channel] != adgold->adgold_mma_fifo_end[channel])
547 {
548 switch (adgold->adgold_mma_regs[channel][0xc] & 0x60)
549 {
550 case 0x00: /*8-bit*/
551 dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] * 256;
552 adgold->adgold_mma_out[channel] = dat;
553 adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255;
554 break;
555
556 case 0x40: /*12-bit sensible format*/
557 if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < 2)
558 return;
559
560 dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] & 0xf0;
561 adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255;
562 dat |= (adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] << 8);
563 adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255;
564 adgold->adgold_mma_out[channel] = dat;
565 break;
566 }
567
568 if (adgold->adgold_mma_regs[channel][0xc] & 1)
569 {
570 adgold_getsamp_dma(adgold, channel);
571 }
572 if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < adgold->adgold_mma_intpos[channel] && !(adgold->adgold_mma_status & 0x01))
573 {
574 // pclog("adgold_mma_poll - IRQ! %i\n", channel);
575 adgold->adgold_mma_status |= 1 << channel;
576 adgold_update_irq_status(adgold);
577 }
578 }
579 if (adgold->adgold_mma_fifo_start[channel] == adgold->adgold_mma_fifo_end[channel])
580 {
581 adgold->adgold_mma_enable[channel] = 0;
582 }
583 }
584
adgold_timer_poll(void * p)585 void adgold_timer_poll(void *p)
586 {
587 adgold_t *adgold = (adgold_t *)p;
588
589 while (adgold->adgold_mma_timer_count <= 0)
590 {
591 adgold->adgold_mma_timer_count += (int)((double)TIMER_USEC * 1.88964);
592 if (adgold->adgold_mma_regs[0][8] & 0x01) /*Timer 0*/
593 {
594 adgold->adgold_mma.timer0_count--;
595 if (!adgold->adgold_mma.timer0_count)
596 {
597 adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch;
598 // pclog("Timer 0 interrupt\n");
599 adgold->adgold_mma_status |= 0x10;
600 adgold_update_irq_status(adgold);
601 }
602 }
603 if (adgold->adgold_mma_regs[0][8] & 0x08) /*Base timer*/
604 {
605 adgold->adgold_mma.timerbase_count--;
606 if (!adgold->adgold_mma.timerbase_count)
607 {
608 adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch;
609 if (adgold->adgold_mma_regs[0][8] & 0x02) /*Timer 1*/
610 {
611 adgold->adgold_mma.timer1_count--;
612 if (!adgold->adgold_mma.timer1_count)
613 {
614 adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch;
615 // pclog("Timer 1 interrupt\n");
616 adgold->adgold_mma_status |= 0x20;
617 adgold_update_irq_status(adgold);
618 }
619 }
620 if (adgold->adgold_mma_regs[0][8] & 0x04) /*Timer 2*/
621 {
622 adgold->adgold_mma.timer2_count--;
623 if (!adgold->adgold_mma.timer2_count)
624 {
625 adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch;
626 // pclog("Timer 2 interrupt\n");
627 adgold->adgold_mma_status |= 0x40;
628 adgold_update_irq_status(adgold);
629 }
630 }
631 }
632 }
633
634 if (adgold->adgold_mma_enable[0])
635 {
636 adgold->adgold_mma.voice_count[0]--;
637 if (!adgold->adgold_mma.voice_count[0])
638 {
639 adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0];
640 adgold_mma_poll(adgold, 0);
641 }
642 }
643 if (adgold->adgold_mma_enable[1])
644 {
645 adgold->adgold_mma.voice_count[1]--;
646 if (!adgold->adgold_mma.voice_count[1])
647 {
648 adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1];
649 adgold_mma_poll(adgold, 1);
650 }
651 }
652 }
653 }
654
adgold_get_buffer(int32_t * buffer,int len,void * p)655 static void adgold_get_buffer(int32_t *buffer, int len, void *p)
656 {
657 adgold_t *adgold = (adgold_t *)p;
658 int16_t adgold_buffer[len*2];
659
660 int c;
661
662 opl3_update2(&adgold->opl);
663 adgold_update(adgold);
664
665 for (c = 0; c < len * 2; c += 2)
666 {
667 adgold_buffer[c] = ((adgold->opl.buffer[c] * adgold->fm_vol_l) >> 7) / 2;
668 adgold_buffer[c] += ((adgold->mma_buffer[0][c >> 1] * adgold->samp_vol_l) >> 7) / 4;
669 adgold_buffer[c+1] = ((adgold->opl.buffer[c+1] * adgold->fm_vol_r) >> 7) / 2;
670 adgold_buffer[c+1] += ((adgold->mma_buffer[1][c >> 1] * adgold->samp_vol_r) >> 7) / 4;
671 }
672
673 if (adgold->surround_enabled)
674 ym7128_apply(&adgold->ym7128, adgold_buffer, len);
675
676 switch (adgold->adgold_38x_regs[0x8] & 6)
677 {
678 case 0:
679 for (c = 0; c < len * 2; c++)
680 adgold_buffer[c] = 0;
681 break;
682 case 2: /*Left channel only*/
683 for (c = 0; c < len * 2; c += 2)
684 adgold_buffer[c+1] = adgold_buffer[c];
685 break;
686 case 4: /*Right channel only*/
687 for (c = 0; c < len * 2; c += 2)
688 adgold_buffer[c] = adgold_buffer[c+1];
689 break;
690 case 6: /*Left and right channels*/
691 break;
692 }
693
694 switch (adgold->adgold_38x_regs[0x8] & 0x18)
695 {
696 case 0x00: /*Forced mono*/
697 for (c = 0; c < len * 2; c += 2)
698 adgold_buffer[c] = adgold_buffer[c+1] = ((int32_t)adgold_buffer[c] + (int32_t)adgold_buffer[c+1]) / 2;
699 break;
700 case 0x08: /*Linear stereo*/
701 break;
702 case 0x10: /*Pseudo stereo*/
703 /*Filter left channel, leave right channel unchanged*/
704 /*Filter cutoff is largely a guess*/
705 for (c = 0; c < len * 2; c += 2)
706 adgold_buffer[c] += adgold_pseudo_stereo_iir(adgold_buffer[c]);
707 break;
708 case 0x18: /*Spatial stereo*/
709 /*Quite probably wrong, I only have the diagram in the TDA8425 datasheet
710 and a very vague understanding of how op-amps work to go on*/
711 for (c = 0; c < len * 2; c += 2)
712 {
713 int16_t l = adgold_buffer[c];
714 int16_t r = adgold_buffer[c+1];
715
716 adgold_buffer[c] += (r / 3) + ((l * 2) / 3);
717 adgold_buffer[c+1] += (l / 3) + ((r * 2) / 3);
718 }
719 break;
720 }
721
722 for (c = 0; c < len * 2; c += 2)
723 {
724 int32_t temp, lowpass, highpass;
725
726 /*Output is deliberately halved to avoid clipping*/
727 temp = ((int32_t)adgold_buffer[c] * adgold->vol_l) >> 17;
728 lowpass = adgold_lowpass_iir(0, temp);
729 highpass = adgold_highpass_iir(0, temp);
730 if (adgold->bass > 6)
731 temp += (lowpass * bass_attenuation[adgold->bass]) >> 14;
732 else if (adgold->bass < 6)
733 temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14);
734 if (adgold->treble > 6)
735 temp += (highpass * treble_attenuation[adgold->treble]) >> 14;
736 else if (adgold->treble < 6)
737 temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14);
738 if (temp < -32768)
739 temp = -32768;
740 if (temp > 32767)
741 temp = 32767;
742 buffer[c] += temp;
743
744 temp = ((int32_t)adgold_buffer[c+1] * adgold->vol_r) >> 17;
745 lowpass = adgold_lowpass_iir(1, temp);
746 highpass = adgold_highpass_iir(1, temp);
747 if (adgold->bass > 6)
748 temp += (lowpass * bass_attenuation[adgold->bass]) >> 14;
749 else if (adgold->bass < 6)
750 temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14);
751 if (adgold->treble > 6)
752 temp += (highpass * treble_attenuation[adgold->treble]) >> 14;
753 else if (adgold->treble < 6)
754 temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14);
755 if (temp < -32768)
756 temp = -32768;
757 if (temp > 32767)
758 temp = 32767;
759 buffer[c+1] += temp;
760 }
761
762 adgold->opl.pos = 0;
763 adgold->pos = 0;
764 }
765
766
adgold_init()767 void *adgold_init()
768 {
769 FILE *f;
770 int c;
771 double out;
772 int opl_emu;
773 adgold_t *adgold = malloc(sizeof(adgold_t));
774 memset(adgold, 0, sizeof(adgold_t));
775
776 adgold->surround_enabled = device_get_config_int("surround");
777 opl_emu = device_get_config_int("opl_emu");
778
779 opl3_init(&adgold->opl, opl_emu);
780 if (adgold->surround_enabled)
781 ym7128_init(&adgold->ym7128);
782
783 out = 65536.0; /*Main volume control ranges from +6 dB to -64 dB in 2 dB steps, then remaining settings are -80 dB (effectively 0)*/
784 for (c = 0x3f; c >= 0x1c; c--)
785 {
786 attenuation[c] = (int)out;
787 out /= 1.25963; /*2 dB steps*/
788 }
789 for (; c >= 0; c--)
790 attenuation[c] = 0;
791
792 f = nvrfopen("adgold.bin", "rb");
793 if (f)
794 {
795 fread(adgold->adgold_eeprom, 0x18, 1, f);
796 fclose(f);
797 }
798
799 adgold->adgold_status = 0xf;
800 adgold->adgold_38x_addr = 0;
801 adgold->adgold_eeprom[0x13] = 3 | (1 << 4); /*IRQ 7, DMA 1*/
802 adgold->adgold_eeprom[0x14] = 3 << 4; /*DMA 3*/
803 adgold->adgold_eeprom[0x15] = 0x388 / 8; /*Present at 388-38f*/
804 memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19);
805 adgold->vol_l = attenuation[adgold->adgold_eeprom[0x04] & 0x3f];
806 adgold->vol_r = attenuation[adgold->adgold_eeprom[0x05] & 0x3f];
807 adgold->bass = adgold->adgold_eeprom[0x06] & 0xf;
808 adgold->treble = adgold->adgold_eeprom[0x07] & 0xf;
809 adgold->fm_vol_l = (int)(int8_t)(adgold->adgold_eeprom[0x09] - 128);
810 adgold->fm_vol_r = (int)(int8_t)(adgold->adgold_eeprom[0x0a] - 128);
811 adgold->samp_vol_l = (int)(int8_t)(adgold->adgold_eeprom[0x0b] - 128);
812 adgold->samp_vol_r = (int)(int8_t)(adgold->adgold_eeprom[0x0c] - 128);
813
814 adgold->adgold_mma_enable[0] = 0;
815 adgold->adgold_mma_fifo_start[0] = adgold->adgold_mma_fifo_end[0] = 0;
816
817 /*388/389 are handled by adlib_init*/
818 io_sethandler(0x0388, 0x0008, adgold_read, NULL, NULL, adgold_write, NULL, NULL, adgold);
819
820 timer_add(adgold_timer_poll, &adgold->adgold_mma_timer_count, TIMER_ALWAYS_ENABLED, adgold);
821
822 sound_add_handler(adgold_get_buffer, adgold);
823
824 return adgold;
825 }
826
adgold_close(void * p)827 void adgold_close(void *p)
828 {
829 FILE *f;
830 adgold_t *adgold = (adgold_t *)p;
831
832 f = nvrfopen("adgold.bin", "wb");
833 if (f)
834 {
835 fwrite(adgold->adgold_eeprom, 0x18, 1, f);
836 fclose(f);
837 }
838
839 free(adgold);
840 }
841
842 static device_config_t adgold_config[] =
843 {
844 {
845 .name = "surround",
846 .description = "Surround module",
847 .type = CONFIG_BINARY,
848 .default_int = 1
849 },
850 {
851 .name = "opl_emu",
852 .description = "OPL emulator",
853 .type = CONFIG_SELECTION,
854 .selection =
855 {
856 {
857 .description = "DBOPL",
858 .value = OPL_DBOPL
859 },
860 {
861 .description = "NukedOPL",
862 .value = OPL_NUKED
863 },
864 },
865 .default_int = OPL_DBOPL
866 },
867 {
868 .type = -1
869 }
870 };
871
872 device_t adgold_device =
873 {
874 "AdLib Gold",
875 0,
876 adgold_init,
877 adgold_close,
878 NULL,
879 NULL,
880 NULL,
881 NULL,
882 adgold_config
883 };
884