diff --git a/src/sound/snd_ess.c b/src/sound/snd_ess.c index a97d5e244..0193c69c9 100644 --- a/src/sound/snd_ess.c +++ b/src/sound/snd_ess.c @@ -6,16 +6,20 @@ * * This file is part of the 86Box distribution. * - * Sound Blaster emulation. + * ESS AudioDrive emulation. * * * * Authors: Sarah Walker, * Miran Grca, * TheCollector1995, + * Cacodemon345, + * Kagamiin~, * * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2020 Miran Grca. + * Copyright 2024 Cacodemon345 + * Copyright 2024 Kagamiin~ */ #include #include @@ -79,7 +83,7 @@ typedef struct ess_mixer_t { uint8_t regs[256]; uint8_t ess_id_str[256]; - uint8_t ess_id_str_pos : 2; + uint8_t ess_id_str_pos; } ess_mixer_t; typedef struct ess_t { @@ -130,7 +134,10 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv) mixer->index = val; mixer->regs[0x01] = val; if (val == 0x40) + { + pclog("ess: Mixer addr 0x40 selected, ID string offset reset\n"); mixer->ess_id_str_pos = 0; + } } else { if (mixer->index == 0) { /* Reset */ @@ -151,7 +158,7 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv) sb_dsp_set_stereo(&ess->dsp, mixer->regs[0x0e] & 2); } else { mixer->regs[mixer->index] = val; - pclog("ess: Register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + pclog("ess: Mixer Register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); switch (mixer->index) { /* Compatibility: chain registers 0x02 and 0x22 as well as 0x06 and 0x26 */ @@ -198,23 +205,27 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv) break; case 0x40: { - break; - uint16_t mpu401_base_addr = 0x300 | ((mixer->regs[0x40] & 0x38) << 1); - gameport_remap(ess->gameport, !(mixer->regs[0x40] & 0x2) ? 0x00 : 0x200); - /* This doesn't work yet. */ - /* - io_removehandler(0x0388, 0x0004, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, - ess->opl.priv); - if (mixer->regs[0x40] & 1) { - io_sethandler(0x0388, 0x0004, - ess->opl.read, NULL, NULL, - ess->opl.write, NULL, NULL, - ess->opl.priv); - }*/ + /* TODO: Implement "Read-Sequence-Key" method of software address selection + * (needed for ESSCFG.EXE to work properly) */ - switch ((mixer->regs[0x40] >> 5) & 7) { + uint16_t mpu401_base_addr = 0x300 | ((mixer->regs[0x40] << 1) & 0x30); + gameport_remap(ess->gameport, !(mixer->regs[0x40] & 0x2) ? 0x00 : 0x200); + + /* This doesn't work yet. */ +#if 1 + io_removehandler(0x0388, 0x0004, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + if ((mixer->regs[0x40] & 0x1) != 0) + { + io_sethandler(0x0388, 0x0004, + ess->opl.read, NULL, NULL, + ess->opl.write, NULL, NULL, + ess->opl.priv); + } +#endif + switch ((mixer->regs[0x40] >> 5) & 0x7) { case 0: mpu401_change_addr(ess->mpu, 0x00); mpu401_setirq(ess->mpu, -1); @@ -252,7 +263,7 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv) } default: - pclog("ess: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + pclog("ess: Unknown mixer register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); break; } } @@ -320,21 +331,22 @@ ess_mixer_read(uint16_t addr, void *priv) case 0x36: case 0x38: case 0x3e: - pclog("ess: Register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + pclog("ess: Mixer Register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); return mixer->regs[mixer->index]; case 0x40: { uint8_t val = mixer->ess_id_str[mixer->ess_id_str_pos]; + uint8_t pos_log = mixer->ess_id_str_pos; /* TODO remove */ mixer->ess_id_str_pos++; if (mixer->ess_id_str_pos >= 4) mixer->ess_id_str_pos = 0; - pclog("ess: ID READ: %02X (pos %d)\n", val, mixer->ess_id_str_pos); + pclog("ess: ID READ: %02X (pos %d)\n", val, pos_log); return val; } default: - pclog("ess: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + pclog("ess: Unknown mixer register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); break; } @@ -491,7 +503,7 @@ ess_1688_init(UNUSED(const device_t *info)) } ess->mpu = (mpu_t *) calloc(1, sizeof(mpu_t)); - mpu401_init(ess->mpu, 0, 0, M_UART, 1); + mpu401_init(ess->mpu, 0, -1, M_UART, 1); sb_dsp_set_mpu(&ess->dsp, ess->mpu); ess->gameport = gameport_add(&gameport_pnp_device); @@ -620,4 +632,4 @@ const device_t ess_1688_device = { .speed_changed = ess_speed_changed, .force_redraw = NULL, .config = ess_config -}; \ No newline at end of file +}; diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 44d9d0950..d14b41d9e 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -582,6 +582,37 @@ sb_16_write_dma(void *priv, uint16_t val) return ret; } +void +sb_ess_update_irq_drq_readback_regs(sb_dsp_t *dsp, bool legacy) +{ + uint8_t t = 0x00; + /* IRQ control */ + if (legacy) + { + t |= 0x80; + } + switch (dsp->sb_irqnum) { + case 5: t |= 0x5; break; + case 7: t |= 0xA; break; + case 10: t |= 0xF; break; + } + pclog("ESSreg 0xB1 was %02X, irqnum is %d, t is %02X; new 0xB1 is %02X\n", ESSreg(0xB1), dsp->sb_irqnum, t, (ESSreg(0xB1) & 0xF0) | t); + ESSreg(0xB1) = (ESSreg(0xB1) & 0xF0) | t; + + /* DRQ control */ + t = 0x00; + if (legacy) + { + t |= 0x80; + } + switch (dsp->sb_8_dmanum) { + case 0: t |= 0x5; break; + case 1: t |= 0xA; break; + case 3: t |= 0xF; break; + } + ESSreg(0xB2) = (ESSreg(0xB2) & 0xF0) | t; +} + void sb_dsp_setirq(sb_dsp_t *dsp, int irq) { @@ -589,23 +620,7 @@ sb_dsp_setirq(sb_dsp_t *dsp, int irq) sb_dsp_log("IRQ now: %i\n", irq); dsp->sb_irqnum = irq; - /* legacy audio interrupt control */ - t = 0x80;/*game compatible IRQ*/ - switch (dsp->sb_irqnum) { - case 5: t |= 0x5; break; - case 7: t |= 0xA; break; - case 10: t |= 0xF; break; - } - ESSreg(0xB1) = t; - - /* DRQ control */ - t = 0x80;/*game compatible DRQ */ - switch (dsp->sb_8_dmanum) { - case 0: t |= 0x5; break; - case 1: t |= 0xA; break; - case 3: t |= 0xF; break; - } - ESSreg(0xB2) = t; + sb_ess_update_irq_drq_readback_regs(dsp, true); } void @@ -615,23 +630,7 @@ sb_dsp_setdma8(sb_dsp_t *dsp, int dma) sb_dsp_log("8-bit DMA now: %i\n", dma); dsp->sb_8_dmanum = dma; - /* legacy audio interrupt control */ - t = 0x80;/*game compatible IRQ*/ - switch (dsp->sb_irqnum) { - case 5: t |= 0x5; break; - case 7: t |= 0xA; break; - case 10: t |= 0xF; break; - } - ESSreg(0xB1) = t; - - /* DRQ control */ - t = 0x80;/*game compatible DRQ */ - switch (dsp->sb_8_dmanum) { - case 0: t |= 0x5; break; - case 1: t |= 0xA; break; - case 3: t |= 0xF; break; - } - ESSreg(0xB2) = t; + sb_ess_update_irq_drq_readback_regs(dsp, true); } void @@ -686,6 +685,7 @@ static uint8_t sb_ess_read_reg(sb_dsp_t *dsp, uint8_t reg) { switch (reg) { default: + pclog("ESS register read reg=%02xh val=%02xh\n",reg, ESSreg(reg)); return ESSreg(reg); } @@ -752,9 +752,43 @@ static void sb_ess_write_reg(sb_dsp_t *dsp, uint8_t reg, uint8_t data) break; case 0xB1: /* Legacy Audio Interrupt Control */ + ESSreg(reg) = (ESSreg(reg) & 0x0F) + (data & 0xF0); // lower 4 bits not writeable + switch (data & 0x0C) + { + case 0x00: + dsp->sb_irqnum = 2; + break; + case 0x04: + dsp->sb_irqnum = 5; + break; + case 0x08: + dsp->sb_irqnum = 7; + break; + case 0x0C: + dsp->sb_irqnum = 10; + break; + } + sb_ess_update_irq_drq_readback_regs(dsp, false); + break; case 0xB2: /* DRQ Control */ chg = ESSreg(reg) ^ data; ESSreg(reg) = (ESSreg(reg) & 0x0F) + (data & 0xF0); // lower 4 bits not writeable + switch (data & 0x0C) + { + case 0x00: + dsp->sb_8_dmanum = -1; + break; + case 0x04: + dsp->sb_8_dmanum = 0; + break; + case 0x08: + dsp->sb_8_dmanum = 1; + break; + case 0x0C: + dsp->sb_8_dmanum = 3; + break; + } + sb_ess_update_irq_drq_readback_regs(dsp, false); if (chg & 0x40) sb_ess_update_dma_status(dsp); break; case 0xB5: /* DAC Direct Access Holding (low) */