ESS: implement mixer regs and fix ESS-specific DMA
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#define HAVE_STDARG_H
|
#define HAVE_STDARG_H
|
||||||
|
|
||||||
@@ -122,6 +123,11 @@ static inline uint8_t expand16to32(const uint8_t t) {
|
|||||||
return (t << 1) | (t >> 3);
|
return (t << 1) | (t >> 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static double ess_mixer_get_vol_4bit(uint8_t vol)
|
||||||
|
{
|
||||||
|
return (48.0 + (20.0 * log((vol & 0xF) / 15.0))) / 48.0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
|
ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
|
||||||
{
|
{
|
||||||
@@ -142,6 +148,14 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
|
|||||||
mixer->regs[0x04] = mixer->regs[0x22] = 0xee;
|
mixer->regs[0x04] = mixer->regs[0x22] = 0xee;
|
||||||
mixer->regs[0x26] = mixer->regs[0x28] = 0xee;
|
mixer->regs[0x26] = mixer->regs[0x28] = 0xee;
|
||||||
mixer->regs[0x2e] = 0x00;
|
mixer->regs[0x2e] = 0x00;
|
||||||
|
|
||||||
|
/* Initialize ESS regs. */
|
||||||
|
mixer->regs[0x14] = mixer->regs[0x32] = 0x88;
|
||||||
|
mixer->regs[0x36] = 0x88;
|
||||||
|
mixer->regs[0x38] = 0x00;
|
||||||
|
mixer->regs[0x3a] = 0x00;
|
||||||
|
mixer->regs[0x3e] = 0x00;
|
||||||
|
|
||||||
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;
|
||||||
@@ -153,20 +167,29 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
|
|||||||
case 0x08:
|
case 0x08:
|
||||||
mixer->regs[mixer->index + 0x20] = ((val & 0xe) << 4) | (val & 0xe);
|
mixer->regs[mixer->index + 0x20] = ((val & 0xe) << 4) | (val & 0xe);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x14:
|
||||||
|
mixer->regs[0x4] = val & 0xee;
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x22:
|
case 0x22:
|
||||||
case 0x26:
|
case 0x26:
|
||||||
case 0x28:
|
case 0x28:
|
||||||
|
case 0x2E:
|
||||||
mixer->regs[mixer->index - 0x20] = (val & 0xe);
|
mixer->regs[mixer->index - 0x20] = (val & 0xe);
|
||||||
|
mixer->regs[mixer->index + 0x10] = val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* More compatibility:
|
/* More compatibility:
|
||||||
SoundBlaster Pro selects register 020h for 030h, 022h for 032h,
|
SoundBlaster Pro selects register 020h for 030h, 022h for 032h,
|
||||||
026h for 036h, and 028h for 038h. */
|
026h for 036h, and 028h for 038h. */
|
||||||
case 0x30:
|
case 0x30:
|
||||||
|
mixer->regs[mixer->index - 0x10] = (val & 0xee);
|
||||||
|
break;
|
||||||
case 0x32:
|
case 0x32:
|
||||||
case 0x36:
|
case 0x36:
|
||||||
case 0x38:
|
case 0x38:
|
||||||
|
case 0x3e:
|
||||||
mixer->regs[mixer->index - 0x10] = (val & 0xee);
|
mixer->regs[mixer->index - 0x10] = (val & 0xee);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -175,25 +198,75 @@ ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
|
|||||||
case 0x0a:
|
case 0x0a:
|
||||||
case 0x0c:
|
case 0x0c:
|
||||||
case 0x0e:
|
case 0x0e:
|
||||||
case 0x2e:
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x40: {
|
||||||
|
uint16_t mpu401_base_addr = 0x300 | ((mixer->regs[0x40] & 0x38) << 1);
|
||||||
|
gameport_remap(ess->gameport, !(mixer->regs[0x40] & 0x2) ? 0x00 : 0x200);
|
||||||
|
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) {
|
||||||
|
case 0:
|
||||||
|
mpu401_change_addr(ess->mpu, 0x00);
|
||||||
|
mpu401_setirq(ess->mpu, -1);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mpu401_change_addr(ess->mpu, mpu401_base_addr);
|
||||||
|
mpu401_setirq(ess->mpu, -1);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mpu401_change_addr(ess->mpu, mpu401_base_addr);
|
||||||
|
mpu401_setirq(ess->mpu, ess->dsp.sb_irqnum);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mpu401_change_addr(ess->mpu, mpu401_base_addr);
|
||||||
|
mpu401_setirq(ess->mpu, 0xE);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
mpu401_change_addr(ess->mpu, mpu401_base_addr);
|
||||||
|
mpu401_setirq(ess->mpu, 0xA);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
mpu401_change_addr(ess->mpu, mpu401_base_addr);
|
||||||
|
mpu401_setirq(ess->mpu, 0xB);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
mpu401_change_addr(ess->mpu, mpu401_base_addr);
|
||||||
|
mpu401_setirq(ess->mpu, 0xC);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
mpu401_change_addr(ess->mpu, mpu401_base_addr);
|
||||||
|
mpu401_setirq(ess->mpu, 0xD);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
//sb_log("ess: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
|
//sb_log("ess: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mixer->voice_l = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 5) & 0x7] / 32768.0;
|
mixer->voice_l = ess_mixer_get_vol_4bit(mixer->regs[0x14]);
|
||||||
mixer->voice_r = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 1) & 0x7] / 32768.0;
|
mixer->voice_r = ess_mixer_get_vol_4bit(mixer->regs[0x14] >> 4);
|
||||||
mixer->master_l = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 5) & 0x7] / 32768.0;
|
mixer->master_l = ess_mixer_get_vol_4bit(mixer->regs[0x32]);
|
||||||
mixer->master_r = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 1) & 0x7] / 32768.0;
|
mixer->master_r = ess_mixer_get_vol_4bit(mixer->regs[0x32] >> 4);
|
||||||
mixer->fm_l = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 5) & 0x7] / 32768.0;
|
mixer->fm_l = ess_mixer_get_vol_4bit(mixer->regs[0x36]);
|
||||||
mixer->fm_r = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 1) & 0x7] / 32768.0;
|
mixer->fm_r = ess_mixer_get_vol_4bit(mixer->regs[0x36] >> 4);
|
||||||
mixer->cd_l = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 5) & 0x7] / 32768.0;
|
mixer->cd_l = ess_mixer_get_vol_4bit(mixer->regs[0x38]);
|
||||||
mixer->cd_r = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 1) & 0x7] / 32768.0;
|
mixer->cd_r = ess_mixer_get_vol_4bit(mixer->regs[0x38] >> 4);
|
||||||
mixer->line_l = sb_att_4dbstep_3bits[(mixer->regs[0x2e] >> 5) & 0x7] / 32768.0;
|
mixer->line_l = ess_mixer_get_vol_4bit(mixer->regs[0x3e]);
|
||||||
mixer->line_r = sb_att_4dbstep_3bits[(mixer->regs[0x2e] >> 1) & 0x7] / 32768.0;
|
mixer->line_r = ess_mixer_get_vol_4bit(mixer->regs[0x3e] >> 4);
|
||||||
|
|
||||||
mixer->mic = sb_att_7dbstep_2bits[(mixer->regs[0x0a] >> 1) & 0x3] / 32768.0;
|
mixer->mic = sb_att_7dbstep_2bits[(mixer->regs[0x0a] >> 1) & 0x3] / 32768.0;
|
||||||
|
|
||||||
@@ -372,6 +445,8 @@ ess_1688_init(UNUSED(const device_t *info))
|
|||||||
sb_dsp_setaddr(&ess->dsp, addr);
|
sb_dsp_setaddr(&ess->dsp, addr);
|
||||||
sb_dsp_setirq(&ess->dsp, device_get_config_int("irq"));
|
sb_dsp_setirq(&ess->dsp, device_get_config_int("irq"));
|
||||||
sb_dsp_setdma8(&ess->dsp, device_get_config_int("dma"));
|
sb_dsp_setdma8(&ess->dsp, device_get_config_int("dma"));
|
||||||
|
sb_dsp_setdma16_8(&ess->dsp, device_get_config_int("dma"));
|
||||||
|
sb_dsp_setdma16_supported(&ess->dsp, 0);
|
||||||
ess_mixer_reset(ess);
|
ess_mixer_reset(ess);
|
||||||
/* DSP I/O handler is activated in sb_dsp_setaddr */
|
/* DSP I/O handler is activated in sb_dsp_setaddr */
|
||||||
{
|
{
|
||||||
@@ -408,6 +483,14 @@ ess_1688_init(UNUSED(const device_t *info))
|
|||||||
ess->mixer_sbpro.ess_id_str[3] = addr & 0xff;
|
ess->mixer_sbpro.ess_id_str[3] = addr & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ess->mpu = (mpu_t *) calloc(1, sizeof(mpu_t));
|
||||||
|
mpu401_init(ess->mpu, 0, 0, M_UART, 1);
|
||||||
|
sb_dsp_set_mpu(&ess->dsp, ess->mpu);
|
||||||
|
|
||||||
|
ess->gameport = gameport_add(&gameport_pnp_device);
|
||||||
|
ess->gameport_addr = 0x000;
|
||||||
|
gameport_remap(ess->gameport, ess->gameport_addr);
|
||||||
|
|
||||||
return ess;
|
return ess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -437,7 +437,7 @@ sb_start_dma_ess(sb_dsp_t* dsp)
|
|||||||
uint8_t real_format = 0;
|
uint8_t real_format = 0;
|
||||||
uint32_t len = !(ESSreg(0xB7) & 4) ? dsp->sb_8_length : dsp->sb_16_length;
|
uint32_t len = !(ESSreg(0xB7) & 4) ? dsp->sb_8_length : dsp->sb_16_length;
|
||||||
|
|
||||||
if (dsp->ess_reload_len) {
|
if (dsp->ess_reload_len || len <= 0) {
|
||||||
len = sb_ess_get_dma_len(dsp);
|
len = sb_ess_get_dma_len(dsp);
|
||||||
dsp->ess_reload_len = 0;
|
dsp->ess_reload_len = 0;
|
||||||
}
|
}
|
||||||
@@ -449,9 +449,9 @@ sb_start_dma_ess(sb_dsp_t* dsp)
|
|||||||
real_format |= !!(ESSreg(0xB7) & 0x20) ? 0x10 : 0;
|
real_format |= !!(ESSreg(0xB7) & 0x20) ? 0x10 : 0;
|
||||||
real_format |= !!(ESSreg(0xB7) & 0x8) ? 0x20 : 0;
|
real_format |= !!(ESSreg(0xB7) & 0x8) ? 0x20 : 0;
|
||||||
if (!!(ESSreg(0xB8) & 8))
|
if (!!(ESSreg(0xB8) & 8))
|
||||||
sb_start_dma_i(dsp, !(ESSreg(0xB7) & 4), (ESSreg(0xB8) >> 2) & 1, real_format, sb_ess_get_dma_len(dsp));
|
sb_start_dma_i(dsp, !(ESSreg(0xB7) & 4), (ESSreg(0xB8) >> 2) & 1, real_format, len);
|
||||||
else
|
else
|
||||||
sb_start_dma(dsp, !(ESSreg(0xB7) & 4), (ESSreg(0xB8) >> 2) & 1, real_format, sb_ess_get_dma_len(dsp));
|
sb_start_dma(dsp, !(ESSreg(0xB7) & 4), (ESSreg(0xB8) >> 2) & 1, real_format, len);
|
||||||
dsp->ess_playback_mode = 1;
|
dsp->ess_playback_mode = 1;
|
||||||
dma_set_drq(dsp->sb_8_dmanum, 1);
|
dma_set_drq(dsp->sb_8_dmanum, 1);
|
||||||
dma_set_drq(dsp->sb_16_8_dmanum, 1);
|
dma_set_drq(dsp->sb_16_8_dmanum, 1);
|
||||||
@@ -748,8 +748,15 @@ static void sb_ess_write_reg(sb_dsp_t *dsp, uint8_t reg, uint8_t data)
|
|||||||
chg = ESSreg(reg) ^ data;
|
chg = ESSreg(reg) ^ data;
|
||||||
ESSreg(reg) = data;
|
ESSreg(reg) = data;
|
||||||
|
|
||||||
if (chg & 1)
|
if (chg & 1) {
|
||||||
dsp->ess_reload_len = 1;
|
if (dsp->sb_16_enable || dsp->sb_8_enable) {
|
||||||
|
if (dsp->sb_16_enable)
|
||||||
|
dsp->sb_16_length = sb_ess_get_dma_len(dsp);
|
||||||
|
if (dsp->sb_8_enable)
|
||||||
|
dsp->sb_8_length = sb_ess_get_dma_len(dsp);
|
||||||
|
} else
|
||||||
|
dsp->ess_reload_len = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (chg & 0xB) {
|
if (chg & 0xB) {
|
||||||
if (chg & 0xA) sb_stop_dma_ess(dsp); /* changing capture/playback direction? stop DMA to reinit */
|
if (chg & 0xA) sb_stop_dma_ess(dsp); /* changing capture/playback direction? stop DMA to reinit */
|
||||||
|
Reference in New Issue
Block a user