From 0561f65592df6239853eb66c6dbce9626465ddbd Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 17 May 2024 01:28:16 +0200 Subject: [PATCH] Sound Blaster: automatic DRQ clearing. --- src/dma.c | 55 +++++++------ src/sound/snd_sb_dsp.c | 172 ++++++++++++++++++++++++----------------- 2 files changed, 130 insertions(+), 97 deletions(-) diff --git a/src/dma.c b/src/dma.c index 318c6cda2..0593d0395 100644 --- a/src/dma.c +++ b/src/dma.c @@ -458,8 +458,8 @@ static uint8_t dma_read(uint16_t addr, UNUSED(void *priv)) { int channel = (addr >> 1) & 3; - uint8_t temp; - int count; + int count; + uint8_t ret = (dmaregs[0][addr & 0xf]); switch (addr & 0xf) { case 0: @@ -468,8 +468,10 @@ dma_read(uint16_t addr, UNUSED(void *priv)) case 6: /*Address registers*/ dma_wp[0] ^= 1; if (dma_wp[0]) - return (dma[channel].ac & 0xff); - return ((dma[channel].ac >> 8) & 0xff); + ret = (dma[channel].ac & 0xff); + else + ret = ((dma[channel].ac >> 8) & 0xff); + break; case 1: case 3: @@ -477,29 +479,30 @@ dma_read(uint16_t addr, UNUSED(void *priv)) case 7: /*Count registers*/ dma_wp[0] ^= 1; count = dma[channel].cc/* + 1*/; - // if (count > dma[channel].cb) - // count = 0x0000; if (dma_wp[0]) - temp = count & 0xff; + ret = count & 0xff; else - temp = count >> 8; - return temp; + ret = count >> 8; + break; case 8: /*Status register*/ - temp = dma_stat_rq_pc & 0xf; - temp <<= 4; - temp |= dma_stat & 0xf; + ret = dma_stat_rq_pc & 0xf; + ret <<= 4; + ret |= dma_stat & 0xf; dma_stat &= ~0xf; - return temp; + break; case 0xd: /*Temporary register*/ - return 0; + ret = 0x00; + break; default: break; } - return (dmaregs[0][addr & 0xf]); + dma_log("DMA: [R] %04X = %02X\n", addr, ret); + + return ret; } static void @@ -507,6 +510,8 @@ dma_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) { int channel = (addr >> 1) & 3; + dma_log("DMA: [W] %04X = %02X\n", addr, val); + dmaregs[0][addr & 0xf] = val; switch (addr & 0xf) { case 0: @@ -537,7 +542,7 @@ dma_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) dma_command[0] = val; #ifdef ENABLE_DMA_LOG if (val & 0x01) - pclog("[%08X:%04X] Memory-to-memory enable\n", CS, cpu_state.pc); + dma_log("[%08X:%04X] Memory-to-memory enable\n", CS, cpu_state.pc); #endif return; @@ -546,9 +551,7 @@ dma_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) if (val & 4) { dma_stat_rq_pc |= (1 << channel); if ((channel == 0) && (dma_command[0] & 0x01)) { -#ifdef ENABLE_DMA_LOG - pclog("Memory to memory transfer start\n"); -#endif + dma_log("Memory to memory transfer start\n"); dma_mem_to_mem_transfer(); } else dma_block_transfer(channel); @@ -828,9 +831,7 @@ dma16_read(uint16_t addr, UNUSED(void *priv)) break; } -#ifdef ENABLE_DMA_LOG - pclog("dma16_read(%08X) = %02X\n", port, ret); -#endif + dma_log("dma16_read(%08X) = %02X\n", port, ret); return ret; } @@ -839,9 +840,9 @@ static void dma16_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) { int channel = ((addr >> 2) & 3) + 4; -#ifdef ENABLE_DMA_LOG - pclog("dma16_write(%08X, %02X)\n", addr, val); -#endif + + dma_log("dma16_write(%08X, %02X)\n", addr, val); + addr >>= 1; dmaregs[1][addr & 0xf] = val; @@ -944,6 +945,8 @@ dma_page_write(uint16_t addr, uint8_t val, UNUSED(void *priv)) { uint8_t convert[8] = CHANNELS; + dma_log("DMA: [W] %04X = %02X\n", addr, val); + #ifdef USE_DYNAREC if ((addr == 0x84) && cpu_use_dynarec) update_tsc(); @@ -1020,6 +1023,8 @@ dma_page_read(uint16_t addr, UNUSED(void *priv)) ret = dma[addr].page_l; } + dma_log("DMA: [R] %04X = %02X\n", addr, ret); + return ret; } diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index e5c2359a0..88f690762 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -543,9 +543,41 @@ sb_ess_get_dma_len(const sb_dsp_t *dsp) return 0x10000U - sb_ess_get_dma_counter(dsp); } +static void +sb_resume_dma(const sb_dsp_t *dsp, const int is_8) +{ + if IS_ESS(dsp) + { + dma_set_drq(dsp->sb_8_dmanum, 1); + dma_set_drq(dsp->sb_16_8_dmanum, 1); + } else if (is_8) + dma_set_drq(dsp->sb_8_dmanum, 1); + else { + if (dsp->sb_16_dmanum != 0xff) + dma_set_drq(dsp->sb_16_dmanum, 1); + + if (dsp->sb_16_8_dmanum != 0xff) + dma_set_drq(dsp->sb_16_8_dmanum, 1); + } +} + +static void +sb_stop_dma(const sb_dsp_t *dsp) +{ + dma_set_drq(dsp->sb_8_dmanum, 0); + + if (dsp->sb_16_dmanum != 0xff) + dma_set_drq(dsp->sb_16_dmanum, 0); + + if (dsp->sb_16_8_dmanum != 0xff) + dma_set_drq(dsp->sb_16_8_dmanum, 0); +} + void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) { + sb_stop_dma(dsp); + dsp->sb_pausetime = -1; if (dma8) { @@ -590,6 +622,8 @@ sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) { + sb_stop_dma(dsp); + if (dma8) { dsp->sb_8_length = dsp->sb_8_origlength = len; dsp->sb_8_format = format; @@ -1549,35 +1583,43 @@ sb_exec_command(sb_dsp_t *dsp) break; case 0xD0: /* Pause 8-bit DMA */ dsp->sb_8_pause = 1; + sb_stop_dma(dsp); break; case 0xD1: /* Speaker on */ if (IS_NOT_ESS(dsp)) { - if (dsp->sb_type < SB15) + if (dsp->sb_type < SB15) { dsp->sb_8_pause = 1; - else if (dsp->sb_type < SB16) + sb_stop_dma(dsp); + } else if (dsp->sb_type < SB16) dsp->muted = 0; } dsp->sb_speaker = 1; break; case 0xD3: /* Speaker off */ if (IS_NOT_ESS(dsp)) { - if (dsp->sb_type < SB15) + if (dsp->sb_type < SB15) { dsp->sb_8_pause = 1; - else if (dsp->sb_type < SB16) + sb_stop_dma(dsp); + } else if (dsp->sb_type < SB16) dsp->muted = 1; } dsp->sb_speaker = 0; break; case 0xD4: /* Continue 8-bit DMA */ dsp->sb_8_pause = 0; + sb_resume_dma(dsp, 1); break; case 0xD5: /* Pause 16-bit DMA */ - if (dsp->sb_type >= SB16) + if (dsp->sb_type >= SB16) { dsp->sb_16_pause = 1; + sb_stop_dma(dsp); + } break; case 0xD6: /* Continue 16-bit DMA */ - if (dsp->sb_type >= SB16) + if (dsp->sb_type >= SB16) { dsp->sb_16_pause = 0; + sb_resume_dma(dsp, 1); + } break; case 0xD8: /* Get speaker status */ sb_add_data(dsp, dsp->sb_speaker ? 0xff : 0); @@ -2002,7 +2044,12 @@ sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent) /* Default values. Use sb_dsp_setxxx() methods to change. */ dsp->sb_irqnum = 7; dsp->sb_8_dmanum = 1; - dsp->sb_16_dmanum = 5; + if (type >= SB16) + dsp->sb_16_dmanum = 5; + else + dsp->sb_16_dmanum = 0xff; + if ((type >= SB16) || IS_ESS(dsp)) + dsp->sb_16_8_dmanum = 0x1; dsp->mpu = NULL; dsp->sbleftright_default = 0; @@ -2111,13 +2158,14 @@ sb_dsp_dma_attach(sb_dsp_t *dsp, dsp->dma_priv = priv; } -void -sb_ess_finish_dma(sb_dsp_t *dsp) +static void +sb_finish_dma(sb_dsp_t *dsp) { - if (!dsp->ess_playback_mode) - return; - ESSreg(0xB8) &= ~0x01; - dma_set_drq(dsp->sb_8_dmanum, 0); + if (dsp->ess_playback_mode) { + ESSreg(0xB8) &= ~0x01; + dma_set_drq(dsp->sb_8_dmanum, 0); + } else + sb_stop_dma(dsp); } void @@ -2347,34 +2395,29 @@ pollsb(void *priv) break; case ESPCM_4: - if (dsp->espcm_sample_idx >= 19) { + if (dsp->espcm_sample_idx >= 19) dsp->espcm_sample_idx = 0; - } if (dsp->espcm_sample_idx == 0) { sb_espcm_fifoctl_run(dsp); - if (fifo_get_empty(dsp->espcm_fifo)) { + if (fifo_get_empty(dsp->espcm_fifo)) break; - } dsp->espcm_byte_buffer[0] = fifo_read(dsp->espcm_fifo); dsp->espcm_range = dsp->espcm_byte_buffer[0] & 0x0F; tempi = dsp->espcm_byte_buffer[0] >> 4; } else if (dsp->espcm_sample_idx & 1) { sb_espcm_fifoctl_run(dsp); - if (fifo_get_empty(dsp->espcm_fifo)) { + if (fifo_get_empty(dsp->espcm_fifo)) break; - } dsp->espcm_byte_buffer[0] = fifo_read(dsp->espcm_fifo); dsp->sb_8_length--; tempi = dsp->espcm_byte_buffer[0] & 0x0F; - } else { + } else tempi = dsp->espcm_byte_buffer[0] >> 4; - } - if (dsp->espcm_sample_idx == 18) { + if (dsp->espcm_sample_idx == 18) dsp->sb_8_length--; - } dsp->espcm_sample_idx++; @@ -2389,20 +2432,17 @@ pollsb(void *priv) else dsp->sbdatr = dsp->sbdat; dsp->sbleftright = !dsp->sbleftright; - } else { + } else dsp->sbdatl = dsp->sbdatr = dsp->sbdat; - } break; case ESPCM_3: - if (dsp->espcm_sample_idx >= 19) { + if (dsp->espcm_sample_idx >= 19) dsp->espcm_sample_idx = 0; - } if (dsp->espcm_sample_idx == 0) { sb_espcm_fifoctl_run(dsp); - if (fifo_get_empty(dsp->espcm_fifo)) { + if (fifo_get_empty(dsp->espcm_fifo)) break; - } dsp->espcm_byte_buffer[0] = fifo_read(dsp->espcm_fifo); dsp->espcm_range = dsp->espcm_byte_buffer[0] & 0x0F; @@ -2411,15 +2451,13 @@ pollsb(void *priv) } else if (dsp->espcm_sample_idx == 1) { for (tempi = 0; tempi < 4; tempi++) { sb_espcm_fifoctl_run(dsp); - if (fifo_get_empty(dsp->espcm_fifo)) { + if (fifo_get_empty(dsp->espcm_fifo)) break; - } dsp->espcm_byte_buffer[tempi] = fifo_read(dsp->espcm_fifo); dsp->sb_8_length--; } - if (tempi < 4) { + if (tempi < 4) break; - } dsp->espcm_table_index = dsp->espcm_byte_buffer[0] & 0x03; @@ -2440,15 +2478,13 @@ pollsb(void *priv) } else if (dsp->espcm_sample_idx == 11) { for (tempi = 1; tempi < 4; tempi++) { sb_espcm_fifoctl_run(dsp); - if (fifo_get_empty(dsp->espcm_fifo)) { + if (fifo_get_empty(dsp->espcm_fifo)) break; - } dsp->espcm_byte_buffer[tempi] = fifo_read(dsp->espcm_fifo); dsp->sb_8_length--; } - if (tempi < 4) { + if (tempi < 4) break; - } dsp->espcm_code_buffer[0] = (dsp->espcm_byte_buffer[1]) & 0x07; dsp->espcm_code_buffer[1] = (dsp->espcm_byte_buffer[1] >> 3) & 0x07; @@ -2485,20 +2521,19 @@ pollsb(void *priv) else dsp->sbdatr = dsp->sbdat; dsp->sbleftright = !dsp->sbleftright; - } else { + } else dsp->sbdatl = dsp->sbdatr = dsp->sbdat; - } break; case ESPCM_1: - if (dsp->espcm_sample_idx >= 19) { + if (dsp->espcm_sample_idx >= 19) dsp->espcm_sample_idx = 0; - } if (dsp->espcm_sample_idx == 0) { sb_espcm_fifoctl_run(dsp); - if (fifo_get_empty(dsp->espcm_fifo)) { + + if (fifo_get_empty(dsp->espcm_fifo)) break; - } + dsp->espcm_byte_buffer[0] = fifo_read(dsp->espcm_fifo); dsp->espcm_range = dsp->espcm_byte_buffer[0] & 0x0F; @@ -2520,13 +2555,12 @@ pollsb(void *priv) dsp->espcm_byte_buffer[0] >>= 1; } - if (dsp->espcm_sample_idx == 18) { + if (dsp->espcm_sample_idx == 18) dsp->sb_8_length--; - } dsp->espcm_sample_idx++; - tempi |= (dsp->espcm_range << 4); + tempi |= (dsp->espcm_range << 4); data[0] = (int) espcm_range_map[tempi]; dsp->sbdat = (int16_t) (data[0] << 8); if (dsp->stereo) { @@ -2537,9 +2571,8 @@ pollsb(void *priv) else dsp->sbdatr = dsp->sbdat; dsp->sbleftright = !dsp->sbleftright; - } else { + } else dsp->sbdatl = dsp->sbdatr = dsp->sbdat; - } break; default: @@ -2552,7 +2585,7 @@ pollsb(void *priv) else { dsp->sb_8_enable = 0; timer_disable(&dsp->output_timer); - sb_ess_finish_dma(dsp); + sb_finish_dma(dsp); } sb_irq(dsp, 1); dsp->ess_irq_generic = true; @@ -2562,16 +2595,16 @@ pollsb(void *priv) if (!dsp->sb_8_autoinit) { dsp->sb_8_enable = 0; timer_disable(&dsp->output_timer); - sb_ess_finish_dma(dsp); + sb_finish_dma(dsp); } if (ESSreg(0xB1) & 0x40) { sb_irq(dsp, 1); dsp->ess_irq_dmactr = true; } } - uint32_t temp = dsp->ess_dma_counter & 0xffff; - dsp->ess_dma_counter = sb_ess_get_dma_counter(dsp); - dsp->ess_dma_counter += temp; + const uint32_t temp = dsp->ess_dma_counter & 0xffff; + dsp->ess_dma_counter = sb_ess_get_dma_counter(dsp); + dsp->ess_dma_counter += temp; } } if (dsp->sb_16_enable && !dsp->sb_16_pause && (dsp->sb_pausetime < 0LL) && dsp->sb_16_output) { @@ -2626,7 +2659,7 @@ pollsb(void *priv) else { dsp->sb_16_enable = 0; timer_disable(&dsp->output_timer); - sb_ess_finish_dma(dsp); + sb_finish_dma(dsp); } sb_irq(dsp, 0); dsp->ess_irq_generic = true; @@ -2636,16 +2669,16 @@ pollsb(void *priv) if (!dsp->sb_16_autoinit) { dsp->sb_16_enable = 0; timer_disable(&dsp->output_timer); - sb_ess_finish_dma(dsp); + sb_finish_dma(dsp); } if (ESSreg(0xB1) & 0x40) { sb_irq(dsp, 0); dsp->ess_irq_dmactr = true; } } - uint32_t temp = dsp->ess_dma_counter & 0xffff; - dsp->ess_dma_counter = sb_ess_get_dma_counter(dsp); - dsp->ess_dma_counter += temp; + const uint32_t temp = dsp->ess_dma_counter & 0xffff; + dsp->ess_dma_counter = sb_ess_get_dma_counter(dsp); + dsp->ess_dma_counter += temp; } } if (dsp->sb_pausetime > -1) { @@ -2715,12 +2748,10 @@ sb_poll_i(void *priv) for (i = 0; i < 19; i++) { s = dsp->espcm_sample_buffer[i]; - if (s < min_sample) { + if (s < min_sample) min_sample = s; - } - if (s > max_sample) { + if (s > max_sample) max_sample = s; - } } if (min_sample < 0) { if (min_sample == -128) @@ -2738,9 +2769,8 @@ sb_poll_i(void *priv) max_sample = min_sample; for (table_addr = 15; table_addr < 256; table_addr += 16) { - if (max_sample <= espcm_range_map[table_addr]) { + if (max_sample <= espcm_range_map[table_addr]) break; - } } dsp->espcm_range = table_addr >> 4; @@ -2750,12 +2780,10 @@ sb_poll_i(void *priv) s = dsp->espcm_sample_buffer[i]; for (; (table_addr >> 4) == dsp->espcm_range; table_addr++) { int sigma = espcm_range_map[table_addr] - s; - if (sigma < 0) { + if (sigma < 0) sigma = -sigma; - } - if (sigma > last_sigma) { + if (sigma > last_sigma) break; - } last_sigma = sigma; } table_addr--; @@ -2787,7 +2815,7 @@ sb_poll_i(void *priv) else { dsp->sb_8_enable = 0; timer_disable(&dsp->input_timer); - sb_ess_finish_dma(dsp); + sb_finish_dma(dsp); } sb_irq(dsp, 1); dsp->ess_irq_generic = true; @@ -2797,7 +2825,7 @@ sb_poll_i(void *priv) if (!dsp->sb_8_autoinit) { dsp->sb_8_enable = 0; timer_disable(&dsp->input_timer); - sb_ess_finish_dma(dsp); + sb_finish_dma(dsp); } if (ESSreg(0xB1) & 0x40) { sb_irq(dsp, 1); @@ -2857,7 +2885,7 @@ sb_poll_i(void *priv) else { dsp->sb_16_enable = 0; timer_disable(&dsp->input_timer); - sb_ess_finish_dma(dsp); + sb_finish_dma(dsp); } sb_irq(dsp, 0); dsp->ess_irq_generic = true; @@ -2867,7 +2895,7 @@ sb_poll_i(void *priv) if (!dsp->sb_16_autoinit) { dsp->sb_16_enable = 0; timer_disable(&dsp->input_timer); - sb_ess_finish_dma(dsp); + sb_finish_dma(dsp); } if (ESSreg(0xB1) & 0x40) { sb_irq(dsp, 0);