PCem
view src/sound_gus.c @ 152:f6069ee5e9d7
Fixed terminal count on auto-init DMA. Fixed sound on All New World of Lemmings when using GUS.
| author | TomW |
|---|---|
| date | Sun Aug 24 14:08:17 2014 +0100 |
| parents | b53e148867e5 |
| children |
line source
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "ibm.h"
6 #include "device.h"
7 #include "dma.h"
8 #include "io.h"
9 #include "pic.h"
10 #include "sound.h"
11 #include "sound_gus.h"
12 #include "timer.h"
14 typedef struct gus_t
15 {
16 int reset;
18 int global;
19 uint32_t addr,dmaaddr;
20 int voice;
21 uint32_t start[32],end[32],cur[32];
22 uint32_t startx[32],endx[32],curx[32];
23 int rstart[32],rend[32];
24 int rcur[32];
25 uint16_t freq[32];
26 uint16_t rfreq[32];
27 uint8_t ctrl[32];
28 uint8_t rctrl[32];
29 int curvol[32];
30 int t1on,t2on;
31 uint8_t tctrl;
32 uint16_t t1,t2,t1l,t2l;
33 uint8_t irqstatus,irqstatus2;
34 uint8_t adcommand;
35 int waveirqs[32],rampirqs[32];
36 int voices;
37 uint8_t dmactrl;
39 int16_t out_l, out_r;
41 int16_t buffer[2][SOUNDBUFLEN];
42 int pos;
44 int samp_timer, samp_latch;
46 uint8_t *ram;
48 int irqnext;
50 int timer_1, timer_2;
52 int irq, dma, irq_midi;
53 int latch_enable;
55 uint8_t sb_2xa, sb_2xc, sb_2xe;
56 uint8_t sb_ctrl;
57 int sb_nmi;
59 uint8_t reg_ctrl;
61 uint8_t ad_status, ad_data;
62 uint8_t ad_timer_ctrl;
64 uint8_t midi_ctrl, midi_status;
65 uint8_t midi_data;
66 int midi_loopback;
68 uint8_t gp1, gp2;
69 uint16_t gp1_addr, gp2_addr;
71 uint8_t usrr;
72 } gus_t;
74 static int gus_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15};
75 static int gus_irqs_midi[8] = {-1, 2, 5, 3, 7, 11, 12, 15};
76 static int gus_dmas[8] = {-1, 1, 3, 5, 6, 7, -1, -1};
78 int gusfreqs[]=
79 {
80 44100,41160,38587,36317,34300,32494,30870,29400,28063,26843,25725,24696,
81 23746,22866,22050,21289,20580,19916,19293
82 };
84 double vol16bit[4096];
86 void pollgusirqs(gus_t *gus)
87 {
88 int c;
90 gus->irqstatus&=~0x60;
91 for (c=0;c<32;c++)
92 {
93 if (gus->waveirqs[c])
94 {
95 // gus->waveirqs[c]=0;
96 gus->irqstatus2=0x60|c;
97 if (gus->rampirqs[c]) gus->irqstatus2 |= 0x80;
98 gus->irqstatus|=0x20;
99 // printf("Voice IRQ %i %02X %i\n",c,gus->irqstatus2,ins);
100 if (gus->irq != -1)
101 picint(1 << gus->irq);
102 return;
103 }
104 if (gus->rampirqs[c])
105 {
106 // gus->rampirqs[c]=0;
107 gus->irqstatus2=0xA0|c;
108 gus->irqstatus|=0x40;
109 // printf("Ramp IRQ %i %02X %i\n",c,gus->irqstatus2,ins);
110 if (gus->irq != -1)
111 picint(1 << gus->irq);
112 return;
113 }
114 }
115 gus->irqstatus2=0xE0;
116 // gus->irqstatus&=~0x20;
117 if (!gus->irqstatus && gus->irq != -1) picintc(1 << gus->irq);
118 }
120 enum
121 {
122 MIDI_INT_RECEIVE = 0x01,
123 MIDI_INT_TRANSMIT = 0x02,
124 MIDI_INT_MASTER = 0x80
125 };
127 enum
128 {
129 MIDI_CTRL_TRANSMIT_MASK = 0x60,
130 MIDI_CTRL_TRANSMIT = 0x20,
131 MIDI_CTRL_RECEIVE = 0x80
132 };
134 enum
135 {
136 GUS_INT_MIDI_TRANSMIT = 0x01,
137 GUS_INT_MIDI_RECEIVE = 0x02
138 };
140 enum
141 {
142 GUS_TIMER_CTRL_AUTO = 0x01
143 };
145 void gus_midi_update_int_status(gus_t *gus)
146 {
147 gus->midi_status &= ~MIDI_INT_MASTER;
148 if ((gus->midi_ctrl & MIDI_CTRL_TRANSMIT_MASK) == MIDI_CTRL_TRANSMIT && (gus->midi_status & MIDI_INT_TRANSMIT))
149 {
150 gus->midi_status |= MIDI_INT_MASTER;
151 gus->irqstatus |= GUS_INT_MIDI_TRANSMIT;
152 }
153 else
154 gus->irqstatus &= ~GUS_INT_MIDI_TRANSMIT;
156 if ((gus->midi_ctrl & MIDI_CTRL_RECEIVE) && (gus->midi_status & MIDI_INT_RECEIVE))
157 {
158 gus->midi_status |= MIDI_INT_MASTER;
159 gus->irqstatus |= GUS_INT_MIDI_RECEIVE;
160 }
161 else
162 gus->irqstatus &= ~GUS_INT_MIDI_RECEIVE;
164 if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != -1))
165 {
166 // pclog("Take MIDI IRQ\n");
167 picint(1 << gus->irq_midi);
168 }
169 }
171 void writegus(uint16_t addr, uint8_t val, void *p)
172 {
173 gus_t *gus = (gus_t *)p;
174 int c, d;
175 int old;
176 // pclog("Write GUS %04X %02X %04X:%04X\n",addr,val,CS,pc);
177 if (gus->latch_enable && addr != 0x24b)
178 gus->latch_enable = 0;
179 switch (addr)
180 {
181 case 0x340: /*MIDI control*/
182 old = gus->midi_ctrl;
183 gus->midi_ctrl = val;
185 if ((val & 3) == 3)
186 gus->midi_status = 0;
187 else if ((old & 3) == 3)
188 {
189 gus->midi_status |= MIDI_INT_TRANSMIT;
190 // pclog("MIDI_INT_TRANSMIT\n");
191 }
192 gus_midi_update_int_status(gus);
193 break;
195 case 0x341: /*MIDI data*/
196 if (gus->midi_loopback)
197 {
198 gus->midi_status |= MIDI_INT_RECEIVE;
199 gus->midi_data = val;
200 }
201 else
202 gus->midi_status |= MIDI_INT_TRANSMIT;
203 break;
205 case 0x342: /*Voice select*/
206 gus->voice=val&31;
207 break;
208 case 0x343: /*Global select*/
209 gus->global=val;
210 break;
211 case 0x344: /*Global low*/
212 // if (gus->global!=0x43 && gus->global!=0x44) printf("Writing register %02X %02X %02X %i\n",gus->global,gus->voice,val, ins);
213 switch (gus->global)
214 {
215 case 0: /*Voice control*/
216 // if (val&1 && !(gus->ctrl[gus->voice]&1)) printf("Voice on %i\n",gus->voice);
217 gus->ctrl[gus->voice]=val;
218 break;
219 case 1: /*Frequency control*/
220 gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF00)|val;
221 break;
222 case 2: /*Start addr high*/
223 gus->startx[gus->voice]=(gus->startx[gus->voice]&0xF807F)|(val<<7);
224 gus->start[gus->voice]=(gus->start[gus->voice]&0x1F00FFFF)|(val<<16);
225 // printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]);
226 break;
227 case 3: /*Start addr low*/
228 gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFFFF00)|val;
229 // printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]);
230 break;
231 case 4: /*End addr high*/
232 gus->endx[gus->voice]=(gus->endx[gus->voice]&0xF807F)|(val<<7);
233 gus->end[gus->voice]=(gus->end[gus->voice]&0x1F00FFFF)|(val<<16);
234 // printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]);
235 break;
236 case 5: /*End addr low*/
237 gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFFFF00)|val;
238 // printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]);
239 break;
241 case 0x6: /*Ramp frequency*/
242 gus->rfreq[gus->voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6))));
243 // printf("RFREQ %02X %i %i %f\n",val,gus->voice,gus->rfreq[gus->voice],(double)(val & 63)/(double)(1 << (3*(val >> 6))));
244 break;
246 case 0x9: /*Current volume*/
247 gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 6)) | (val << 6);
248 // printf("Vol %i is %04X\n",gus->voice,gus->curvol[gus->voice]);
249 break;
251 case 0xA: /*Current addr high*/
252 gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1F00FFFF)|(val<<16);
253 gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8);
254 // gus->cur[gus->voice]=(gus->cur[gus->voice]&0x0F807F00)|((val<<7)<<8);
255 // printf("Write %i cur %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]);
256 break;
257 case 0xB: /*Current addr low*/
258 gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFFFF00)|val;
259 // printf("Write %i cur %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]);
260 break;
262 case 0x42: /*DMA address low*/
263 gus->dmaaddr=(gus->dmaaddr&0xFF000)|(val<<4);
264 break;
266 case 0x43: /*Address low*/
267 gus->addr=(gus->addr&0xFFF00)|val;
268 break;
269 case 0x45: /*Timer control*/
270 // printf("Timer control %02X\n",val);
271 gus->tctrl=val;
272 break;
273 }
274 break;
275 case 0x345: /*Global high*/
276 // if (gus->global!=0x43 && gus->global!=0x44) printf("HWriting register %02X %02X %02X %04X:%04X %i %X\n",gus->global,gus->voice,val,CS,pc, ins, gus->rcur[1] >> 10);
277 switch (gus->global)
278 {
279 case 0: /*Voice control*/
280 if (!(val&1) && gus->ctrl[gus->voice]&1)
281 {
282 // printf("Voice on %i - start %05X end %05X freq %04X\n",gus->voice,gus->start[gus->voice],gus->end[gus->voice],gus->freq[gus->voice]);
283 // if (val&0x40) gus->cur[gus->voice]=gus->end[gus->voice]<<8;
284 // else gus->cur[gus->voice]=gus->start[gus->voice]<<8;
285 }
287 gus->ctrl[gus->voice] = val & 0x7f;
289 old = gus->waveirqs[gus->voice];
290 gus->waveirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0;
291 if (gus->waveirqs[gus->voice] != old)
292 pollgusirqs(gus);
293 break;
294 case 1: /*Frequency control*/
295 gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF)|(val<<8);
296 break;
297 case 2: /*Start addr high*/
298 gus->startx[gus->voice]=(gus->startx[gus->voice]&0x07FFF)|(val<<15);
299 gus->start[gus->voice]=(gus->start[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24);
300 // printf("Write %i start %08X %08X %02X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice],val);
301 break;
302 case 3: /*Start addr low*/
303 gus->startx[gus->voice]=(gus->startx[gus->voice]&0xFFF80)|(val&0x7F);
304 gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFF00FF)|(val<<8);
305 // printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]);
306 break;
307 case 4: /*End addr high*/
308 gus->endx[gus->voice]=(gus->endx[gus->voice]&0x07FFF)|(val<<15);
309 gus->end[gus->voice]=(gus->end[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24);
310 // printf("Write %i end %08X %08X %02X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice],val);
311 break;
312 case 5: /*End addr low*/
313 gus->endx[gus->voice]=(gus->endx[gus->voice]&0xFFF80)|(val&0x7F);
314 gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFF00FF)|(val<<8);
315 // printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]);
316 break;
318 case 0x6: /*Ramp frequency*/
319 gus->rfreq[gus->voice] = (int)( (double)((val & 63) * (1 << 10))/(double)(1 << (3 * (val >> 6))));
320 // pclog("Ramp freq %02X %i %i %f %i\n", val, gus->voice, gus->rfreq[gus->voice], (double)(val & 63)/(double)(1 << (3*(val >> 6))), ins);
321 break;
322 case 0x7: /*Ramp start*/
323 gus->rstart[gus->voice] = val << 14;
324 // pclog("Ramp start %04X\n", gus->rstart[gus->voice] >> 10);
325 break;
326 case 0x8: /*Ramp end*/
327 gus->rend[gus->voice] = val << 14;
328 // pclog("Ramp end %04X\n", gus->rend[gus->voice] >> 10);
329 break;
330 case 0x9: /*Current volume*/
331 gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 14)) | (val << 14);
332 // printf("Vol %i is %04X\n",gus->voice,gus->curvol[gus->voice]);
333 break;
335 case 0xA: /*Current addr high*/
336 gus->cur[gus->voice]=(gus->cur[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24);
337 gus->curx[gus->voice]=(gus->curx[gus->voice]&0x07FFF00)|((val<<15)<<8);
338 // printf("Write %i cur %08X %08X %02X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice],val);
339 // gus->cur[gus->voice]=(gus->cur[gus->voice]&0x007FFF00)|((val<<15)<<8);
340 break;
341 case 0xB: /*Current addr low*/
342 gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFF00FF)|(val<<8);
343 gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8);
344 // gus->cur[gus->voice]=(gus->cur[gus->voice]&0x0FFF8000)|((val&0x7F)<<8);
345 // printf("Write %i cur %08X %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]);
346 break;
347 case 0xD: /*Ramp control*/
348 old = gus->rampirqs[gus->voice];
349 gus->rctrl[gus->voice] = val & 0x7F;
350 gus->rampirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0;
351 if (gus->rampirqs[gus->voice] != old)
352 pollgusirqs(gus);
353 // printf("Ramp control %02i %02X %02X %i\n",gus->voice,val,gus->rampirqs[gus->voice],ins);
354 break;
356 case 0xE:
357 gus->voices=(val&63)+1;
358 if (gus->voices>32) gus->voices=32;
359 if (gus->voices<14) gus->voices=14;
360 gus->global=val;
361 // printf("GUS voices %i\n",val&31);
362 if (gus->voices < 14)
363 gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0));
364 else
365 gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14]));
366 break;
368 case 0x41: /*DMA*/
369 if (val&1 && gus->dma != -1)
370 {
371 // printf("DMA start! %05X %02X\n",gus->dmaaddr,val);
372 if (val & 2)
373 {
374 c=0;
375 while (c<65536)
376 {
377 int dma_result;
378 d = gus->ram[gus->dmaaddr];
379 if (val & 0x80) d ^= 0x80;
380 dma_result = dma_channel_write(gus->dma, d);
381 if (dma_result == DMA_NODATA)
382 break;
383 gus->dmaaddr++;
384 gus->dmaaddr&=0xFFFFF;
385 c++;
386 if (dma_result & DMA_OVER)
387 break;
388 }
389 // printf("GUS->MEM Transferred %i bytes\n",c);
390 gus->dmactrl=val&~0x40;
391 if (val&0x20) gus->irqnext=1;
392 }
393 else
394 {
395 c=0;
396 while (c<65536)
397 {
398 d = dma_channel_read(gus->dma);
399 if (d == DMA_NODATA)
400 break;
401 if (val&0x80) d^=0x80;
402 gus->ram[gus->dmaaddr]=d;
403 gus->dmaaddr++;
404 gus->dmaaddr&=0xFFFFF;
405 c++;
406 if (d & DMA_OVER)
407 break;
408 }
409 // printf("MEM->GUS Transferred %i bytes\n",c);
410 gus->dmactrl=val&~0x40;
411 if (val&0x20) gus->irqnext=1;
412 }
413 // exit(-1);
414 }
415 break;
417 case 0x42: /*DMA address low*/
418 gus->dmaaddr=(gus->dmaaddr&0xFF0)|(val<<12);
419 break;
421 case 0x43: /*Address low*/
422 gus->addr=(gus->addr&0xF00FF)|(val<<8);
423 break;
424 case 0x44: /*Address high*/
425 gus->addr=(gus->addr&0xFFFF)|((val<<16)&0xF0000);
426 break;
427 case 0x45: /*Timer control*/
428 if (!(val&4)) gus->irqstatus&=~4;
429 if (!(val&8)) gus->irqstatus&=~8;
430 if (!(val & 0x20))
431 {
432 gus->ad_status &= ~0x18;
433 nmi = 0;
434 }
435 if (!(val & 0x02))
436 {
437 gus->ad_status &= ~0x01;
438 nmi = 0;
439 }
440 // printf("Timer control %02X\n",val);
441 /* if ((val&4) && !(gus->tctrl&4))
442 {
443 gus->t1=gus->t1l;
444 gus->t1on=1;
445 }*/
446 gus->tctrl=val;
447 gus->sb_ctrl = val;
448 break;
449 case 0x46: /*Timer 1*/
450 gus->t1 = gus->t1l = val;
451 gus->t1on = 1;
452 // printf("GUS timer 1 %i\n",val);
453 break;
454 case 0x47: /*Timer 2*/
455 gus->t2 = gus->t2l = val;
456 gus->t2on = 1;
457 // printf("GUS timer 2 %i\n",val);
458 break;
460 case 0x4c: /*Reset*/
461 gus->reset = val;
462 break;
463 }
464 break;
465 case 0x347: /*DRAM access*/
466 gus->ram[gus->addr]=val;
467 // pclog("GUS RAM write %05X %02X\n",gus->addr,val);
468 gus->addr&=0xFFFFF;
469 break;
470 case 0x248: case 0x388:
471 gus->adcommand = val;
472 // pclog("Setting ad command %02X %02X %p\n", val, gus->adcommand, &gus->adcommand);
473 break;
475 case 0x389:
476 if ((gus->tctrl & GUS_TIMER_CTRL_AUTO) || gus->adcommand != 4)
477 {
478 gus->ad_data = val;
479 gus->ad_status |= 0x01;
480 if (gus->sb_ctrl & 0x02)
481 {
482 if (gus->sb_nmi)
483 nmi = 1;
484 else if (gus->irq != -1)
485 picint(1 << gus->irq);
486 }
487 }
488 else if (!(gus->tctrl & GUS_TIMER_CTRL_AUTO) && gus->adcommand == 4)
489 {
490 if (val & 0x80)
491 {
492 gus->ad_status &= ~0x60;
493 }
494 else
495 {
496 gus->ad_timer_ctrl = val;
498 if (val & 0x01)
499 gus->t1on = 1;
500 else
501 gus->t1 = gus->t1l;
503 if (val & 0x02)
504 gus->t2on = 1;
505 else
506 gus->t2 = gus->t2l;
507 }
508 }
509 break;
511 case 0x240:
512 gus->midi_loopback = val & 0x20;
513 gus->latch_enable = (val & 0x40) ? 2 : 1;
514 break;
516 case 0x24b:
517 switch (gus->reg_ctrl & 0x07)
518 {
519 case 0:
520 if (gus->latch_enable == 1)
521 gus->dma = gus_dmas[val & 7];
522 if (gus->latch_enable == 2)
523 {
524 gus->irq = gus_irqs[val & 7];
525 if (val & 0x40)
526 gus->irq_midi = gus->irq;
527 else
528 gus->irq_midi = gus_irqs_midi[(val >> 3) & 7];
530 gus->sb_nmi = val & 0x80;
531 }
532 gus->latch_enable = 0;
533 // pclog("IRQ %i DMA %i\n", gus->irq, gus->dma);
534 break;
535 case 1:
536 gus->gp1 = val;
537 break;
538 case 2:
539 gus->gp2 = val;
540 break;
541 case 3:
542 gus->gp1_addr = val;
543 break;
544 case 4:
545 gus->gp2_addr = val;
546 break;
547 case 5:
548 gus->usrr = 0;
549 break;
550 case 6:
551 break;
552 }
553 break;
555 case 0x246:
556 gus->ad_status |= 0x08;
557 if (gus->sb_ctrl & 0x20)
558 {
559 if (gus->sb_nmi)
560 nmi = 1;
561 else if (gus->irq != -1)
562 picint(1 << gus->irq);
563 }
564 break;
565 case 0x24a:
566 gus->sb_2xa = val;
567 break;
568 case 0x24c:
569 gus->ad_status |= 0x10;
570 if (gus->sb_ctrl & 0x20)
571 {
572 if (gus->sb_nmi)
573 nmi = 1;
574 else if (gus->irq != -1)
575 picint(1 << gus->irq);
576 }
577 case 0x24d:
578 gus->sb_2xc = val;
579 break;
580 case 0x24e:
581 gus->sb_2xe = val;
582 break;
583 case 0x24f:
584 gus->reg_ctrl = val;
585 break;
586 }
587 }
589 uint8_t readgus(uint16_t addr, void *p)
590 {
591 gus_t *gus = (gus_t *)p;
592 uint8_t val;
593 // /*if (addr!=0x246) */printf("Read GUS %04X %04X(%06X):%04X %02X\n",addr,CS,cs,pc,gus->global);
594 switch (addr)
595 {
596 case 0x340: /*MIDI status*/
597 val = gus->midi_status;
598 // pclog("Read MIDI status %02X\n", val);
599 break;
601 case 0x341: /*MIDI data*/
602 val = gus->midi_data;
603 gus->midi_status &= ~MIDI_INT_RECEIVE;
604 gus_midi_update_int_status(gus);
605 break;
607 case 0x240: return 0;
608 case 0x246: /*IRQ status*/
609 val = gus->irqstatus & ~0x10;
610 if (gus->ad_status & 0x19)
611 val |= 0x10;
612 // pclog("Read IRQ status %02X\n", val);
613 return val;
615 case 0x24F: return 0;
616 case 0x342: return gus->voice;
617 case 0x343: return gus->global;
618 case 0x344: /*Global low*/
619 // /*if (gus->global!=0x43 && gus->global!=0x44) */printf("Reading register %02X %02X\n",gus->global,gus->voice);
620 switch (gus->global)
621 {
622 case 0x82: /*Start addr high*/
623 return gus->start[gus->voice]>>16;
624 case 0x83: /*Start addr low*/
625 return gus->start[gus->voice]&0xFF;
627 case 0x89: /*Current volume*/
628 return gus->rcur[gus->voice]>>6;
629 case 0x8A: /*Current addr high*/
630 return gus->cur[gus->voice]>>16;
631 case 0x8B: /*Current addr low*/
632 return gus->cur[gus->voice]&0xFF;
634 case 0x8F: /*IRQ status*/
635 val=gus->irqstatus2;
636 // pclog("Read IRQ status - %02X\n",val);
637 gus->rampirqs[gus->irqstatus2&0x1F]=0;
638 gus->waveirqs[gus->irqstatus2&0x1F]=0;
639 pollgusirqs(gus);
640 return val;
642 case 0x00: case 0x01: case 0x02: case 0x03:
643 case 0x04: case 0x05: case 0x06: case 0x07:
644 case 0x08: case 0x09: case 0x0a: case 0x0b:
645 case 0x0c: case 0x0d: case 0x0e: case 0x0f:
646 val = 0xff;
647 break;
649 // default:
650 // fatal("Bad GUS global low read %02X\n",gus->global);
651 }
652 break;
653 case 0x345: /*Global high*/
654 // /*if (gus->global!=0x43 && gus->global!=0x44) */printf("HReading register %02X %02X\n",gus->global,gus->voice);
655 switch (gus->global)
656 {
657 case 0x80: /*Voice control*/
658 // pclog("Read voice control %02i %02X\n", gus->voice, gus->ctrl[gus->voice]|(gus->waveirqs[gus->voice]?0x80:0));
659 return gus->ctrl[gus->voice]|(gus->waveirqs[gus->voice]?0x80:0);
661 case 0x82: /*Start addr high*/
662 return gus->start[gus->voice]>>24;
663 case 0x83: /*Start addr low*/
664 return gus->start[gus->voice]>>8;
666 case 0x89: /*Current volume*/
667 // pclog("Read current volume %i\n", gus->rcur[gus->voice] >> 14);
668 return gus->rcur[gus->voice]>>14;
670 case 0x8A: /*Current addr high*/
671 return gus->cur[gus->voice]>>24;
672 case 0x8B: /*Current addr low*/
673 return gus->cur[gus->voice]>>8;
675 case 0x8D:
676 // pclog("Read ramp control %02X %04X %08X %08X %08X\n",gus->rctrl[gus->voice]|(gus->rampirqs[gus->voice]?0x80:0),gus->rcur[gus->voice] >> 14,gus->rfreq[gus->voice],gus->rstart[gus->voice],gus->rend[gus->voice]);
677 return gus->rctrl[gus->voice]|(gus->rampirqs[gus->voice]?0x80:0);
679 case 0x8F: /*IRQ status*/
680 // pclog("Read IRQ 1\n");
681 val=gus->irqstatus2;
682 gus->rampirqs[gus->irqstatus2&0x1F]=0;
683 gus->waveirqs[gus->irqstatus2&0x1F]=0;
684 pollgusirqs(gus);
685 // pclog("Read IRQ status - %02X %i %i\n",val, gus->waveirqs[gus->irqstatus2&0x1F], gus->rampirqs[gus->irqstatus2&0x1F]);
686 return val;
688 case 0x41: /*DMA control*/
689 val=gus->dmactrl|((gus->irqstatus&0x80)?0x40:0);
690 gus->irqstatus&=~0x80;
691 return val;
692 case 0x45: /*Timer control*/
693 return gus->tctrl;
694 case 0x49: /*Sampling control*/
695 return 0;
697 case 0x00: case 0x01: case 0x02: case 0x03:
698 case 0x04: case 0x05: case 0x06: case 0x07:
699 case 0x08: case 0x09: case 0x0a: case 0x0b:
700 case 0x0c: case 0x0d: case 0x0e: case 0x0f:
701 val = 0xff;
702 break;
704 // default:
705 // fatal("Bad GUS global high read %02X\n",gus->global);
706 }
707 break;
708 case 0x346: return 0xff;
709 case 0x347: /*DRAM access*/
710 val=gus->ram[gus->addr];
711 // pclog("GUS RAM read %05X %02X\n",gus->addr,val);
712 gus->addr&=0xFFFFF;
713 return val;
714 case 0x349: return 0;
715 case 0x746: /*Revision level*/
716 return 0xff; /*Pre 3.7 - no mixer*/
718 case 0x24b:
719 switch (gus->reg_ctrl & 0x07)
720 {
721 case 1:
722 val = gus->gp1;
723 break;
724 case 2:
725 val = gus->gp2;
726 break;
727 case 3:
728 val = gus->gp1_addr;
729 break;
730 case 4:
731 val = gus->gp2_addr;
732 break;
733 }
734 break;
736 case 0x24c:
737 val = gus->sb_2xc;
738 if (gus->reg_ctrl & 0x20)
739 gus->sb_2xc &= 0x80;
740 break;
741 case 0x24e:
742 /* gus->ad_status |= 0x10;
743 if (gus->reg_ctrl & 0x80)
744 {
745 gus->reg_ctrl_r |= 0x80;
746 if (gus->sb_nmi)
747 nmi = 1;
748 else
749 picint(1 << gus->irq);
750 }*/
751 return gus->sb_2xe;
753 case 0x248: case 0x388:
754 // pclog("Read ad_status %02X\n", gus->ad_status);
755 if (gus->tctrl & GUS_TIMER_CTRL_AUTO)
756 val = gus->sb_2xa;
757 else
758 {
759 val = gus->ad_status & ~(gus->ad_timer_ctrl & 0x60);
760 if (val & 0x60)
761 val |= 0x80;
762 }
763 break;
765 case 0x249:
766 gus->ad_status &= ~0x01;
767 nmi = 0;
768 case 0x389:
769 val = gus->ad_data;
770 break;
772 case 0x24A:
773 val = gus->adcommand;
774 // pclog("Read ad command %02X %02X %p\n", gus->adcommand, val, &gus->adcommand);
775 break;
777 }
778 // printf("Bad GUS read %04X! %02X\n",addr,gus->global);
779 // exit(-1);
780 return val;
781 }
783 void gus_poll_timer_1(void *p)
784 {
785 gus_t *gus = (gus_t *)p;
787 gus->timer_1 += (TIMER_USEC * 80);
788 // pclog("gus_poll_timer_1 %i %i %i %i %02X\n", gustime, gus->t1on, gus->t1, gus->t1l, gus->tctrl);
789 if (gus->t1on)
790 {
791 gus->t1++;
792 if (gus->t1 > 0xFF)
793 {
794 // gus->t1on=0;
795 gus->t1=gus->t1l;
796 gus->ad_status |= 0x40;
797 if (gus->tctrl&4)
798 {
799 if (gus->irq != -1)
800 picint(1 << gus->irq);
801 gus->ad_status |= 0x04;
802 gus->irqstatus |= 0x04;
803 // pclog("GUS T1 IRQ!\n");
804 }
805 }
806 }
807 if (gus->irqnext)
808 {
809 // pclog("Take IRQ\n");
810 gus->irqnext=0;
811 gus->irqstatus|=0x80;
812 if (gus->irq != -1)
813 picint(1 << gus->irq);
814 }
815 gus_midi_update_int_status(gus);
816 }
818 void gus_poll_timer_2(void *p)
819 {
820 gus_t *gus = (gus_t *)p;
822 gus->timer_2 += (TIMER_USEC * 320);
823 // pclog("pollgus2 %i %i %i %i %02X\n", gustime, gus->t2on, gus->t2, gus->t2l, gus->tctrl);
824 if (gus->t2on)
825 {
826 gus->t2++;
827 if (gus->t2 > 0xFF)
828 {
829 // gus->t2on=0;
830 gus->t2=gus->t2l;
831 gus->ad_status |= 0x20;
832 if (gus->tctrl&8)
833 {
834 if (gus->irq != -1)
835 picint(1 << gus->irq);
836 gus->ad_status |= 0x02;
837 gus->irqstatus |= 0x08;
838 // pclog("GUS T2 IRQ!\n");
839 }
840 }
841 }
842 if (gus->irqnext)
843 {
844 // pclog("Take IRQ\n");
845 gus->irqnext=0;
846 gus->irqstatus|=0x80;
847 if (gus->irq != -1)
848 picint(1 << gus->irq);
849 }
850 }
852 void gus_poll_wave(void *p)
853 {
854 gus_t *gus = (gus_t *)p;
855 uint32_t addr;
856 int d;
857 int16_t v;
858 int32_t vl;
859 int update_irqs = 0;
861 gus->samp_timer += gus->samp_latch;
863 gus->out_l = gus->out_r = 0;
865 if ((gus->reset & 3) != 3)
866 return;
867 //pclog("gus_poll_wave\n");
868 for (d=0;d<32;d++)
869 {
870 if (!(gus->ctrl[d] & 3))
871 {
872 if (gus->ctrl[d] & 4)
873 {
874 addr = gus->cur[d] >> 9;
875 addr = (addr & 0xC0000) | ((addr << 1) & 0x3FFFE);
876 if (!(gus->freq[d] >> 10)) /*Interpolate*/
877 {
878 vl = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80) * (511 - (gus->cur[d] & 511));
879 vl += (int16_t)(int8_t)((gus->ram[(addr + 3) & 0xFFFFF] ^ 0x80) - 0x80) * (gus->cur[d] & 511);
880 v = vl >> 9;
881 }
882 else
883 v = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80);
884 }
885 else
886 {
887 if (!(gus->freq[d] >> 10)) /*Interpolate*/
888 {
889 vl = ((int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80)) * (511 - (gus->cur[d] & 511));
890 vl += ((int8_t)((gus->ram[((gus->cur[d] >> 9) + 1) & 0xFFFFF] ^ 0x80) - 0x80)) * (gus->cur[d] & 511);
891 v = vl >> 9;
892 }
893 else
894 v = (int16_t)(int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80);
895 }
897 // pclog("Voice %i : %04X %05X %04X ", d, v, gus->cur[d] >> 9, gus->rcur[d] >> 10);
898 if ((gus->rcur[d] >> 14) > 4095) v = (int16_t)(float)(v) * 24.0 * vol16bit[4095];
899 else v = (int16_t)(float)(v) * 24.0 * vol16bit[(gus->rcur[d]>>10) & 4095];
900 // pclog("%f %04X\n", vol16bit[(gus->rcur[d]>>10) & 4095], v);
902 gus->out_l += v;
903 gus->out_r += v;
905 if (gus->ctrl[d]&0x40)
906 {
907 gus->cur[d] -= (gus->freq[d] >> 1);
908 if (gus->cur[d] <= gus->start[d])
909 {
910 int diff = gus->start[d] - gus->cur[d];
911 if (!(gus->rctrl[d]&4))
912 {
913 if (!(gus->ctrl[d]&8))
914 {
915 gus->ctrl[d] |= 1;
916 gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d];
917 }
918 else
919 {
920 if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40;
921 gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff);
922 }
923 }
924 if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d])
925 {
926 gus->waveirqs[d] = 1;
927 update_irqs = 1;
928 // pclog("Causing wave IRQ %02X %i\n", gus->ctrl[d], d);
929 }
930 }
931 }
932 else
933 {
934 gus->cur[d] += (gus->freq[d] >> 1);
936 if (gus->cur[d] >= gus->end[d])
937 {
938 int diff = gus->cur[d] - gus->end[d];
939 if (!(gus->rctrl[d]&4))
940 {
941 if (!(gus->ctrl[d]&8))
942 {
943 gus->ctrl[d] |= 1;
944 gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d];
945 }
946 else
947 {
948 if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40;
949 gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff);
950 }
951 }
952 if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d])
953 {
954 gus->waveirqs[d] = 1;
955 update_irqs = 1;
956 // pclog("Causing wave IRQ %02X %i\n", gus->ctrl[d], d);
957 }
958 }
959 }
960 }
961 if (!(gus->rctrl[d] & 3))
962 {
963 if (gus->rctrl[d] & 0x40)
964 {
965 gus->rcur[d] -= gus->rfreq[d];
966 if (gus->rcur[d] <= gus->rstart[d])
967 {
968 int diff = gus->rstart[d] - gus->rcur[d];
969 if (!(gus->rctrl[d] & 8))
970 {
971 gus->rctrl[d] |= 1;
972 gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d];
973 }
974 else
975 {
976 if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40;
977 gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff);
978 }
980 if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d])
981 {
982 gus->rampirqs[d] = 1;
983 update_irqs = 1;
984 // pclog("Causing ramp IRQ %02X %i\n",gus->rctrl[d], d);
985 }
986 }
987 }
988 else
989 {
990 gus->rcur[d] += gus->rfreq[d];
991 // if (d == 1) printf("RCUR+ %i %08X %08X %08X %08X\n",d,gus->rfreq[d],gus->rcur[d],gus->rstart[d],gus->rend[d]);
992 if (gus->rcur[d] >= gus->rend[d])
993 {
994 int diff = gus->rcur[d] - gus->rend[d];
995 if (!(gus->rctrl[d] & 8))
996 {
997 gus->rctrl[d] |= 1;
998 gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d];
999 }
1000 else
1001 {
1002 if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40;
1003 gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff);
1004 }
1006 if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d])
1007 {
1008 gus->rampirqs[d] = 1;
1009 update_irqs = 1;
1010 // pclog("Causing ramp IRQ %02X %i\n",gus->rctrl[d], d);
1011 }
1012 }
1013 }
1014 }
1015 }
1017 if (update_irqs)
1018 pollgusirqs(gus);
1019 }
1021 void gus_poll(void *p)
1022 {
1023 gus_t *gus = (gus_t *)p;
1025 if (gus->pos >= SOUNDBUFLEN)
1026 return;
1028 //pclog("gus_poll\n");
1029 gus->buffer[0][gus->pos] = gus->out_l;
1030 gus->buffer[1][gus->pos] = gus->out_r;
1032 gus->pos++;
1033 }
1035 static void gus_get_buffer(int16_t *buffer, int len, void *p)
1036 {
1037 gus_t *gus = (gus_t *)p;
1038 int c;
1040 for (c = 0; c < len * 2; c++)
1041 {
1042 buffer[c] += gus->buffer[c & 1][c >> 1];
1043 }
1045 gus->pos = 0;
1046 }
1049 void *gus_init()
1050 {
1051 int c;
1052 double out = 1.0;
1053 gus_t *gus = malloc(sizeof(gus_t));
1054 memset(gus, 0, sizeof(gus_t));
1056 gus->ram = malloc(1 << 20);
1057 memset(gus->ram, 0, 1 << 20);
1059 pclog("gus_init\n");
1061 for (c=0;c<32;c++)
1062 {
1063 gus->ctrl[c]=1;
1064 gus->rctrl[c]=1;
1065 gus->rfreq[c]=63*512;
1066 }
1068 for (c=4095;c>=0;c--) {
1069 vol16bit[c]=out;//(float)c/4095.0;//out;
1070 out/=1.002709201; /* 0.0235 dB Steps */
1071 }
1073 printf("Top volume %f %f %f %f\n",vol16bit[4095],vol16bit[3800],vol16bit[3000],vol16bit[2048]);
1074 gus->voices=14;
1076 gus->samp_timer = gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0));
1078 gus->t1l = gus->t2l = 0xff;
1080 io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus);
1081 io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus);
1082 io_sethandler(0x0746, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus);
1083 io_sethandler(0x0388, 0x0002, readgus, NULL, NULL, writegus, NULL, NULL, gus);
1084 timer_add(gus_poll_wave, &gus->samp_timer, TIMER_ALWAYS_ENABLED, gus);
1085 timer_add(gus_poll_timer_1, &gus->timer_1, TIMER_ALWAYS_ENABLED, gus);
1086 timer_add(gus_poll_timer_2, &gus->timer_2, TIMER_ALWAYS_ENABLED, gus);
1088 sound_add_handler(gus_poll, gus_get_buffer, gus);
1090 return gus;
1091 }
1093 void gus_close(void *p)
1094 {
1095 gus_t *gus = (gus_t *)p;
1097 free(gus->ram);
1098 free(gus);
1099 }
1101 void gus_speed_changed(void *p)
1102 {
1103 gus_t *gus = (gus_t *)p;
1105 if (gus->voices < 14)
1106 gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0));
1107 else
1108 gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14]));
1109 }
1111 device_t gus_device =
1112 {
1113 "Gravis UltraSound",
1114 0,
1115 gus_init,
1116 gus_close,
1117 NULL,
1118 gus_speed_changed,
1119 NULL,
1120 NULL
1121 };
