diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index b26c5f06e..70fcff387 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -187,6 +187,8 @@ typedef struct sb_t { uint8_t pnp_rom[512]; uint16_t opl_pnp_addr; + + uint16_t midi_addr; uint16_t gameport_addr; void *opl_mixer; diff --git a/src/include/86box/snd_sb_dsp.h b/src/include/86box/snd_sb_dsp.h index 9bc1d2308..0bc719d98 100644 --- a/src/include/86box/snd_sb_dsp.h +++ b/src/include/86box/snd_sb_dsp.h @@ -91,6 +91,8 @@ typedef struct sb_dsp_t { uint8_t sbref; int8_t sbstep; + uint8_t activity; + int sbdacpos; int sbleftright; diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 364c01557..882eaceea 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -1374,6 +1374,70 @@ sb_ct1745_mixer_reset(sb_t *sb) } } +static void +ess_base_write(uint16_t addr, uint8_t val, void *priv) +{ + sb_t * ess = (sb_t *) priv; + + switch (addr & 0x000f) { + case 0x0002: + case 0x0003: + case 0x0006: + case 0x000c: + ess->dsp.activity &= 0xdf; + break; + case 0x0008: + case 0x0009: + ess->dsp.activity &= 0x7f; + break; + } +} + +static uint8_t +ess_base_read(uint16_t addr, void *priv) +{ + sb_t * ess = (sb_t *) priv; + + switch (addr & 0x000f) { + case 0x0002: + case 0x0003: + case 0x0004: /* Undocumented but tested by the LBA 2 ES688 driver. */ + case 0x000a: + ess->dsp.activity &= 0xdf; + break; + case 0x0008: + case 0x0009: + ess->dsp.activity &= 0x7f; + break; + case 0x000c: + case 0x000e: + ess->dsp.activity &= 0xbf; + break; + } + + sb_log("ess_base_read(%04X): %04X, activity now: %02X\n", addr, addr & 0x000f, ess->dsp.activity); + + return 0xff; +} + +static void +ess_fm_midi_write(uint16_t addr, uint8_t val, void *priv) +{ + sb_t * ess = (sb_t *) priv; + + ess->dsp.activity &= 0x7f; +} + +static uint8_t +ess_fm_midi_read(uint16_t addr, void *priv) +{ + sb_t * ess = (sb_t *) priv; + + ess->dsp.activity &= 0x7f; + + return 0xff; +} + void ess_mixer_write(uint16_t addr, uint8_t val, void *priv) { @@ -1500,6 +1564,12 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv) { uint16_t mpu401_base_addr = 0x300 | ((mixer->regs[0x40] << 1) & 0x30); sb_log("mpu401_base_addr = %04X\n", mpu401_base_addr); + + io_removehandler(ess->midi_addr, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + gameport_remap(ess->gameport, !(mixer->regs[0x40] & 0x2) ? 0x00 : 0x200); if (ess->dsp.sb_subtype != SB_SUBTYPE_ESS_ES1688) { @@ -1519,7 +1589,8 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv) default: break; case 0: - mpu401_change_addr(ess->mpu, 0x00); + mpu401_base_addr = 0x0000; + mpu401_change_addr(ess->mpu, mpu401_base_addr); mpu401_setirq(ess->mpu, -1); break; case 1: @@ -1551,6 +1622,11 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv) mpu401_setirq(ess->mpu, 10); break; } + ess->midi_addr = mpu401_base_addr; + io_sethandler(addr, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); break; } @@ -2166,15 +2242,36 @@ ess_x688_pnp_config_changed(UNUSED(const uint8_t ld), isapnp_device_config_t *co ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_removehandler(addr, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_removehandler(addr + 8, 0x0002, ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_removehandler(addr + 8, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_removehandler(addr + 4, 0x0002, ess_mixer_read, NULL, NULL, ess_mixer_write, NULL, NULL, ess); + io_removehandler(addr + 2, 0x0004, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_removehandler(addr + 6, 0x0001, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_removehandler(addr + 0x0a, 0x0006, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + ess->mixer_ess.ess_id_str[2] = 0x00; ess->mixer_ess.ess_id_str[3] = 0x00; @@ -2185,10 +2282,23 @@ ess_x688_pnp_config_changed(UNUSED(const uint8_t ld), isapnp_device_config_t *co ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_removehandler(addr, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); } - if (ess->pnp == 3) - mpu401_change_addr(ess->mpu, 0); + if (ess->pnp == 3) { + addr = ess->midi_addr; + if (addr) { + ess->midi_addr = 0; + mpu401_change_addr(ess->mpu, 0); + io_removehandler(addr, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + } + } sb_dsp_setaddr(&ess->dsp, 0); sb_dsp_setirq(&ess->dsp, 0); @@ -2204,16 +2314,36 @@ ess_x688_pnp_config_changed(UNUSED(const uint8_t ld), isapnp_device_config_t *co ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_sethandler(addr, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_sethandler(addr + 8, 0x0002, ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_sethandler(addr + 8, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_sethandler(addr + 4, 0x0002, ess_mixer_read, NULL, NULL, ess_mixer_write, NULL, NULL, ess); sb_dsp_setaddr(&ess->dsp, addr); + io_sethandler(addr + 2, 0x0004, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(addr + 6, 0x0001, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(addr + 0x0a, 0x0006, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); ess->mixer_ess.ess_id_str[2] = (addr >> 8) & 0xff; ess->mixer_ess.ess_id_str[3] = addr & 0xff; @@ -2226,12 +2356,21 @@ ess_x688_pnp_config_changed(UNUSED(const uint8_t ld), isapnp_device_config_t *co ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_sethandler(addr, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); } if (ess->pnp == 3) { addr = config->io[2].base; - if (addr != ISAPNP_IO_DISABLED) + if (addr != ISAPNP_IO_DISABLED) { mpu401_change_addr(ess->mpu, addr); + io_sethandler(addr, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + } } val = config->irq[0].irq; @@ -2312,27 +2451,58 @@ ess_soundpiper_mca_write(const int port, const uint8_t val, void *priv) ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_removehandler(ess->dsp.sb_addr, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_removehandler(ess->dsp.sb_addr + 8, 0x0002, ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_removehandler(ess->dsp.sb_addr + 8, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_removehandler(0x0388, 0x0004, ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_removehandler(0x0388, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_removehandler(ess->dsp.sb_addr + 4, 0x0002, ess_mixer_read, NULL, NULL, ess_mixer_write, NULL, NULL, ess); + + io_removehandler(ess->dsp.sb_addr + 2, 0x0004, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_removehandler(ess->dsp.sb_addr + 6, 0x0001, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_removehandler(ess->dsp.sb_addr + 0x0a, 0x0006, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); } /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&ess->dsp, 0); gameport_remap(ess->gameport, 0); - if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688) + if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688) { mpu401_change_addr(ess->mpu, 0); + io_removehandler(0x0330, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + } + ess->pos_regs[port & 7] = val; if (ess->pos_regs[2] & 1) { @@ -2353,20 +2523,52 @@ ess_soundpiper_mca_write(const int port, const uint8_t val, void *priv) ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_sethandler(ess->dsp.sb_addr, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_sethandler(ess->dsp.sb_addr + 8, 0x0002, ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_sethandler(ess->dsp.sb_addr + 8, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_sethandler(0x0388, 0x0004, ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_sethandler(0x0388, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_sethandler(ess->dsp.sb_addr + 4, 0x0002, ess_mixer_read, NULL, NULL, ess_mixer_write, NULL, NULL, ess); - if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688) + io_sethandler(ess->dsp.sb_addr + 2, 0x0004, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(ess->dsp.sb_addr + 6, 0x0001, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(ess->dsp.sb_addr + 0x0a, 0x0006, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + + if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688) { mpu401_change_addr(ess->mpu, ess->pos_regs[3] & 0x02 ? 0x0330 : 0); + + if (ess->pos_regs[3] & 0x02) + io_sethandler(0x0330, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + } } /* DSP I/O handler is activated in sb_dsp_setaddr */ @@ -2420,25 +2622,57 @@ ess_chipchat_mca_write(int port, uint8_t val, void *priv) ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_removehandler(ess->dsp.sb_addr, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_removehandler(ess->dsp.sb_addr + 8, 0x0002, ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_removehandler(ess->dsp.sb_addr + 8, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_removehandler(0x0388, 0x0004, ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_removehandler(0x0388, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_removehandler(ess->dsp.sb_addr + 4, 0x0002, ess_mixer_read, NULL, NULL, ess_mixer_write, NULL, NULL, ess); + + io_removehandler(ess->dsp.sb_addr + 2, 0x0004, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_removehandler(ess->dsp.sb_addr + 6, 0x0001, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_removehandler(ess->dsp.sb_addr + 0x0a, 0x0006, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); } /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&ess->dsp, 0); gameport_remap(ess->gameport, 0); - mpu401_change_addr(ess->mpu, 0); + if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688) { + mpu401_change_addr(ess->mpu, 0); + + io_removehandler(0x0330, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + } ess->pos_regs[port & 7] = val; @@ -2450,20 +2684,52 @@ ess_chipchat_mca_write(int port, uint8_t val, void *priv) ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_sethandler(ess->dsp.sb_addr, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_sethandler(ess->dsp.sb_addr + 8, 0x0002, ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_sethandler(ess->dsp.sb_addr + 8, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_sethandler(0x0388, 0x0004, ess->opl.read, NULL, NULL, ess->opl.write, NULL, NULL, ess->opl.priv); + io_sethandler(0x0388, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); io_sethandler(ess->dsp.sb_addr + 4, 0x0002, ess_mixer_read, NULL, NULL, ess_mixer_write, NULL, NULL, ess); - if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688) + io_sethandler(ess->dsp.sb_addr + 2, 0x0004, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(ess->dsp.sb_addr + 6, 0x0001, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(ess->dsp.sb_addr + 0x0a, 0x0006, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + + if (ess->dsp.sb_subtype == SB_SUBTYPE_ESS_ES1688) { mpu401_change_addr(ess->mpu, (ess->pos_regs[2] == 0x51) ? 0x0330 : 0); + + if (ess->pos_regs[2] == 0x51) + io_sethandler(0x0330, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + } } /* DSP I/O handler is activated in sb_dsp_setaddr */ @@ -3452,20 +3718,43 @@ ess_x688_init(UNUSED(const device_t *info)) ess_mixer_reset(ess); /* DSP I/O handler is activated in sb_dsp_setaddr */ - { - io_sethandler(addr, 0x0004, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, - ess->opl.priv); - io_sethandler(addr + 8, 0x0002, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, - ess->opl.priv); - io_sethandler(0x0388, 0x0004, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, - ess->opl.priv); - } + io_sethandler(addr, 0x0004, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + io_sethandler(addr, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + io_sethandler(addr + 8, 0x0002, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + io_sethandler(addr + 8, 0x0002, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + io_sethandler(0x0388, 0x0004, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + io_sethandler(0x0388, 0x0004, + ess_fm_midi_read, NULL, NULL, + ess_fm_midi_write, NULL, NULL, + ess); + + io_sethandler(addr + 2, 0x0004, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(addr + 6, 0x0001, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); + io_sethandler(addr + 0x0a, 0x0006, + ess_base_read, NULL, NULL, + ess_base_write, NULL, NULL, + ess); ess->mixer_enabled = 1; ess->mixer_ess.regs[0x40] = 0x0a; diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 53666f71d..f51ff4d25 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -726,6 +726,8 @@ sb_8_read_dma(void *priv) sb_dsp_t *dsp = (sb_dsp_t *) priv; int ret; + dsp->activity &= 0xdf; + if (dsp->sb_8_dmanum >= 4) { if (dsp->dma_ff) { uint32_t temp = (dsp->dma_data & 0xff00) >> 8; @@ -750,7 +752,9 @@ sb_8_read_dma(void *priv) int sb_8_write_dma(void *priv, uint8_t val) { - const sb_dsp_t *dsp = (sb_dsp_t *) priv; + sb_dsp_t *dsp = (sb_dsp_t *) priv; + + dsp->activity &= 0xdf; return dma_channel_write(dsp->sb_8_dmanum, val) == DMA_NODATA; } @@ -770,11 +774,13 @@ sb_8_write_dma(void *priv, uint8_t val) int sb_16_read_dma(void *priv) { - const sb_dsp_t *dsp = (sb_dsp_t *) priv; + sb_dsp_t *dsp = (sb_dsp_t *) priv; int ret; int dma_ch = dsp->sb_16_dmanum; + dsp->activity &= 0xdf; + if (dsp->sb_16_dma_enabled && dsp->sb_16_dma_supported && !dsp->sb_16_dma_translate && (dma_ch != 4)) ret = dma_channel_read(dma_ch); else { @@ -808,10 +814,12 @@ sb_16_read_dma(void *priv) int sb_16_write_dma(void *priv, uint16_t val) { - const sb_dsp_t *dsp = (sb_dsp_t *) priv; + sb_dsp_t *dsp = (sb_dsp_t *) priv; int dma_ch = dsp->sb_16_dmanum; int ret; + dsp->activity &= 0xdf; + if (dsp->sb_16_dma_enabled && dsp->sb_16_dma_supported && !dsp->sb_16_dma_translate && (dma_ch != 4)) ret = dma_channel_write(dma_ch, val) == DMA_NODATA; else { @@ -1723,17 +1731,14 @@ sb_exec_command(sb_dsp_t *dsp) break; case 0xF2: /* Trigger 8-bit IRQ */ sb_dsp_log("Trigger 8-bit IRQ\n"); - if (!timer_is_enabled(&dsp->irq_timer)) { - timer_set_delay_u64(&dsp->irq_timer, (100ULL * TIMER_USEC)); - } + timer_set_delay_u64(&dsp->irq_timer, (10ULL * TIMER_USEC)); break; case 0xF3: /* Trigger 16-bit IRQ */ sb_dsp_log("Trigger 16-bit IRQ\n"); if (IS_ESS(dsp)) dsp->ess_irq_generic = true; - else if (!timer_is_enabled(&dsp->irq16_timer)) { - timer_set_delay_u64(&dsp->irq16_timer, (100ULL * TIMER_USEC)); - } + else + timer_set_delay_u64(&dsp->irq16_timer, (10ULL * TIMER_USEC)); break; case 0xF8: if (dsp->sb_type < SB16) @@ -1886,7 +1891,11 @@ sb_read(uint16_t a, void *priv) switch (a & 0xf) { case 0x6: - ret = IS_ESS(dsp) ? 0x00 : 0xff; + if (IS_ESS(dsp)) { + ret = (dsp->espcm_fifo_reset & 0x03) | 0x08 | (dsp->activity & 0xe0); + dsp->activity |= 0xe0; + } else + ret = 0xff; break; case 0xA: /* Read data */ if (dsp->mpu && dsp->uart_midi) @@ -2075,6 +2084,7 @@ sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent) dsp->sb_type = type; dsp->sb_subtype = subtype; dsp->parent = parent; + dsp->activity = 0xe0; /* Default values. Use sb_dsp_setxxx() methods to change. */ dsp->sb_irqnum = 7;