Some cleanup, implementing IRQ and DMA channel register update

This commit is contained in:
Kagamiin~
2024-03-05 21:22:15 -03:00
parent b8ff131996
commit c76ada30b7
2 changed files with 105 additions and 59 deletions

View File

@@ -6,16 +6,20 @@
* *
* This file is part of the 86Box distribution. * This file is part of the 86Box distribution.
* *
* Sound Blaster emulation. * ESS AudioDrive emulation.
* *
* *
* *
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/> * Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com> * Miran Grca, <mgrca8@gmail.com>
* TheCollector1995, <mariogplayer@gmail.com> * TheCollector1995, <mariogplayer@gmail.com>
* Cacodemon345,
* Kagamiin~, <kagamiin@riseup.net>
* *
* Copyright 2008-2020 Sarah Walker. * Copyright 2008-2020 Sarah Walker.
* Copyright 2016-2020 Miran Grca. * Copyright 2016-2020 Miran Grca.
* Copyright 2024 Cacodemon345
* Copyright 2024 Kagamiin~
*/ */
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h> #include <stdint.h>
@@ -79,7 +83,7 @@ typedef struct ess_mixer_t {
uint8_t regs[256]; uint8_t regs[256];
uint8_t ess_id_str[256]; uint8_t ess_id_str[256];
uint8_t ess_id_str_pos : 2; uint8_t ess_id_str_pos;
} ess_mixer_t; } ess_mixer_t;
typedef struct ess_t { typedef struct ess_t {
@@ -130,7 +134,10 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
mixer->index = val; mixer->index = val;
mixer->regs[0x01] = val; mixer->regs[0x01] = val;
if (val == 0x40) if (val == 0x40)
{
pclog("ess: Mixer addr 0x40 selected, ID string offset reset\n");
mixer->ess_id_str_pos = 0; mixer->ess_id_str_pos = 0;
}
} else { } else {
if (mixer->index == 0) { if (mixer->index == 0) {
/* Reset */ /* 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); sb_dsp_set_stereo(&ess->dsp, mixer->regs[0x0e] & 2);
} else { } else {
mixer->regs[mixer->index] = val; 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) { switch (mixer->index) {
/* Compatibility: chain registers 0x02 and 0x22 as well as 0x06 and 0x26 */ /* 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; break;
case 0x40: { case 0x40: {
break; /* TODO: Implement "Read-Sequence-Key" method of software address selection
uint16_t mpu401_base_addr = 0x300 | ((mixer->regs[0x40] & 0x38) << 1); * (needed for ESSCFG.EXE to work properly) */
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);
}*/
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: case 0:
mpu401_change_addr(ess->mpu, 0x00); mpu401_change_addr(ess->mpu, 0x00);
mpu401_setirq(ess->mpu, -1); mpu401_setirq(ess->mpu, -1);
@@ -252,7 +263,7 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
} }
default: 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; break;
} }
} }
@@ -320,21 +331,22 @@ ess_mixer_read(uint16_t addr, void *priv)
case 0x36: case 0x36:
case 0x38: case 0x38:
case 0x3e: 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]; return mixer->regs[mixer->index];
case 0x40: case 0x40:
{ {
uint8_t val = mixer->ess_id_str[mixer->ess_id_str_pos]; 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++; mixer->ess_id_str_pos++;
if (mixer->ess_id_str_pos >= 4) if (mixer->ess_id_str_pos >= 4)
mixer->ess_id_str_pos = 0; 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; return val;
} }
default: 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; break;
} }
@@ -491,7 +503,7 @@ ess_1688_init(UNUSED(const device_t *info))
} }
ess->mpu = (mpu_t *) calloc(1, sizeof(mpu_t)); 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); sb_dsp_set_mpu(&ess->dsp, ess->mpu);
ess->gameport = gameport_add(&gameport_pnp_device); ess->gameport = gameport_add(&gameport_pnp_device);
@@ -620,4 +632,4 @@ const device_t ess_1688_device = {
.speed_changed = ess_speed_changed, .speed_changed = ess_speed_changed,
.force_redraw = NULL, .force_redraw = NULL,
.config = ess_config .config = ess_config
}; };

View File

@@ -582,6 +582,37 @@ sb_16_write_dma(void *priv, uint16_t val)
return ret; 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 void
sb_dsp_setirq(sb_dsp_t *dsp, int irq) 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); sb_dsp_log("IRQ now: %i\n", irq);
dsp->sb_irqnum = irq; dsp->sb_irqnum = irq;
/* legacy audio interrupt control */ sb_ess_update_irq_drq_readback_regs(dsp, true);
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;
} }
void void
@@ -615,23 +630,7 @@ sb_dsp_setdma8(sb_dsp_t *dsp, int dma)
sb_dsp_log("8-bit DMA now: %i\n", dma); sb_dsp_log("8-bit DMA now: %i\n", dma);
dsp->sb_8_dmanum = dma; dsp->sb_8_dmanum = dma;
/* legacy audio interrupt control */ sb_ess_update_irq_drq_readback_regs(dsp, true);
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;
} }
void void
@@ -686,6 +685,7 @@ static uint8_t sb_ess_read_reg(sb_dsp_t *dsp, uint8_t reg)
{ {
switch (reg) { switch (reg) {
default: default:
pclog("ESS register read reg=%02xh val=%02xh\n",reg, ESSreg(reg));
return 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; break;
case 0xB1: /* Legacy Audio Interrupt Control */ 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 */ case 0xB2: /* DRQ Control */
chg = ESSreg(reg) ^ data; chg = ESSreg(reg) ^ data;
ESSreg(reg) = (ESSreg(reg) & 0x0F) + (data & 0xF0); // lower 4 bits not writeable 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); if (chg & 0x40) sb_ess_update_dma_status(dsp);
break; break;
case 0xB5: /* DAC Direct Access Holding (low) */ case 0xB5: /* DAC Direct Access Holding (low) */