|
17 | 17 | * Copyright 2026 win2kgamer |
18 | 18 | */ |
19 | 19 |
|
20 | | -/* |
21 | | - * Known issues: |
22 | | - * - MegaEM 3.x has nonfunctional SoundBlaster emulation and appears to |
23 | | - * rely on undocumented hardware behavior. This manifests as silent |
24 | | - * digital audio in MegaEM 3.03 and as an IRQ conflict error on MegaEM |
25 | | - * 3.04 and later. |
26 | | - */ |
27 | | - |
28 | 20 | /* |
29 | 21 | * TODO: |
30 | | - * - Find the undocumented hardware behavior MegaEM 3.x relies on for emulating |
31 | | - * a SoundBlaster. |
32 | 22 | * - Implement the 16-bit recording daughterboard for the GUS Classic: this has |
33 | 23 | * a CS4231 codec and can be jumpered for the following addresses: 530h, 604h, |
34 | 24 | * E80h or F40h. IRQ (3/4/5/6/7/9) and DMA (1/2/3) are also jumpered. |
@@ -246,6 +236,14 @@ typedef struct gus_t { |
246 | 236 | uint16_t cur_codec_addr; |
247 | 237 | uint8_t dmaover; |
248 | 238 |
|
| 239 | + /* GUS ADC stub */ |
| 240 | + uint8_t adc_srate; |
| 241 | + uint8_t adc_ctrl; |
| 242 | + uint16_t adc_freq; |
| 243 | + uint8_t adc_irq; |
| 244 | + double inputlatch; |
| 245 | + pc_timer_t sample_timer; |
| 246 | + |
249 | 247 | void * log; /* New logging system */ |
250 | 248 | } gus_t; |
251 | 249 |
|
@@ -301,6 +299,8 @@ gus_update_int_status(gus_t *gus) |
301 | 299 | irq_pending = 1; /*Timer 2 interrupt pending*/ |
302 | 300 | if ((gus->irqstatus & 0x80) && (gus->dmactrl & 0x20)) |
303 | 301 | irq_pending = 1; /*DMA TC interrupt pending*/ |
| 302 | + if ((gus->irqstatus & 0x80) && (gus->adc_ctrl & 0x20)) |
| 303 | + irq_pending = 1; /*ADC DMA TC interrupt pending*/ |
304 | 304 |
|
305 | 305 | midi_irq_pending = gus->midi_status & MIDI_INT_MASTER; |
306 | 306 |
|
@@ -355,6 +355,40 @@ gus_midi_update_int_status(gus_t *gus) |
355 | 355 | gus_update_int_status(gus); |
356 | 356 | } |
357 | 357 |
|
| 358 | +void |
| 359 | +gus_input_poll(void *priv) |
| 360 | +{ |
| 361 | + gus_t *gus = (gus_t *) priv; |
| 362 | + int dma_result; |
| 363 | + |
| 364 | + timer_advance_u64(&gus->sample_timer, (uint64_t) gus->inputlatch); |
| 365 | + |
| 366 | + if (gus->adc_ctrl & 0x01) { |
| 367 | + if (gus->adc_ctrl & 0x02) { |
| 368 | + if (gus->adc_ctrl & 0x04) |
| 369 | + dma_result = dma_channel_write(gus->dma, (gus->adc_ctrl & 0x80) ? 0x0000 : 0x8080); |
| 370 | + else { |
| 371 | + dma_result = dma_channel_write(gus->dma, (gus->adc_ctrl & 0x80) ? 0x00 : 0x80); |
| 372 | + dma_result = dma_channel_write(gus->dma, (gus->adc_ctrl & 0x80) ? 0x00 : 0x80); |
| 373 | + } |
| 374 | + } else { |
| 375 | + if (gus->adc_ctrl & 0x04) |
| 376 | + dma_result = dma_channel_write(gus->dma, (gus->adc_ctrl & 0x80) ? 0x0000 : 0x0080); |
| 377 | + else |
| 378 | + dma_result = dma_channel_write(gus->dma, (gus->adc_ctrl & 0x80) ? 0x00 : 0x80); |
| 379 | + } |
| 380 | + if (dma_result & DMA_OVER) { |
| 381 | + gus->adc_ctrl &= 0xfe; |
| 382 | + gus->irqstatus |= 0x80; |
| 383 | + gus->adc_irq = 1; |
| 384 | + gus_log(gus->log, "ADC DMA complete, firing IRQ\n"); |
| 385 | + timer_disable(&gus->sample_timer); |
| 386 | + } |
| 387 | + } else { |
| 388 | + timer_disable(&gus->sample_timer); |
| 389 | + } |
| 390 | +} |
| 391 | + |
358 | 392 | void |
359 | 393 | gus_write(uint16_t addr, uint8_t val, void *priv) |
360 | 394 | { |
@@ -662,6 +696,25 @@ gus_write(uint16_t addr, uint8_t val, void *priv) |
662 | 696 | gus->t2on = 1; |
663 | 697 | break; |
664 | 698 |
|
| 699 | + case 0x48: /*ADC Sample Rate*/ |
| 700 | + gus->adc_srate = val; |
| 701 | + gus->adc_freq = 617400 / gus->adc_srate; /* (9878400 / (freq * 16) - 2 */ |
| 702 | + double temp = 1000000.0 / gus->adc_freq; |
| 703 | + if (gus->adc_freq < 4000) |
| 704 | + gus->adc_freq = 4000; |
| 705 | + if (gus->adc_freq > 44100) |
| 706 | + gus->adc_freq = 44100; |
| 707 | + gus->inputlatch = ((double) TIMER_USEC * temp); |
| 708 | + gus_log(gus->log, "GUS ADC samplerate set to %i, val = %02X\n", gus->adc_freq, gus->adc_srate); |
| 709 | + break; |
| 710 | + case 0x49: /*ADC Sample Control*/ |
| 711 | + /* This is the ADC equivalent of index 41h DMA Control and is relied on by MegaEM 3.x */ |
| 712 | + gus->adc_ctrl = val; |
| 713 | + if (val & 1) |
| 714 | + timer_set_delay_u64(&gus->sample_timer, (uint64_t) gus->inputlatch); |
| 715 | + gus_log(gus->log, "GUS DMA Control write! new val = %02X\n", val); |
| 716 | + break; |
| 717 | + |
665 | 718 | case 0x4B: /*Joystick trim DAC*/ |
666 | 719 | gus->joy_trim = val; |
667 | 720 | break; |
@@ -950,8 +1003,11 @@ gus_read(uint16_t addr, void *priv) |
950 | 1003 | /* Handling for undocumented NMI status bit, needed by SBOS */ |
951 | 1004 | if (((gus->ad_status & 0x18) && (gus->sb_ctrl & 0x20)) || ((gus->ad_status & 0x01) && (gus->sb_ctrl & 0x02))) |
952 | 1005 | val |= 0x10; |
| 1006 | + /* Ensure the DMA TC bit *is* set if the ADC caused an IRQ */ |
| 1007 | + if (gus->adc_irq) |
| 1008 | + val |= 0x80; |
953 | 1009 | /* DMA Terminal Count bit is inhibited if DMA Control bit 5 is cleared */ |
954 | | - if (!(gus->dmactrl & 0x20)) |
| 1010 | + if ((!(gus->dmactrl & 0x20)) && (!(gus->adc_ctrl & 0x20))) |
955 | 1011 | val &= 0x7f; |
956 | 1012 | gus_log(gus->log, "GUS read: port = %04X, val = %02X\n", addr, val); |
957 | 1013 | return val; |
@@ -1069,9 +1125,12 @@ gus_read(uint16_t addr, void *priv) |
1069 | 1125 | case 0x45: /*Timer control*/ |
1070 | 1126 | gus_log(gus->log, "GUS read: port = %04X, val = %02X\n", addr, gus->tctrl); |
1071 | 1127 | return gus->tctrl; |
1072 | | - case 0x49: /*Sampling control*/ |
1073 | | - gus_log(gus->log, "GUS read: port = %04X, val = %02X\n", addr, 0); |
1074 | | - return 0; |
| 1128 | + case 0x49: /*ADC Sampling control*/ |
| 1129 | + val = gus->adc_ctrl | (((gus->irqstatus & 0x80) || gus->adc_irq) ? 0x40 : 0); |
| 1130 | + gus->irqstatus &= ~0x80; |
| 1131 | + gus->adc_irq = 0; |
| 1132 | + gus_log(gus->log, "GUS read: port = %04X, val = %02X\n", addr, val); |
| 1133 | + return val; |
1075 | 1134 |
|
1076 | 1135 | case 0x4B: /*Joystick trim DAC*/ |
1077 | 1136 | gus_log(gus->log, "GUS read: port = %04X, val = %02X\n", addr, gus->joy_trim); |
@@ -1828,6 +1887,7 @@ gus_init(UNUSED(const device_t *info)) |
1828 | 1887 | timer_add(&gus->samp_timer, gus_poll_wave, gus, 1); |
1829 | 1888 | timer_add(&gus->timer_1, gus_poll_timer_1, gus, 1); |
1830 | 1889 | timer_add(&gus->timer_2, gus_poll_timer_2, gus, 1); |
| 1890 | + timer_add(&gus->sample_timer, gus_input_poll, gus, 0); |
1831 | 1891 |
|
1832 | 1892 | sound_add_handler(gus_get_buffer, gus); |
1833 | 1893 |
|
|
0 commit comments