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