Finish DSP part of ESS
This commit is contained in:
@@ -143,6 +143,7 @@ typedef struct sb_dsp_t {
|
|||||||
uint8_t ess_regs[256]; /* ESS registers. */
|
uint8_t ess_regs[256]; /* ESS registers. */
|
||||||
uint8_t ess_playback_mode;
|
uint8_t ess_playback_mode;
|
||||||
uint8_t ess_extended_mode;
|
uint8_t ess_extended_mode;
|
||||||
|
uint8_t ess_reload_len;
|
||||||
|
|
||||||
mpu_t *mpu;
|
mpu_t *mpu;
|
||||||
} sb_dsp_t;
|
} sb_dsp_t;
|
||||||
|
@@ -18,7 +18,7 @@ add_library(snd OBJECT sound.c snd_opl.c snd_opl_nuked.c snd_opl_ymfm.cpp snd_re
|
|||||||
snd_lpt_dss.c snd_ps1.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c
|
snd_lpt_dss.c snd_ps1.c snd_adlib.c snd_adlibgold.c snd_ad1848.c snd_audiopci.c
|
||||||
snd_azt2316a.c snd_cms.c snd_cmi8x38.c snd_cs423x.c snd_gus.c snd_sb.c snd_sb_dsp.c
|
snd_azt2316a.c snd_cms.c snd_cmi8x38.c snd_cs423x.c snd_gus.c snd_sb.c snd_sb_dsp.c
|
||||||
snd_emu8k.c snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c
|
snd_emu8k.c snd_mpu401.c snd_sn76489.c snd_ssi2001.c snd_wss.c snd_ym7128.c
|
||||||
snd_optimc.c esfmu/esfm.c esfmu/esfm_registers.c snd_opl_esfm.c)
|
snd_optimc.c esfmu/esfm.c esfmu/esfm_registers.c snd_opl_esfm.c snd_ess.c)
|
||||||
|
|
||||||
if(OPENAL)
|
if(OPENAL)
|
||||||
if(VCPKG_TOOLCHAIN)
|
if(VCPKG_TOOLCHAIN)
|
||||||
|
258
src/sound/snd_ess.c
Normal file
258
src/sound/snd_ess.c
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
/*
|
||||||
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||||
|
* running old operating systems and software designed for IBM
|
||||||
|
* PC systems and compatibles from 1981 through fairly recent
|
||||||
|
* system designs based on the PCI bus.
|
||||||
|
*
|
||||||
|
* This file is part of the 86Box distribution.
|
||||||
|
*
|
||||||
|
* Sound Blaster emulation.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Authors: Sarah Walker, <https://pcem-emulator.co.uk/>
|
||||||
|
* Miran Grca, <mgrca8@gmail.com>
|
||||||
|
* TheCollector1995, <mariogplayer@gmail.com>
|
||||||
|
*
|
||||||
|
* Copyright 2008-2020 Sarah Walker.
|
||||||
|
* Copyright 2016-2020 Miran Grca.
|
||||||
|
*/
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
#define HAVE_STDARG_H
|
||||||
|
|
||||||
|
#include <86box/86box.h>
|
||||||
|
#include <86box/device.h>
|
||||||
|
#include <86box/filters.h>
|
||||||
|
#include <86box/gameport.h>
|
||||||
|
#include <86box/hdc.h>
|
||||||
|
#include <86box/isapnp.h>
|
||||||
|
#include <86box/hdc_ide.h>
|
||||||
|
#include <86box/io.h>
|
||||||
|
#include <86box/mca.h>
|
||||||
|
#include <86box/mem.h>
|
||||||
|
#include <86box/midi.h>
|
||||||
|
#include <86box/pic.h>
|
||||||
|
#include <86box/rom.h>
|
||||||
|
#include <86box/sound.h>
|
||||||
|
#include <86box/timer.h>
|
||||||
|
#include <86box/snd_sb.h>
|
||||||
|
#include <86box/plat_unused.h>
|
||||||
|
|
||||||
|
static const double sb_att_4dbstep_3bits[] = {
|
||||||
|
164.0, 2067.0, 3276.0, 5193.0, 8230.0, 13045.0, 20675.0, 32767.0
|
||||||
|
};
|
||||||
|
|
||||||
|
static const double sb_att_7dbstep_2bits[] = {
|
||||||
|
164.0, 6537.0, 14637.0, 32767.0
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SB PRO */
|
||||||
|
typedef struct ess_mixer_t {
|
||||||
|
double master_l;
|
||||||
|
double master_r;
|
||||||
|
double voice_l;
|
||||||
|
double voice_r;
|
||||||
|
double fm_l;
|
||||||
|
double fm_r;
|
||||||
|
double cd_l;
|
||||||
|
double cd_r;
|
||||||
|
double line_l;
|
||||||
|
double line_r;
|
||||||
|
double mic;
|
||||||
|
/*see sb_ct1745_mixer for values for input selector*/
|
||||||
|
int32_t input_selector;
|
||||||
|
|
||||||
|
int input_filter;
|
||||||
|
int in_filter_freq;
|
||||||
|
int output_filter;
|
||||||
|
|
||||||
|
int stereo;
|
||||||
|
int stereo_isleft;
|
||||||
|
|
||||||
|
uint8_t index;
|
||||||
|
uint8_t regs[256];
|
||||||
|
} ess_mixer_t;
|
||||||
|
|
||||||
|
typedef struct ess_t {
|
||||||
|
uint8_t mixer_enabled;
|
||||||
|
fm_drv_t opl;
|
||||||
|
sb_dsp_t dsp;
|
||||||
|
union {
|
||||||
|
ess_mixer_t mixer_sbpro;
|
||||||
|
};
|
||||||
|
mpu_t *mpu;
|
||||||
|
emu8k_t emu8k;
|
||||||
|
void *gameport;
|
||||||
|
|
||||||
|
int pnp;
|
||||||
|
|
||||||
|
uint8_t pos_regs[8];
|
||||||
|
uint8_t pnp_rom[512];
|
||||||
|
|
||||||
|
uint16_t opl_pnp_addr;
|
||||||
|
uint16_t gameport_addr;
|
||||||
|
|
||||||
|
void *opl_mixer;
|
||||||
|
void (*opl_mix)(void*, double*, double*);
|
||||||
|
} ess_t;
|
||||||
|
|
||||||
|
static inline uint8_t expand16to32(const uint8_t t) {
|
||||||
|
/* 4-bit -> 5-bit expansion.
|
||||||
|
*
|
||||||
|
* 0 -> 0
|
||||||
|
* 1 -> 2
|
||||||
|
* 2 -> 4
|
||||||
|
* 3 -> 6
|
||||||
|
* ....
|
||||||
|
* 7 -> 14
|
||||||
|
* 8 -> 17
|
||||||
|
* 9 -> 19
|
||||||
|
* 10 -> 21
|
||||||
|
* 11 -> 23
|
||||||
|
* ....
|
||||||
|
* 15 -> 31 */
|
||||||
|
return (t << 1) | (t >> 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ess_mixer_write(uint16_t addr, uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
ess_t *ess = (ess_t *) priv;
|
||||||
|
ess_mixer_t *mixer = &ess->mixer_sbpro;
|
||||||
|
|
||||||
|
if (!(addr & 1)) {
|
||||||
|
mixer->index = val;
|
||||||
|
mixer->regs[0x01] = val;
|
||||||
|
} else {
|
||||||
|
if (mixer->index == 0) {
|
||||||
|
/* Reset */
|
||||||
|
mixer->regs[0x0a] = mixer->regs[0x0c] = 0x00;
|
||||||
|
mixer->regs[0x0e] = 0x00;
|
||||||
|
/* Changed default from -11dB to 0dB */
|
||||||
|
mixer->regs[0x04] = mixer->regs[0x22] = 0xee;
|
||||||
|
mixer->regs[0x26] = mixer->regs[0x28] = 0xee;
|
||||||
|
mixer->regs[0x2e] = 0x00;
|
||||||
|
sb_dsp_set_stereo(&ess->dsp, mixer->regs[0x0e] & 2);
|
||||||
|
} else {
|
||||||
|
mixer->regs[mixer->index] = val;
|
||||||
|
|
||||||
|
switch (mixer->index) {
|
||||||
|
/* Compatibility: chain registers 0x02 and 0x22 as well as 0x06 and 0x26 */
|
||||||
|
case 0x02:
|
||||||
|
case 0x06:
|
||||||
|
case 0x08:
|
||||||
|
mixer->regs[mixer->index + 0x20] = ((val & 0xe) << 4) | (val & 0xe);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x22:
|
||||||
|
case 0x26:
|
||||||
|
case 0x28:
|
||||||
|
mixer->regs[mixer->index - 0x20] = (val & 0xe);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* More compatibility:
|
||||||
|
SoundBlaster Pro selects register 020h for 030h, 022h for 032h,
|
||||||
|
026h for 036h, and 028h for 038h. */
|
||||||
|
case 0x30:
|
||||||
|
case 0x32:
|
||||||
|
case 0x36:
|
||||||
|
case 0x38:
|
||||||
|
mixer->regs[mixer->index - 0x10] = (val & 0xee);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x00:
|
||||||
|
case 0x04:
|
||||||
|
case 0x0a:
|
||||||
|
case 0x0c:
|
||||||
|
case 0x0e:
|
||||||
|
case 0x2e:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
//sb_log("ess: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mixer->voice_l = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 5) & 0x7] / 32768.0;
|
||||||
|
mixer->voice_r = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 1) & 0x7] / 32768.0;
|
||||||
|
mixer->master_l = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 5) & 0x7] / 32768.0;
|
||||||
|
mixer->master_r = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 1) & 0x7] / 32768.0;
|
||||||
|
mixer->fm_l = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 5) & 0x7] / 32768.0;
|
||||||
|
mixer->fm_r = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 1) & 0x7] / 32768.0;
|
||||||
|
mixer->cd_l = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 5) & 0x7] / 32768.0;
|
||||||
|
mixer->cd_r = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 1) & 0x7] / 32768.0;
|
||||||
|
mixer->line_l = sb_att_4dbstep_3bits[(mixer->regs[0x2e] >> 5) & 0x7] / 32768.0;
|
||||||
|
mixer->line_r = sb_att_4dbstep_3bits[(mixer->regs[0x2e] >> 1) & 0x7] / 32768.0;
|
||||||
|
|
||||||
|
mixer->mic = sb_att_7dbstep_2bits[(mixer->regs[0x0a] >> 1) & 0x3] / 32768.0;
|
||||||
|
|
||||||
|
mixer->output_filter = !(mixer->regs[0xe] & 0x20);
|
||||||
|
mixer->input_filter = !(mixer->regs[0xc] & 0x20);
|
||||||
|
mixer->in_filter_freq = ((mixer->regs[0xc] & 0x8) == 0) ? 3200 : 8800;
|
||||||
|
mixer->stereo = mixer->regs[0xe] & 2;
|
||||||
|
if (mixer->index == 0xe)
|
||||||
|
sb_dsp_set_stereo(&ess->dsp, val & 2);
|
||||||
|
|
||||||
|
switch (mixer->regs[0xc] & 6) {
|
||||||
|
case 2:
|
||||||
|
mixer->input_selector = INPUT_CD_L | INPUT_CD_R;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
mixer->input_selector = INPUT_LINE_L | INPUT_LINE_R;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mixer->input_selector = INPUT_MIC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: pcspeaker volume? Or is it not worth? */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
ess_mixer_read(uint16_t addr, void *priv)
|
||||||
|
{
|
||||||
|
const ess_t *ess = (ess_t *) priv;
|
||||||
|
const ess_mixer_t *mixer = &ess->mixer_sbpro;
|
||||||
|
|
||||||
|
if (!(addr & 1))
|
||||||
|
return mixer->index;
|
||||||
|
|
||||||
|
switch (mixer->index) {
|
||||||
|
case 0x00:
|
||||||
|
case 0x04:
|
||||||
|
case 0x0a:
|
||||||
|
case 0x0c:
|
||||||
|
case 0x0e:
|
||||||
|
case 0x22:
|
||||||
|
case 0x26:
|
||||||
|
case 0x28:
|
||||||
|
case 0x2e:
|
||||||
|
case 0x02:
|
||||||
|
case 0x06:
|
||||||
|
case 0x30:
|
||||||
|
case 0x32:
|
||||||
|
case 0x36:
|
||||||
|
case 0x38:
|
||||||
|
return mixer->regs[mixer->index];
|
||||||
|
|
||||||
|
default:
|
||||||
|
//sb_log("ess: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ess_mixer_reset(ess_t *ess)
|
||||||
|
{
|
||||||
|
ess_mixer_write(4, 0, ess);
|
||||||
|
ess_mixer_write(5, 0, ess);
|
||||||
|
}
|
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#define _USE_MATH_DEFINES
|
#define _USE_MATH_DEFINES
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -418,30 +419,65 @@ sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len)
|
|||||||
memset(dsp->record_buffer, 0, sizeof(dsp->record_buffer));
|
memset(dsp->record_buffer, 0, sizeof(dsp->record_buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
sb_start_dma_ess(sb_dsp_t* dsp, int dma8, int autoinit, uint8_t format, int len)
|
static unsigned int sb_ess_get_dma_len(sb_dsp_t *dsp)
|
||||||
{
|
{
|
||||||
|
unsigned int r;
|
||||||
|
|
||||||
|
r = (unsigned int)ESSreg(0xA5) << 8U;
|
||||||
|
r |= (unsigned int)ESSreg(0xA4);
|
||||||
|
|
||||||
|
/* the 16-bit counter is a "two's complement" of the DMA count because it counts UP to 0 and triggers IRQ on overflow */
|
||||||
|
return 0x10000U-r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
sb_start_dma_ess(sb_dsp_t* dsp)
|
||||||
|
{
|
||||||
|
uint8_t real_format = 0;
|
||||||
|
uint32_t len = !(ESSreg(0xB7) & 4) ? dsp->sb_8_length : dsp->sb_16_length;
|
||||||
|
|
||||||
|
if (!dsp->ess_reload_len) {
|
||||||
|
len = sb_ess_get_dma_len(dsp);
|
||||||
|
}
|
||||||
|
|
||||||
if (IS_ESS(dsp)) {
|
if (IS_ESS(dsp)) {
|
||||||
dma_set_drq(dsp->sb_8_dmanum, 0);
|
dma_set_drq(dsp->sb_8_dmanum, 0);
|
||||||
dma_set_drq(dsp->sb_16_8_dmanum, 0);
|
dma_set_drq(dsp->sb_16_8_dmanum, 0);
|
||||||
}
|
}
|
||||||
sb_start_dma(dsp, dma8, autoinit, format, len);
|
real_format |= !!(ESSreg(0xB7) & 0x20) ? 0x10 : 0;
|
||||||
|
real_format |= !!(ESSreg(0xB7) & 0x8) ? 0x20 : 0;
|
||||||
|
if (!!(ESSreg(0xB8) & 8))
|
||||||
|
sb_start_dma_i(dsp, !(ESSreg(0xB7) & 4), (ESSreg(0xB8) >> 2) & 1, real_format, sb_ess_get_dma_len(dsp));
|
||||||
|
else
|
||||||
|
sb_start_dma(dsp, !(ESSreg(0xB7) & 4), (ESSreg(0xB8) >> 2) & 1, real_format, sb_ess_get_dma_len(dsp));
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sb_start_dma_ess_i(sb_dsp_t* dsp, int dma8, int autoinit, uint8_t format, int len)
|
sb_stop_dma_ess(sb_dsp_t* dsp)
|
||||||
{
|
{
|
||||||
if (IS_ESS(dsp)) {
|
dsp->sb_8_enable = dsp->sb_16_enable = 0;
|
||||||
dma_set_drq(dsp->sb_8_dmanum, 0);
|
|
||||||
dma_set_drq(dsp->sb_16_8_dmanum, 0);
|
dma_set_drq(dsp->sb_16_8_dmanum, 0);
|
||||||
|
dma_set_drq(dsp->sb_8_dmanum, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sb_ess_update_dma_status(sb_dsp_t* dsp)
|
||||||
|
{
|
||||||
|
bool dma_en = (ESSreg(0xB8) & 1)?true:false;
|
||||||
|
|
||||||
|
// if the DRQ is disabled, do not start
|
||||||
|
if (!(ESSreg(0xB2) & 0x40))
|
||||||
|
dma_en = false;
|
||||||
|
|
||||||
|
if (dma_en) {
|
||||||
|
if (!dsp->sb_8_enable && !dsp->sb_16_enable) sb_start_dma_ess(dsp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (dsp->sb_8_enable || dsp->sb_16_enable) sb_stop_dma_ess(dsp);
|
||||||
}
|
}
|
||||||
sb_start_dma_i(dsp, dma8, autoinit, format, len);
|
|
||||||
dsp->ess_playback_mode = 1;
|
|
||||||
dma_set_drq(dsp->sb_8_dmanum, 1);
|
|
||||||
dma_set_drq(dsp->sb_16_8_dmanum, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -598,17 +634,6 @@ static void sb_ess_update_filter_freq(sb_dsp_t *dsp)
|
|||||||
ESSreg(0xA2) = 256 - (7160000 / (freq * 82));
|
ESSreg(0xA2) = 256 - (7160000 / (freq * 82));
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int sb_ess_get_dma_len(sb_dsp_t *dsp)
|
|
||||||
{
|
|
||||||
unsigned int r;
|
|
||||||
|
|
||||||
r = (unsigned int)ESSreg(0xA5) << 8U;
|
|
||||||
r |= (unsigned int)ESSreg(0xA4);
|
|
||||||
|
|
||||||
/* the 16-bit counter is a "two's complement" of the DMA count because it counts UP to 0 and triggers IRQ on overflow */
|
|
||||||
return 0x10000U-r;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t sb_ess_read_reg(sb_dsp_t *dsp, uint8_t reg)
|
static uint8_t sb_ess_read_reg(sb_dsp_t *dsp, uint8_t reg)
|
||||||
{
|
{
|
||||||
switch (reg) {
|
switch (reg) {
|
||||||
@@ -619,6 +644,120 @@ static uint8_t sb_ess_read_reg(sb_dsp_t *dsp, uint8_t reg)
|
|||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sb_ess_write_reg(sb_dsp_t *dsp, uint8_t reg, uint8_t data)
|
||||||
|
{
|
||||||
|
uint8_t chg = 0x00;
|
||||||
|
sb_dsp_log("ESS register write reg=%02xh val=%02xh\n",reg,data);
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
case 0xA1: /* Extended Mode Sample Rate Generator */
|
||||||
|
{
|
||||||
|
ESSreg(reg) = data;
|
||||||
|
if (data & 0x80)
|
||||||
|
dsp->sb_freq = 795500UL / (256ul - data);
|
||||||
|
else
|
||||||
|
dsp->sb_freq = 397700UL / (128ul - data);
|
||||||
|
|
||||||
|
if (dsp->sb_16_enable || dsp->sb_8_enable) {
|
||||||
|
sb_stop_dma_ess(dsp);
|
||||||
|
sb_start_dma_ess(dsp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0xA2: /* Filter divider (effectively, a hardware lowpass filter under S/W control) */
|
||||||
|
ESSreg(reg) = data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xA4: /* DMA Transfer Count Reload (low) */
|
||||||
|
case 0xA5: /* DMA Transfer Count Reload (high) */
|
||||||
|
ESSreg(reg) = data;
|
||||||
|
if (dsp->sb_16_length == 0 || dsp->sb_8_length == 0)
|
||||||
|
dsp->ess_reload_len = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xA8: /* Analog Control */
|
||||||
|
/* bits 7:5 0 Reserved. Always write 0
|
||||||
|
* bit 4 1 Reserved. Always write 1
|
||||||
|
* bit 3 Record monitor 1=Enable record monitor
|
||||||
|
* enable
|
||||||
|
* bit 2 0 Reserved. Always write 0
|
||||||
|
* bits 1:0 Stereo/mono select 00=Reserved
|
||||||
|
* 01=Stereo
|
||||||
|
* 10=Mono
|
||||||
|
* 11=Reserved */
|
||||||
|
chg = ESSreg(reg) ^ data;
|
||||||
|
ESSreg(reg) = data;
|
||||||
|
if (chg & 0x3) {
|
||||||
|
if (dsp->sb_16_enable || dsp->sb_8_enable) {
|
||||||
|
sb_stop_dma_ess(dsp);
|
||||||
|
sb_start_dma_ess(dsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xB1: /* Legacy Audio Interrupt Control */
|
||||||
|
case 0xB2: /* DRQ Control */
|
||||||
|
chg = ESSreg(reg) ^ data;
|
||||||
|
ESSreg(reg) = (ESSreg(reg) & 0x0F) + (data & 0xF0); // lower 4 bits not writeable
|
||||||
|
if (chg & 0x40) sb_ess_update_dma_status(dsp);
|
||||||
|
break;
|
||||||
|
case 0xB5: /* DAC Direct Access Holding (low) */
|
||||||
|
case 0xB6: /* DAC Direct Access Holding (high) */
|
||||||
|
ESSreg(reg) = data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xB7: /* Audio 1 Control 1 */
|
||||||
|
/* bit 7 Enable FIFO to/from codec
|
||||||
|
* bit 6 Opposite from bit 3 Must be set opposite to bit 3
|
||||||
|
* bit 5 FIFO signed mode 1=Data is signed twos-complement 0=Data is unsigned
|
||||||
|
* bit 4 Reserved Always write 1
|
||||||
|
* bit 3 FIFO stereo mode 1=Data is stereo
|
||||||
|
* bit 2 FIFO 16-bit mode 1=Data is 16-bit
|
||||||
|
* bit 1 Reserved Always write 0
|
||||||
|
* bit 0 Generate load signal */
|
||||||
|
chg = ESSreg(reg) ^ data;
|
||||||
|
ESSreg(reg) = data;
|
||||||
|
if (chg & 0x0C) {
|
||||||
|
if (dsp->sb_16_enable || dsp->sb_8_enable) {
|
||||||
|
sb_stop_dma_ess(dsp);
|
||||||
|
sb_start_dma_ess(dsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xB8: /* Audio 1 Control 2 */
|
||||||
|
/* bits 7:4 reserved
|
||||||
|
* bit 3 CODEC mode 1=first DMA converter in ADC mode
|
||||||
|
* 0=first DMA converter in DAC mode
|
||||||
|
* bit 2 DMA mode 1=auto-initialize mode
|
||||||
|
* 0=normal DMA mode
|
||||||
|
* bit 1 DMA read enable 1=first DMA is read (for ADC)
|
||||||
|
* 0=first DMA is write (for DAC)
|
||||||
|
* bit 0 DMA xfer enable 1=DMA is allowed to proceed */
|
||||||
|
data &= 0xF;
|
||||||
|
chg = ESSreg(reg) ^ data;
|
||||||
|
ESSreg(reg) = data;
|
||||||
|
|
||||||
|
if (chg & 1)
|
||||||
|
dsp->ess_reload_len = 1;
|
||||||
|
|
||||||
|
if (chg & 0xB) {
|
||||||
|
if (chg & 0xA) sb_stop_dma_ess(dsp); /* changing capture/playback direction? stop DMA to reinit */
|
||||||
|
sb_ess_update_dma_status(dsp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xB9: /* Audio 1 Transfer Type */
|
||||||
|
case 0xBA: /* Left Channel ADC Offset Adjust */
|
||||||
|
case 0xBB: /* Right Channel ADC Offset Adjust */
|
||||||
|
ESSreg(reg) = data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sb_exec_command(sb_dsp_t *dsp)
|
sb_exec_command(sb_dsp_t *dsp)
|
||||||
{
|
{
|
||||||
@@ -632,11 +771,17 @@ sb_exec_command(sb_dsp_t *dsp)
|
|||||||
if (dsp->sb_type >= SB16)
|
if (dsp->sb_type >= SB16)
|
||||||
dsp->sb_8051_ram[0x20] = dsp->sb_command;
|
dsp->sb_8051_ram[0x20] = dsp->sb_command;
|
||||||
|
|
||||||
if (IS_ESS(dsp)) {
|
if (IS_ESS(dsp) && dsp->sb_command >= 0xA0 && dsp->sb_command <= 0xCF) {
|
||||||
if (dsp->sb_command == 0xC6 || dsp->sb_command == 0xC7) {
|
if (dsp->sb_command == 0xC6 || dsp->sb_command == 0xC7) {
|
||||||
dsp->ess_extended_mode = !!(dsp->sb_command == 0xC6);
|
dsp->ess_extended_mode = !!(dsp->sb_command == 0xC6);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (dsp->sb_command == 0xC0) {
|
||||||
|
sb_add_data(dsp, sb_ess_read_reg(dsp, dsp->sb_data[0]));
|
||||||
|
} else if (dsp->sb_command < 0xC0 && dsp->ess_extended_mode) {
|
||||||
|
sb_ess_write_reg(dsp, dsp->sb_command, dsp->sb_data[0]);
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (dsp->sb_command) {
|
switch (dsp->sb_command) {
|
||||||
@@ -1062,12 +1207,29 @@ sb_exec_command(sb_dsp_t *dsp)
|
|||||||
while (sb16_copyright[c])
|
while (sb16_copyright[c])
|
||||||
sb_add_data(dsp, sb16_copyright[c++]);
|
sb_add_data(dsp, sb16_copyright[c++]);
|
||||||
sb_add_data(dsp, 0);
|
sb_add_data(dsp, 0);
|
||||||
|
} else if (IS_ESS(dsp)) {
|
||||||
|
sb_add_data(dsp, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xE4: /* Write test register */
|
case 0xE4: /* Write test register */
|
||||||
dsp->sb_test = dsp->sb_data[0];
|
dsp->sb_test = dsp->sb_data[0];
|
||||||
break;
|
break;
|
||||||
case 0xE7: /* ???? */
|
case 0xE7: /* ???? */ /* ESS detect/read config on ESS cards */
|
||||||
|
if (IS_ESS(dsp)) {
|
||||||
|
switch (dsp->sb_subtype) {
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
case SB_SUBTYPE_ESS_ES688:
|
||||||
|
sb_add_data(dsp, 0x68);
|
||||||
|
sb_add_data(dsp, 0x80 | 0x04);
|
||||||
|
break;
|
||||||
|
case SB_SUBTYPE_ESS_ES1688:
|
||||||
|
// Determined via Windows driver debugging.
|
||||||
|
sb_add_data(dsp, 0x68);
|
||||||
|
sb_add_data(dsp, 0x80 | 0x09);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0xE8: /* Read test register */
|
case 0xE8: /* Read test register */
|
||||||
sb_add_data(dsp, dsp->sb_test);
|
sb_add_data(dsp, dsp->sb_test);
|
||||||
@@ -1170,6 +1332,13 @@ sb_write(uint16_t a, uint8_t v, void *priv)
|
|||||||
else if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x07)
|
else if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x07)
|
||||||
sb_commands[dsp->sb_command] = 2;
|
sb_commands[dsp->sb_command] = 2;
|
||||||
}
|
}
|
||||||
|
if (IS_ESS(dsp) && dsp->sb_command >= 0xA0 && dsp->sb_command <= 0xCF) {
|
||||||
|
if (dsp->sb_command <= 0xC0) {
|
||||||
|
sb_commands[dsp->sb_command] = 1;
|
||||||
|
} else {
|
||||||
|
sb_commands[dsp->sb_command] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1) {
|
if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1) {
|
||||||
sb_exec_command(dsp);
|
sb_exec_command(dsp);
|
||||||
|
Reference in New Issue
Block a user