CMI8x38: Implement Sound Blaster emulation
This commit is contained in:
2
.ci/Jenkinsfile
vendored
2
.ci/Jenkinsfile
vendored
@@ -25,7 +25,7 @@ def osArchs = [
|
||||
]
|
||||
|
||||
def osFlags = [
|
||||
'Windows': '',
|
||||
'Windows': '-D QT=ON',
|
||||
'Linux': '-D QT=ON'
|
||||
]
|
||||
|
||||
|
@@ -35,11 +35,11 @@
|
||||
|
||||
dma_t dma[8];
|
||||
uint8_t dma_e;
|
||||
uint8_t dma_m;
|
||||
|
||||
|
||||
static uint8_t dmaregs[3][16];
|
||||
static int dma_wp[2];
|
||||
static uint8_t dma_m;
|
||||
static uint8_t dma_stat;
|
||||
static uint8_t dma_stat_rq;
|
||||
static uint8_t dma_stat_rq_pc;
|
||||
|
@@ -66,6 +66,7 @@ typedef struct {
|
||||
|
||||
extern dma_t dma[8];
|
||||
extern uint8_t dma_e;
|
||||
extern uint8_t dma_m;
|
||||
|
||||
|
||||
extern void dma_init(void);
|
||||
|
@@ -20,6 +20,11 @@ typedef struct sb_dsp_t {
|
||||
int sb_16_length, sb_16_format, sb_16_autoinit, sb_16_pause, sb_16_enable, sb_16_autolen, sb_16_output;
|
||||
int sb_16_dmanum;
|
||||
int sb_pausetime;
|
||||
int (*dma_readb)(void *priv),
|
||||
(*dma_readw)(void *priv),
|
||||
(*dma_writeb)(void *priv, uint8_t val),
|
||||
(*dma_writew)(void *priv, uint16_t val);
|
||||
void *dma_priv;
|
||||
|
||||
uint8_t sb_read_data[256];
|
||||
int sb_read_wp, sb_read_rp;
|
||||
@@ -36,6 +41,8 @@ typedef struct sb_dsp_t {
|
||||
int midi_in_timestamp;
|
||||
|
||||
int sb_irqnum;
|
||||
void (*irq_update)(void *priv, int set),
|
||||
*irq_priv;
|
||||
|
||||
uint8_t sbe2;
|
||||
int sbe2count;
|
||||
@@ -53,7 +60,7 @@ typedef struct sb_dsp_t {
|
||||
|
||||
int sbdacpos;
|
||||
|
||||
int sbleftright;
|
||||
int sbleftright, sbleftright_default;
|
||||
|
||||
int sbreset;
|
||||
uint8_t sbreaddat;
|
||||
@@ -123,4 +130,12 @@ void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo);
|
||||
void sb_dsp_update(sb_dsp_t *dsp);
|
||||
void sb_update_mask(sb_dsp_t *dsp, int irqm8, int irqm16, int irqm401);
|
||||
|
||||
void sb_dsp_irq_attach(sb_dsp_t *dsp, void (*irq_update)(void *priv, int set), void *priv);
|
||||
void sb_dsp_dma_attach(sb_dsp_t *dsp,
|
||||
int (*dma_readb)(void *priv),
|
||||
int (*dma_readw)(void *priv),
|
||||
int (*dma_writeb)(void *priv, uint8_t val),
|
||||
int (*dma_writew)(void *priv, uint16_t val),
|
||||
void *priv);
|
||||
|
||||
#endif /* SOUND_SND_SB_DSP_H */
|
||||
|
4
src/io.c
4
src/io.c
@@ -673,7 +673,7 @@ io_trap_remap(void *handle, int enable, uint16_t addr, uint16_t size)
|
||||
trap->base, trap->base + trap->size - 1, trap->enable, addr, addr + size - 1, enable);
|
||||
|
||||
/* Remove old I/O mapping. */
|
||||
if (trap->enable && trap->base && trap->size) {
|
||||
if (trap->enable && trap->size) {
|
||||
io_removehandler(trap->base, trap->size,
|
||||
io_trap_readb, io_trap_readw, io_trap_readl,
|
||||
io_trap_writeb, io_trap_writew, io_trap_writel,
|
||||
@@ -686,7 +686,7 @@ io_trap_remap(void *handle, int enable, uint16_t addr, uint16_t size)
|
||||
trap->size = size;
|
||||
|
||||
/* Add new I/O mapping. */
|
||||
if (trap->enable && trap->base && trap->size) {
|
||||
if (trap->enable && trap->size) {
|
||||
io_sethandler(trap->base, trap->size,
|
||||
io_trap_readb, io_trap_readw, io_trap_readl,
|
||||
io_trap_writeb, io_trap_writew, io_trap_writel,
|
||||
|
@@ -26,10 +26,13 @@
|
||||
#include <86box/mem.h>
|
||||
#include <86box/pic.h>
|
||||
#include <86box/timer.h>
|
||||
#include <86box/dma.h>
|
||||
#include <86box/pci.h>
|
||||
#include <86box/sound.h>
|
||||
#include <86box/snd_sb.h>
|
||||
#include <86box/snd_sb_dsp.h>
|
||||
#include <86box/gameport.h>
|
||||
#include <86box/nmi.h>
|
||||
#include <86box/ui.h>
|
||||
|
||||
|
||||
@@ -43,6 +46,14 @@ enum {
|
||||
CMEDIA_CMI8738_6CH = 0x080011 /* chip version 055 with 6-channel output */
|
||||
};
|
||||
|
||||
enum {
|
||||
TRAP_DMA = 0,
|
||||
TRAP_PIC,
|
||||
TRAP_OPL,
|
||||
TRAP_MPU,
|
||||
TRAP_MAX
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t id, reg, always_run, playback_enabled, channels;
|
||||
struct _cmi8x38_ *dev;
|
||||
@@ -63,17 +74,21 @@ typedef struct {
|
||||
typedef struct _cmi8x38_ {
|
||||
uint32_t type;
|
||||
uint16_t io_base, sb_base, opl_base, mpu_base;
|
||||
uint8_t pci_regs[256], io_regs[256], mixer_ext_regs[16];
|
||||
int slot;
|
||||
uint8_t pci_regs[256], io_regs[256];
|
||||
int slot, sb_irq;
|
||||
|
||||
sb_t *sb;
|
||||
void *gameport;
|
||||
void *gameport, *io_traps[TRAP_MAX];
|
||||
|
||||
cmi8x38_dma_t dma[2];
|
||||
uint16_t tdma_base_addr, tdma_base_count;
|
||||
uint8_t prev_mask;
|
||||
int tdma_last_8, tdma_last_16, tdma_mask;
|
||||
|
||||
int master_vol_l, master_vol_r, cd_vol_l, cd_vol_r;
|
||||
} cmi8x38_t;
|
||||
|
||||
#define ENABLE_CMI8X38_LOG 1
|
||||
|
||||
#ifdef ENABLE_CMI8X38_LOG
|
||||
int cmi8x38_do_log = ENABLE_CMI8X38_LOG;
|
||||
|
||||
@@ -104,7 +119,7 @@ static void
|
||||
cmi8x38_update_irqs(cmi8x38_t *dev)
|
||||
{
|
||||
/* Calculate and use the INTR flag. */
|
||||
if (*((uint32_t *) &dev->io_regs[0x10]) & 0x0401c003) {
|
||||
if ((*((uint32_t *) &dev->io_regs[0x10]) & 0x0401c003) || dev->sb_irq) {
|
||||
dev->io_regs[0x13] |= 0x80;
|
||||
pci_set_irq(dev->slot, PCI_INTA);
|
||||
cmi8x38_log("CMI8x38: Raising IRQ\n");
|
||||
@@ -135,6 +150,290 @@ cmi8x38_mpu_irq_pending(void *priv)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cmi8x38_sb_irq_update(void *priv, int set)
|
||||
{
|
||||
cmi8x38_t *dev = (cmi8x38_t *) priv;
|
||||
dev->sb_irq = set;
|
||||
cmi8x38_update_irqs(dev);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cmi8x38_sb_dma_post(cmi8x38_t *dev, uint16_t *addr, uint16_t *count, int channel)
|
||||
{
|
||||
/* Increment address and decrement count. */
|
||||
*addr += 1;
|
||||
*count -= 1;
|
||||
|
||||
/* Handle end of DMA. */
|
||||
if (*count == 0xffff) {
|
||||
if (dma[channel].mode & 0x10) { /* auto-init */
|
||||
/* Restart TDMA. */
|
||||
*addr = dev->tdma_base_addr;
|
||||
*count = dev->tdma_base_count;
|
||||
cmi8x38_log("CMI8x38: Restarting TDMA on DMA %d with addr %08X count %04X\n", channel, (dma[channel].ab & 0xffff0000) | *addr, *count);
|
||||
} else {
|
||||
/* Mask TDMA. */
|
||||
dev->tdma_mask |= 1 << channel;
|
||||
}
|
||||
return DMA_OVER;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cmi8x38_sb_dma_readb(void *priv)
|
||||
{
|
||||
cmi8x38_t *dev = (cmi8x38_t *) priv;
|
||||
|
||||
/* Stop if the DMA channel is invalid or if TDMA is masked. */
|
||||
int channel = dev->sb->dsp.sb_8_dmanum;
|
||||
if ((channel < 0) || (dev->tdma_mask & (1 << channel)))
|
||||
return DMA_NODATA;
|
||||
|
||||
/* Get 16-bit address and count registers. */
|
||||
uint16_t *addr = (uint16_t *) &dev->io_regs[0x1c],
|
||||
*count = (uint16_t *) &dev->io_regs[0x1e];
|
||||
|
||||
/* Read data. */
|
||||
int ret = mem_readb_phys((dma[channel].ab & 0xffff0000) | *addr);
|
||||
|
||||
/* Handle address, count and end. */
|
||||
ret |= cmi8x38_sb_dma_post(dev, addr, count, channel);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cmi8x38_sb_dma_readw(void *priv)
|
||||
{
|
||||
cmi8x38_t *dev = (cmi8x38_t *) priv;
|
||||
|
||||
/* Stop if the DMA channel is invalid or if TDMA is masked. */
|
||||
int channel = dev->sb->dsp.sb_16_dmanum;
|
||||
if ((channel < 0) || (dev->tdma_mask & (1 << channel)))
|
||||
return DMA_NODATA;
|
||||
|
||||
/* Get 16-bit address and count registers. */
|
||||
uint16_t *addr = (uint16_t *) &dev->io_regs[0x1c],
|
||||
*count = (uint16_t *) &dev->io_regs[0x1e];
|
||||
|
||||
/* Read data. */
|
||||
int ret = mem_readw_phys((dma[channel].ab & 0xfffe0000) | ((*addr) << 1));
|
||||
|
||||
/* Handle address, count and end. */
|
||||
ret |= cmi8x38_sb_dma_post(dev, addr, count, channel);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cmi8x38_sb_dma_writeb(void *priv, uint8_t val)
|
||||
{
|
||||
cmi8x38_t *dev = (cmi8x38_t *) priv;
|
||||
|
||||
/* Stop if the DMA channel is invalid or if TDMA is masked. */
|
||||
int channel = dev->sb->dsp.sb_8_dmanum;
|
||||
if ((channel < 0) || (dev->tdma_mask & (1 << channel)))
|
||||
return 1;
|
||||
|
||||
/* Get 16-bit address and count registers. */
|
||||
uint16_t *addr = (uint16_t *) &dev->io_regs[0x1c],
|
||||
*count = (uint16_t *) &dev->io_regs[0x1e];
|
||||
|
||||
/* Write data. */
|
||||
mem_writeb_phys((dma[channel].ab & 0xffff0000) | *addr, val);
|
||||
|
||||
/* Handle address, count and end. */
|
||||
cmi8x38_sb_dma_post(dev, addr, count, channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
cmi8x38_sb_dma_writew(void *priv, uint16_t val)
|
||||
{
|
||||
cmi8x38_t *dev = (cmi8x38_t *) priv;
|
||||
|
||||
/* Stop if the DMA channel is invalid or if TDMA is masked. */
|
||||
int channel = dev->sb->dsp.sb_16_dmanum;
|
||||
if ((channel < 0) || (dev->tdma_mask & (1 << channel)))
|
||||
return 1;
|
||||
|
||||
/* Get 16-bit address and count registers. */
|
||||
uint16_t *addr = (uint16_t *) &dev->io_regs[0x1c],
|
||||
*count = (uint16_t *) &dev->io_regs[0x1e];
|
||||
|
||||
/* Write data. */
|
||||
mem_writew_phys((dma[channel].ab & 0xfffe0000) | ((*addr) << 1), val);
|
||||
|
||||
/* Handle address, count and end. */
|
||||
cmi8x38_sb_dma_post(dev, addr, count, channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cmi8x38_dma_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
cmi8x38_t *dev = (cmi8x38_t *) priv;
|
||||
|
||||
/* Keep track of the last DMA channel written to. */
|
||||
uint8_t channel;
|
||||
if (addr < 0x08) {
|
||||
channel = addr >> 1;
|
||||
dev->tdma_last_8 = channel;
|
||||
} else {
|
||||
channel = 4 | ((addr >> 2) & 3);
|
||||
dev->tdma_last_16 = channel;
|
||||
}
|
||||
|
||||
/* Stop if not autodetecting. See note on cmi8x38_write(0x27). */
|
||||
if (!(dev->io_regs[0x27] & 0x01))
|
||||
return;
|
||||
|
||||
/* Write TDMA registers if this is a TDMA channel. */
|
||||
if ((channel == dev->sb->dsp.sb_8_dmanum) || (channel == dev->sb->dsp.sb_16_dmanum)) {
|
||||
/* Write base address and count. */
|
||||
uint16_t *addr = (uint16_t *) &dev->io_regs[0x1c],
|
||||
*count = (uint16_t *) &dev->io_regs[0x1e];
|
||||
*addr = dev->tdma_base_addr = dma[channel].ab >> !!(channel & 4);
|
||||
*count = dev->tdma_base_count = dma[channel].cb;
|
||||
cmi8x38_log("CMI8x38: Starting TDMA on DMA %d with addr %08X count %04X\n", channel, (dma[channel].ab & 0xffff0000) | *addr, *count);
|
||||
|
||||
/* Set high channel flag. */
|
||||
if (channel & 4)
|
||||
dev->io_regs[0x10] |= 0x20;
|
||||
else
|
||||
dev->io_regs[0x10] &= ~0x20;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cmi8x38_dma_mask_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
cmi8x38_t *dev = (cmi8x38_t *) priv;
|
||||
|
||||
/* Stop if not autodetecting. See note on cmi8x38_write(0x27). */
|
||||
if (!(dev->io_regs[0x27] & 0x01))
|
||||
return;
|
||||
|
||||
/* Unmask TDMA on DMA unmasking edge. */
|
||||
if ((dev->sb->dsp.sb_8_dmanum >= 0) && (dev->prev_mask & (1 << dev->sb->dsp.sb_8_dmanum)) && !(dma_m & (1 << dev->sb->dsp.sb_8_dmanum)))
|
||||
dev->tdma_mask &= ~(1 << dev->sb->dsp.sb_8_dmanum);
|
||||
else if ((dev->sb->dsp.sb_16_dmanum >= 0) && (dev->prev_mask & (1 << dev->sb->dsp.sb_16_dmanum)) && !(dma_m & (1 << dev->sb->dsp.sb_16_dmanum)))
|
||||
dev->tdma_mask &= ~(1 << dev->sb->dsp.sb_16_dmanum);
|
||||
dev->prev_mask = dma_m;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cmi8338_io_trap(int size, uint16_t addr, uint8_t write, uint8_t val, void *priv)
|
||||
{
|
||||
cmi8x38_t *dev = (cmi8x38_t *) priv;
|
||||
|
||||
#ifdef ENABLE_CMI8X38_LOG
|
||||
if (write)
|
||||
cmi8x38_log("CMI8x38: cmi8338_io_trap(%04X, %02X)\n", addr, val);
|
||||
else
|
||||
cmi8x38_log("CMI8x38: cmi8338_io_trap(%04X)\n", addr);
|
||||
#endif
|
||||
|
||||
/* Weird offsets, it's best to just treat the register as a big dword. */
|
||||
uint32_t *lcs = (uint32_t *) &dev->io_regs[0x14];
|
||||
*lcs &= ~0x0003dff0;
|
||||
*lcs |= (addr & 0x0f) << 14;
|
||||
if (write)
|
||||
*lcs |= 0x1000 | (val << 4);
|
||||
|
||||
/* Raise NMI. */
|
||||
nmi = 1;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
cmi8x38_sb_mixer_read(uint16_t addr, void *priv)
|
||||
{
|
||||
cmi8x38_t *dev = (cmi8x38_t *) priv;
|
||||
sb_ct1745_mixer_t *mixer = &dev->sb->mixer_sb16;
|
||||
uint8_t ret = sb_ct1745_mixer_read(addr, dev->sb);
|
||||
|
||||
if (addr & 1) {
|
||||
if ((mixer->index == 0x0e) || (mixer->index >= 0xf0))
|
||||
ret = mixer->regs[mixer->index];
|
||||
cmi8x38_log("CMI8x38: sb_mixer_read(1, %02X) = %02X\n", mixer->index, ret);
|
||||
} else {
|
||||
cmi8x38_log("CMI8x38: sb_mixer_read(0) = %02X\n", ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cmi8x38_sb_mixer_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
cmi8x38_t *dev = (cmi8x38_t *) priv;
|
||||
sb_ct1745_mixer_t *mixer = &dev->sb->mixer_sb16;
|
||||
|
||||
/* Our clone mixer has a few differences. */
|
||||
if (addr & 1) {
|
||||
cmi8x38_log("CMI8x38: sb_mixer_write(1, %02X, %02X)\n", mixer->index, val);
|
||||
|
||||
switch (mixer->index) {
|
||||
/* Reset interleaved stereo flag for SBPro mode. */
|
||||
case 0x00:
|
||||
mixer->regs[0x0e] = 0x00;
|
||||
break;
|
||||
|
||||
/* No dynamic IRQ and DMA assignment. */
|
||||
case 0x80: case 0x81:
|
||||
return;
|
||||
|
||||
/* Some extended registers beyond those accepted by the CT1745. */
|
||||
case 0xf0:
|
||||
if (dev->type == CMEDIA_CMI8338)
|
||||
val &= 0xfe;
|
||||
mixer->regs[mixer->index] = val;
|
||||
return;
|
||||
|
||||
case 0xf8 ... 0xff:
|
||||
if (dev->type == CMEDIA_CMI8338)
|
||||
mixer->regs[mixer->index] = val;
|
||||
/* fall-through */
|
||||
|
||||
case 0xf1 ... 0xf7:
|
||||
return;
|
||||
}
|
||||
|
||||
sb_ct1745_mixer_write(addr, val, dev->sb);
|
||||
|
||||
/* No [3F:47] controls. */
|
||||
mixer->input_gain_L = 0;
|
||||
mixer->input_gain_R = 0;
|
||||
mixer->output_gain_L = (double) 1.0;
|
||||
mixer->output_gain_R = (double) 1.0;
|
||||
mixer->bass_l = 8;
|
||||
mixer->bass_r = 8;
|
||||
mixer->treble_l = 8;
|
||||
mixer->treble_r = 8;
|
||||
|
||||
/* Check interleaved stereo flag for SBPro mode. */
|
||||
if ((mixer->index == 0x00) || (mixer->index == 0x0e))
|
||||
sb_dsp_set_stereo(&dev->sb->dsp, mixer->regs[0x0e] & 2);
|
||||
} else {
|
||||
cmi8x38_log("CMI8x38: sb_mixer_write(0, %02X)\n", val);
|
||||
sb_ct1745_mixer_write(addr, val, dev->sb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
cmi8x38_remap_sb(cmi8x38_t *dev)
|
||||
{
|
||||
@@ -143,21 +442,19 @@ cmi8x38_remap_sb(cmi8x38_t *dev)
|
||||
opl3_write, NULL, NULL, &dev->sb->opl);
|
||||
io_removehandler(dev->sb_base + 8, 0x0002, opl3_read, NULL, NULL,
|
||||
opl3_write, NULL, NULL, &dev->sb->opl);
|
||||
io_removehandler(dev->sb_base + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL,
|
||||
sb_ct1745_mixer_write, NULL, NULL, dev->sb);
|
||||
io_removehandler(dev->sb_base + 4, 0x0002, cmi8x38_sb_mixer_read, NULL, NULL,
|
||||
cmi8x38_sb_mixer_write, NULL, NULL, dev);
|
||||
|
||||
sb_dsp_setaddr(&dev->sb->dsp, 0);
|
||||
}
|
||||
|
||||
if (dev->io_regs[0x04] & 0x08) {
|
||||
dev->sb_base = 0x220;
|
||||
if (dev->type == CMEDIA_CMI8338)
|
||||
dev->sb_base += (dev->io_regs[0x17] & 0x80) >> 2;
|
||||
else
|
||||
dev->sb_base += (dev->io_regs[0x17] & 0x0c) << 3;
|
||||
} else {
|
||||
if (!(dev->io_regs[0x04] & 0x08))
|
||||
dev->sb_base = 0;
|
||||
}
|
||||
cmi8x38_log("CMI8x38: remap_sb(%04X)\n", dev->sb_base);
|
||||
|
||||
if (dev->sb_base) {
|
||||
@@ -165,8 +462,8 @@ cmi8x38_remap_sb(cmi8x38_t *dev)
|
||||
opl3_write, NULL, NULL, &dev->sb->opl);
|
||||
io_sethandler(dev->sb_base + 8, 0x0002, opl3_read, NULL, NULL,
|
||||
opl3_write, NULL, NULL, &dev->sb->opl);
|
||||
io_sethandler(dev->sb_base + 4, 0x0002, sb_ct1745_mixer_read, NULL, NULL,
|
||||
sb_ct1745_mixer_write, NULL, NULL, dev->sb);
|
||||
io_sethandler(dev->sb_base + 4, 0x0002, cmi8x38_sb_mixer_read, NULL, NULL,
|
||||
cmi8x38_sb_mixer_write, NULL, NULL, dev);
|
||||
|
||||
sb_dsp_setaddr(&dev->sb->dsp, dev->sb_base);
|
||||
}
|
||||
@@ -181,14 +478,11 @@ cmi8x38_remap_opl(cmi8x38_t *dev)
|
||||
opl3_write, NULL, NULL, &dev->sb->opl);
|
||||
}
|
||||
|
||||
if (dev->io_regs[0x1a] & 0x08) {
|
||||
if (dev->type == CMEDIA_CMI8338)
|
||||
dev->opl_base = 0x388;
|
||||
else
|
||||
dev->opl_base = opl_ports_cmi8738[dev->io_regs[0x17] & 0x03];
|
||||
} else {
|
||||
dev->opl_base = (dev->type == CMEDIA_CMI8338) ? 0x388 : opl_ports_cmi8738[dev->io_regs[0x17] & 0x03];
|
||||
io_trap_remap(dev->io_traps[TRAP_OPL], dev->io_regs[0x16] & 0x80, dev->opl_base, 4);
|
||||
if (!(dev->io_regs[0x1a] & 0x08))
|
||||
dev->opl_base = 0;
|
||||
}
|
||||
|
||||
cmi8x38_log("CMI8x38: remap_opl(%04X)\n", dev->opl_base);
|
||||
|
||||
if (dev->opl_base) {
|
||||
@@ -204,13 +498,13 @@ cmi8x38_remap_mpu(cmi8x38_t *dev)
|
||||
if (dev->mpu_base)
|
||||
mpu401_change_addr(dev->sb->mpu, 0);
|
||||
|
||||
if (dev->io_regs[0x04] & 0x04) {
|
||||
/* The CMI8338 datasheet's port range of [300:330] is
|
||||
inaccurate. Drivers expect [330:300] like CMI8738. */
|
||||
dev->mpu_base = 0x330 - ((dev->io_regs[0x17] & 0x60) >> 1);
|
||||
} else {
|
||||
io_trap_remap(dev->io_traps[TRAP_MPU], dev->io_regs[0x16] & 0x20, dev->mpu_base, 2);
|
||||
if (!(dev->io_regs[0x04] & 0x04))
|
||||
dev->mpu_base = 0;
|
||||
}
|
||||
|
||||
cmi8x38_log("CMI8x38: remap_mpu(%04X)\n", dev->mpu_base);
|
||||
|
||||
if (dev->mpu_base)
|
||||
@@ -219,9 +513,9 @@ cmi8x38_remap_mpu(cmi8x38_t *dev)
|
||||
|
||||
|
||||
static void
|
||||
cmi8x38_start_playback(cmi8x38_t *dev, uint8_t val)
|
||||
cmi8x38_start_playback(cmi8x38_t *dev)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t i, val = dev->io_regs[0x00];
|
||||
|
||||
i = !(val & 0x01);
|
||||
if (!dev->dma[0].playback_enabled && i)
|
||||
@@ -243,16 +537,8 @@ cmi8x38_read(uint16_t addr, void *priv)
|
||||
uint8_t ret;
|
||||
|
||||
switch (addr) {
|
||||
case 0x22:
|
||||
sb_ct1745_mixer_t *mixer = &dev->sb->mixer_sb16;
|
||||
if (mixer->index >= 0xf0)
|
||||
ret = dev->mixer_ext_regs[mixer->index & 0x0f];
|
||||
else
|
||||
ret = sb_ct1745_mixer_read(1, dev->sb);
|
||||
break;
|
||||
|
||||
case 0x23:
|
||||
ret = sb_ct1745_mixer_read(0, dev->sb);
|
||||
case 0x22: case 0x23:
|
||||
ret = cmi8x38_sb_mixer_read(addr ^ 1, dev);
|
||||
break;
|
||||
|
||||
case 0x40 ... 0x4f:
|
||||
@@ -327,7 +613,8 @@ cmi8x38_write(uint16_t addr, uint8_t val, void *priv)
|
||||
dev->dma[1].always_run = val & 0x02;
|
||||
|
||||
/* Start playback if requested. */
|
||||
cmi8x38_start_playback(dev, val);
|
||||
dev->io_regs[addr] = val;
|
||||
cmi8x38_start_playback(dev);
|
||||
break;
|
||||
|
||||
case 0x02:
|
||||
@@ -354,7 +641,7 @@ cmi8x38_write(uint16_t addr, uint8_t val, void *priv)
|
||||
|
||||
/* Start playback along with DMA channels. */
|
||||
if (val & 0x03)
|
||||
cmi8x38_start_playback(dev, dev->io_regs[0x00]);
|
||||
cmi8x38_start_playback(dev);
|
||||
break;
|
||||
|
||||
case 0x04:
|
||||
@@ -425,8 +712,14 @@ cmi8x38_write(uint16_t addr, uint8_t val, void *priv)
|
||||
break;
|
||||
|
||||
case 0x16:
|
||||
if (dev->type == CMEDIA_CMI8338)
|
||||
if (dev->type == CMEDIA_CMI8338) {
|
||||
val &= 0xa0;
|
||||
|
||||
/* Enable or disable I/O traps. */
|
||||
dev->io_regs[addr] = val;
|
||||
cmi8x38_remap_opl(dev);
|
||||
cmi8x38_remap_mpu(dev);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x17:
|
||||
@@ -438,6 +731,10 @@ cmi8x38_write(uint16_t addr, uint8_t val, void *priv)
|
||||
pci_set_irq(dev->slot, PCI_INTA);
|
||||
else if ((dev->io_regs[0x17] & 0x10) && !(val & 0x10))
|
||||
pci_clear_irq(dev->slot, PCI_INTA);
|
||||
|
||||
/* Enable or disable I/O traps. */
|
||||
io_trap_remap(dev->io_traps[TRAP_DMA], val & 0x02, 0x0000, 16);
|
||||
io_trap_remap(dev->io_traps[TRAP_PIC], val & 0x01, 0x0020, 2);
|
||||
}
|
||||
|
||||
/* Remap the legacy devices. */
|
||||
@@ -484,43 +781,13 @@ cmi8x38_write(uint16_t addr, uint8_t val, void *priv)
|
||||
val &= 0xf7;
|
||||
else
|
||||
val &= 0x07;
|
||||
|
||||
/* Enable or disable SBPro channel swapping. */
|
||||
dev->sb->dsp.sbleftright_default = !!(val & 0x02);
|
||||
break;
|
||||
|
||||
case 0x22:
|
||||
sb_ct1745_mixer_t *mixer = &dev->sb->mixer_sb16;
|
||||
switch (mixer->index) {
|
||||
case 0xf0:
|
||||
if (dev->type == CMEDIA_CMI8338)
|
||||
val &= 0xfe;
|
||||
dev->mixer_ext_regs[dev->sb->mixer_sb16.index & 0x0f] = val;
|
||||
break;
|
||||
|
||||
case 0xf8 ... 0xff:
|
||||
if (dev->type == CMEDIA_CMI8338)
|
||||
dev->mixer_ext_regs[dev->sb->mixer_sb16.index & 0x0f] = val;
|
||||
/* fall-through */
|
||||
|
||||
case 0xf1 ... 0xf7:
|
||||
break;
|
||||
|
||||
default:
|
||||
sb_ct1745_mixer_write(1, val, dev->sb);
|
||||
|
||||
/* Our clone mixer lacks the [3F:47] controls. */
|
||||
mixer->input_gain_L = 0;
|
||||
mixer->input_gain_R = 0;
|
||||
mixer->output_gain_L = (double) 1.0;
|
||||
mixer->output_gain_R = (double) 1.0;
|
||||
mixer->bass_l = 8;
|
||||
mixer->bass_r = 8;
|
||||
mixer->treble_l = 8;
|
||||
mixer->treble_r = 8;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
||||
case 0x23:
|
||||
sb_ct1745_mixer_write(0, val, dev->sb);
|
||||
case 0x22: case 0x23:
|
||||
cmi8x38_sb_mixer_write(addr ^ 1, val, dev);
|
||||
return;
|
||||
|
||||
case 0x24:
|
||||
@@ -533,6 +800,16 @@ cmi8x38_write(uint16_t addr, uint8_t val, void *priv)
|
||||
val &= 0x03;
|
||||
else
|
||||
val &= 0x27;
|
||||
|
||||
if (val & 0x01) {
|
||||
/* Latch last DMA channels that had address/count registers written to.
|
||||
Nobody knows how this "autodetection" works, but the CMI8338 TSR
|
||||
disables it before and reenables it after copying the TDMA base/addr
|
||||
to the 8237 registers corresponding to the 8-bit SB DMA channel. */
|
||||
dev->sb->dsp.sb_8_dmanum = dev->tdma_last_8;
|
||||
if (!(dev->io_regs[0x21] & 0x01))
|
||||
dev->sb->dsp.sb_16_dmanum = dev->tdma_last_16;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x40 ... 0x4f:
|
||||
@@ -751,9 +1028,11 @@ cmi8x38_poll(void *priv)
|
||||
int16_t *out_l, *out_r, *out_ol, *out_or; /* o = opposite */
|
||||
|
||||
/* Schedule next run if playback is enabled. */
|
||||
#if 0 /* temporary */
|
||||
if (dev->io_regs[0x00] & (1 << dma->id))
|
||||
dma->playback_enabled = 0;
|
||||
else
|
||||
#endif
|
||||
timer_advance_u64(&dma->poll_timer, dma->timer_latch);
|
||||
|
||||
/* Update audio buffer. */
|
||||
@@ -1000,6 +1279,10 @@ cmi8x38_reset(void *priv)
|
||||
memset(dev->dma[i].fifo, 0, sizeof(dev->dma[i].fifo));
|
||||
}
|
||||
|
||||
/* Reset legacy DMA channel. */
|
||||
dev->tdma_last_8 = dev->tdma_last_16 = dev->sb->dsp.sb_8_dmanum = dev->sb->dsp.sb_16_dmanum = -1;
|
||||
dev->tdma_mask = 0;
|
||||
|
||||
/* Reset Sound Blaster 16 mixer. */
|
||||
sb_ct1745_mixer_reset(dev->sb);
|
||||
}
|
||||
@@ -1023,8 +1306,15 @@ cmi8x38_init(const device_t *info)
|
||||
dev->sb->opl_enabled = 1; /* let snd_sb.c handle the OPL3 */
|
||||
dev->sb->mixer_sb16.output_filter = 0; /* no output filtering */
|
||||
|
||||
/* Initialize MPU-401 interrupt handler. */
|
||||
/* Initialize legacy interrupt and DMA handlers. */
|
||||
mpu401_irq_attach(dev->sb->mpu, cmi8x38_mpu_irq_update, cmi8x38_mpu_irq_pending, dev);
|
||||
sb_dsp_irq_attach(&dev->sb->dsp, cmi8x38_sb_irq_update, dev);
|
||||
sb_dsp_dma_attach(&dev->sb->dsp, cmi8x38_sb_dma_readb, cmi8x38_sb_dma_readw, cmi8x38_sb_dma_writeb, cmi8x38_sb_dma_writew, dev);
|
||||
dev->sb->dsp.sb_type = SBPRO;
|
||||
io_sethandler(0x00, 8, NULL, NULL, NULL, cmi8x38_dma_write, NULL, NULL, dev);
|
||||
io_sethandler(0xc0, 16, NULL, NULL, NULL, cmi8x38_dma_write, NULL, NULL, dev);
|
||||
io_sethandler(0x08, 8, NULL, NULL, NULL, cmi8x38_dma_mask_write, NULL, NULL, dev);
|
||||
io_sethandler(0xd0, 16, NULL, NULL, NULL, cmi8x38_dma_mask_write, NULL, NULL, dev);
|
||||
|
||||
/* Initialize DMA channels. */
|
||||
for (int i = 0; i < (sizeof(dev->dma) / sizeof(dev->dma[0])); i++) {
|
||||
@@ -1044,6 +1334,14 @@ cmi8x38_init(const device_t *info)
|
||||
/* Initialize game port. */
|
||||
dev->gameport = gameport_add(&gameport_pnp_device);
|
||||
|
||||
/* Initialize I/O traps. */
|
||||
if (dev->type == CMEDIA_CMI8338) {
|
||||
dev->io_traps[TRAP_DMA] = io_trap_add(cmi8338_io_trap, dev);
|
||||
dev->io_traps[TRAP_PIC] = io_trap_add(cmi8338_io_trap, dev);
|
||||
dev->io_traps[TRAP_OPL] = io_trap_add(cmi8338_io_trap, dev);
|
||||
dev->io_traps[TRAP_MPU] = io_trap_add(cmi8338_io_trap, dev);
|
||||
}
|
||||
|
||||
/* Add PCI card. */
|
||||
dev->slot = pci_add_card((info->local & (1 << 13)) ? PCI_ADD_SOUND : PCI_ADD_NORMAL, cmi8x38_pci_read, cmi8x38_pci_write, dev);
|
||||
|
||||
@@ -1061,6 +1359,9 @@ cmi8x38_close(void *priv)
|
||||
|
||||
cmi8x38_log("CMI8x38: close()\n");
|
||||
|
||||
for (int i = 0; i < TRAP_MAX; i++)
|
||||
io_trap_remove(dev->io_traps[i]);
|
||||
|
||||
free(dev);
|
||||
}
|
||||
|
||||
|
@@ -169,6 +169,16 @@ recalc_sb16_filter(int c, int playback_freq)
|
||||
low_fir_sb16_coef[c][n] /= gain;
|
||||
}
|
||||
|
||||
static void
|
||||
sb_irq_update_pic(void *priv, int set)
|
||||
{
|
||||
sb_dsp_t *dsp = (sb_dsp_t *) priv;
|
||||
if (set)
|
||||
picint(1 << dsp->sb_irqnum);
|
||||
else
|
||||
picintc(1 << dsp->sb_irqnum);
|
||||
}
|
||||
|
||||
void
|
||||
sb_update_mask(sb_dsp_t *dsp, int irqm8, int irqm16, int irqm401)
|
||||
{
|
||||
@@ -185,7 +195,7 @@ sb_update_mask(sb_dsp_t *dsp, int irqm8, int irqm16, int irqm401)
|
||||
dsp->sb_irqm401 = irqm401;
|
||||
|
||||
if (clear)
|
||||
picintc(1 << dsp->sb_irqnum);
|
||||
dsp->irq_update(dsp->irq_priv, 0);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -210,9 +220,9 @@ sb_update_status(sb_dsp_t *dsp, int bit, int set)
|
||||
}
|
||||
|
||||
if (set && !masked)
|
||||
picint(1 << dsp->sb_irqnum);
|
||||
dsp->irq_update(dsp->irq_priv, 1);
|
||||
else if (!set)
|
||||
picintc(1 << dsp->sb_irqnum);
|
||||
dsp->irq_update(dsp->irq_priv, 0);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -281,7 +291,7 @@ sb_dsp_reset(sb_dsp_t *dsp)
|
||||
dsp->record_pos_read = 0;
|
||||
dsp->record_pos_write = SB_DSP_REC_SAFEFTY_MARGIN;
|
||||
|
||||
picintc(1 << dsp->sb_irqnum);
|
||||
dsp->irq_update(dsp->irq_priv, 0);
|
||||
|
||||
dsp->asp_data_len = 0;
|
||||
}
|
||||
@@ -350,7 +360,7 @@ sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len)
|
||||
dsp->sb_8_output = 1;
|
||||
if (!timer_is_enabled(&dsp->output_timer))
|
||||
timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho);
|
||||
dsp->sbleftright = 0;
|
||||
dsp->sbleftright = dsp->sbleftright_default;
|
||||
dsp->sbdacpos = 0;
|
||||
} else {
|
||||
dsp->sb_16_length = len;
|
||||
@@ -397,29 +407,31 @@ sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len)
|
||||
}
|
||||
|
||||
int
|
||||
sb_8_read_dma(sb_dsp_t *dsp)
|
||||
sb_8_read_dma(void *priv)
|
||||
{
|
||||
sb_dsp_t *dsp = (sb_dsp_t *) priv;
|
||||
return dma_channel_read(dsp->sb_8_dmanum);
|
||||
}
|
||||
|
||||
void
|
||||
sb_8_write_dma(sb_dsp_t *dsp, uint8_t val)
|
||||
int
|
||||
sb_8_write_dma(void *priv, uint8_t val)
|
||||
{
|
||||
dma_channel_write(dsp->sb_8_dmanum, val);
|
||||
sb_dsp_t *dsp = (sb_dsp_t *) priv;
|
||||
return dma_channel_write(dsp->sb_8_dmanum, val) == DMA_NODATA;
|
||||
}
|
||||
|
||||
int
|
||||
sb_16_read_dma(sb_dsp_t *dsp)
|
||||
sb_16_read_dma(void *priv)
|
||||
{
|
||||
sb_dsp_t *dsp = (sb_dsp_t *) priv;
|
||||
return dma_channel_read(dsp->sb_16_dmanum);
|
||||
}
|
||||
|
||||
int
|
||||
sb_16_write_dma(sb_dsp_t *dsp, uint16_t val)
|
||||
sb_16_write_dma(void *priv, uint16_t val)
|
||||
{
|
||||
int ret = dma_channel_write(dsp->sb_16_dmanum, val);
|
||||
|
||||
return (ret == DMA_NODATA);
|
||||
sb_dsp_t *dsp = (sb_dsp_t *) priv;
|
||||
return dma_channel_write(dsp->sb_16_dmanum, val) == DMA_NODATA;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -469,12 +481,12 @@ sb_exec_command(sb_dsp_t *dsp)
|
||||
sb_start_dma(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
break;
|
||||
case 0x17: /* 2-bit ADPCM output with reference */
|
||||
dsp->sbref = sb_8_read_dma(dsp);
|
||||
dsp->sbref = dsp->dma_readb(dsp->dma_priv);
|
||||
dsp->sbstep = 0;
|
||||
/* Fall through */
|
||||
case 0x16: /* 2-bit ADPCM output */
|
||||
sb_start_dma(dsp, 1, 0, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv);
|
||||
dsp->sb_8_length--;
|
||||
if (dsp->sb_command == 0x17)
|
||||
dsp->sb_8_length--;
|
||||
@@ -486,7 +498,7 @@ sb_exec_command(sb_dsp_t *dsp)
|
||||
case 0x1F: /* 2-bit ADPCM autoinit output */
|
||||
if (dsp->sb_type >= SB15) {
|
||||
sb_start_dma(dsp, 1, 1, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv);
|
||||
dsp->sb_8_length--;
|
||||
}
|
||||
break;
|
||||
@@ -581,23 +593,23 @@ sb_exec_command(sb_dsp_t *dsp)
|
||||
dsp->sb_8_autolen = dsp->sb_data[0] + (dsp->sb_data[1] << 8);
|
||||
break;
|
||||
case 0x75: /* 4-bit ADPCM output with reference */
|
||||
dsp->sbref = sb_8_read_dma(dsp);
|
||||
dsp->sbref = dsp->dma_readb(dsp->dma_priv);
|
||||
dsp->sbstep = 0;
|
||||
/* Fall through */
|
||||
case 0x74: /* 4-bit ADPCM output */
|
||||
sb_start_dma(dsp, 1, 0, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv);
|
||||
dsp->sb_8_length--;
|
||||
if (dsp->sb_command == 0x75)
|
||||
dsp->sb_8_length--;
|
||||
break;
|
||||
case 0x77: /* 2.6-bit ADPCM output with reference */
|
||||
dsp->sbref = sb_8_read_dma(dsp);
|
||||
dsp->sbref = dsp->dma_readb(dsp->dma_priv);
|
||||
dsp->sbstep = 0;
|
||||
/* Fall through */
|
||||
case 0x76: /* 2.6-bit ADPCM output */
|
||||
sb_start_dma(dsp, 1, 0, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv);
|
||||
dsp->sb_8_length--;
|
||||
if (dsp->sb_command == 0x77)
|
||||
dsp->sb_8_length--;
|
||||
@@ -605,14 +617,14 @@ sb_exec_command(sb_dsp_t *dsp)
|
||||
case 0x7D: /* 4-bit ADPCM autoinit output */
|
||||
if (dsp->sb_type >= SB15) {
|
||||
sb_start_dma(dsp, 1, 1, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv);
|
||||
dsp->sb_8_length--;
|
||||
}
|
||||
break;
|
||||
case 0x7F: /* 2.6-bit ADPCM autoinit output */
|
||||
if (dsp->sb_type >= SB15) {
|
||||
sb_start_dma(dsp, 1, 1, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8));
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv);
|
||||
dsp->sb_8_length--;
|
||||
}
|
||||
break;
|
||||
@@ -757,7 +769,7 @@ sb_exec_command(sb_dsp_t *dsp)
|
||||
}
|
||||
dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][8];
|
||||
dsp->sbe2count++;
|
||||
sb_8_write_dma(dsp, dsp->sbe2);
|
||||
dsp->dma_writeb(dsp->dma_priv, dsp->sbe2);
|
||||
break;
|
||||
case 0xE3: /* DSP copyright */
|
||||
if (dsp->sb_type >= SB16) {
|
||||
@@ -1016,7 +1028,7 @@ sb_read(uint16_t a, void *priv)
|
||||
}
|
||||
break;
|
||||
case 0xE: /* Read data ready */
|
||||
picintc(1 << dsp->sb_irqnum);
|
||||
dsp->irq_update(dsp->irq_priv, 0);
|
||||
dsp->sb_irq8 = dsp->sb_irq16 = 0;
|
||||
/* Only bit 7 is defined but aztech diagnostics fail if the others are set. Keep the original behavior to not interfere with what's already working. */
|
||||
if (IS_AZTECH(dsp)) {
|
||||
@@ -1030,7 +1042,7 @@ sb_read(uint16_t a, void *priv)
|
||||
case 0xF: /* 16-bit ack */
|
||||
dsp->sb_irq16 = 0;
|
||||
if (!dsp->sb_irq8)
|
||||
picintc(1 << dsp->sb_irqnum);
|
||||
dsp->irq_update(dsp->irq_priv, 0);
|
||||
sb_dsp_log("SB 16-bit ACK read 0xFF\n");
|
||||
ret = 0xff;
|
||||
break;
|
||||
@@ -1108,6 +1120,16 @@ sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent)
|
||||
dsp->sb_16_dmanum = 5;
|
||||
dsp->mpu = NULL;
|
||||
|
||||
dsp->sbleftright_default = 0;
|
||||
|
||||
dsp->irq_update = sb_irq_update_pic;
|
||||
dsp->irq_priv = dsp;
|
||||
dsp->dma_readb = sb_8_read_dma;
|
||||
dsp->dma_readw = sb_16_read_dma;
|
||||
dsp->dma_writeb = sb_8_write_dma;
|
||||
dsp->dma_writew = sb_16_write_dma;
|
||||
dsp->dma_priv = dsp;
|
||||
|
||||
sb_doreset(dsp);
|
||||
|
||||
timer_add(&dsp->output_timer, pollsb, dsp, 0);
|
||||
@@ -1149,6 +1171,28 @@ sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo)
|
||||
dsp->stereo = stereo;
|
||||
}
|
||||
|
||||
void
|
||||
sb_dsp_irq_attach(sb_dsp_t *dsp, void (*irq_update)(void *priv, int set), void *priv)
|
||||
{
|
||||
dsp->irq_update = irq_update;
|
||||
dsp->irq_priv = priv;
|
||||
}
|
||||
|
||||
void
|
||||
sb_dsp_dma_attach(sb_dsp_t *dsp,
|
||||
int (*dma_readb)(void *priv),
|
||||
int (*dma_readw)(void *priv),
|
||||
int (*dma_writeb)(void *priv, uint8_t val),
|
||||
int (*dma_writew)(void *priv, uint16_t val),
|
||||
void *priv)
|
||||
{
|
||||
dsp->dma_readb = dma_readb;
|
||||
dsp->dma_readw = dma_readw;
|
||||
dsp->dma_writeb = dma_writeb;
|
||||
dsp->dma_writew = dma_writew;
|
||||
dsp->dma_priv = priv;
|
||||
}
|
||||
|
||||
void
|
||||
pollsb(void *p)
|
||||
{
|
||||
@@ -1162,7 +1206,7 @@ pollsb(void *p)
|
||||
|
||||
switch (dsp->sb_8_format) {
|
||||
case 0x00: /* Mono unsigned */
|
||||
data[0] = sb_8_read_dma(dsp);
|
||||
data[0] = dsp->dma_readb(dsp->dma_priv);
|
||||
/* Needed to prevent clicking in Worms, which programs the DSP to
|
||||
auto-init DMA but programs the DMA controller to single cycle */
|
||||
if (data[0] == DMA_NODATA)
|
||||
@@ -1181,7 +1225,7 @@ pollsb(void *p)
|
||||
dsp->sb_8_length--;
|
||||
break;
|
||||
case 0x10: /* Mono signed */
|
||||
data[0] = sb_8_read_dma(dsp);
|
||||
data[0] = dsp->dma_readb(dsp->dma_priv);
|
||||
if (data[0] == DMA_NODATA)
|
||||
break;
|
||||
dsp->sbdat = data[0] << 8;
|
||||
@@ -1198,8 +1242,8 @@ pollsb(void *p)
|
||||
dsp->sb_8_length--;
|
||||
break;
|
||||
case 0x20: /* Stereo unsigned */
|
||||
data[0] = sb_8_read_dma(dsp);
|
||||
data[1] = sb_8_read_dma(dsp);
|
||||
data[0] = dsp->dma_readb(dsp->dma_priv);
|
||||
data[1] = dsp->dma_readb(dsp->dma_priv);
|
||||
if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA))
|
||||
break;
|
||||
dsp->sbdatl = (data[0] ^ 0x80) << 8;
|
||||
@@ -1207,8 +1251,8 @@ pollsb(void *p)
|
||||
dsp->sb_8_length -= 2;
|
||||
break;
|
||||
case 0x30: /* Stereo signed */
|
||||
data[0] = sb_8_read_dma(dsp);
|
||||
data[1] = sb_8_read_dma(dsp);
|
||||
data[0] = dsp->dma_readb(dsp->dma_priv);
|
||||
data[1] = dsp->dma_readb(dsp->dma_priv);
|
||||
if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA))
|
||||
break;
|
||||
dsp->sbdatl = data[0] << 8;
|
||||
@@ -1241,7 +1285,7 @@ pollsb(void *p)
|
||||
|
||||
if (dsp->sbdacpos >= 2) {
|
||||
dsp->sbdacpos = 0;
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv);
|
||||
dsp->sb_8_length--;
|
||||
}
|
||||
|
||||
@@ -1284,7 +1328,7 @@ pollsb(void *p)
|
||||
dsp->sbdacpos++;
|
||||
if (dsp->sbdacpos >= 3) {
|
||||
dsp->sbdacpos = 0;
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv);
|
||||
dsp->sb_8_length--;
|
||||
}
|
||||
|
||||
@@ -1321,7 +1365,7 @@ pollsb(void *p)
|
||||
dsp->sbdacpos++;
|
||||
if (dsp->sbdacpos >= 4) {
|
||||
dsp->sbdacpos = 0;
|
||||
dsp->sbdat2 = sb_8_read_dma(dsp);
|
||||
dsp->sbdat2 = dsp->dma_readb(dsp->dma_priv);
|
||||
}
|
||||
|
||||
if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) {
|
||||
@@ -1352,22 +1396,22 @@ pollsb(void *p)
|
||||
|
||||
switch (dsp->sb_16_format) {
|
||||
case 0x00: /* Mono unsigned */
|
||||
data[0] = sb_16_read_dma(dsp);
|
||||
data[0] = dsp->dma_readw(dsp->dma_priv);
|
||||
if (data[0] == DMA_NODATA)
|
||||
break;
|
||||
dsp->sbdatl = dsp->sbdatr = data[0] ^ 0x8000;
|
||||
dsp->sb_16_length--;
|
||||
break;
|
||||
case 0x10: /* Mono signed */
|
||||
data[0] = sb_16_read_dma(dsp);
|
||||
data[0] = dsp->dma_readw(dsp->dma_priv);
|
||||
if (data[0] == DMA_NODATA)
|
||||
break;
|
||||
dsp->sbdatl = dsp->sbdatr = data[0];
|
||||
dsp->sb_16_length--;
|
||||
break;
|
||||
case 0x20: /* Stereo unsigned */
|
||||
data[0] = sb_16_read_dma(dsp);
|
||||
data[1] = sb_16_read_dma(dsp);
|
||||
data[0] = dsp->dma_readw(dsp->dma_priv);
|
||||
data[1] = dsp->dma_readw(dsp->dma_priv);
|
||||
if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA))
|
||||
break;
|
||||
dsp->sbdatl = data[0] ^ 0x8000;
|
||||
@@ -1375,8 +1419,8 @@ pollsb(void *p)
|
||||
dsp->sb_16_length -= 2;
|
||||
break;
|
||||
case 0x30: /* Stereo signed */
|
||||
data[0] = sb_16_read_dma(dsp);
|
||||
data[1] = sb_16_read_dma(dsp);
|
||||
data[0] = dsp->dma_readw(dsp->dma_priv);
|
||||
data[1] = dsp->dma_readw(dsp->dma_priv);
|
||||
if ((data[0] == DMA_NODATA) || (data[1] == DMA_NODATA))
|
||||
break;
|
||||
dsp->sbdatl = data[0];
|
||||
@@ -1418,27 +1462,27 @@ sb_poll_i(void *p)
|
||||
if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && !dsp->sb_8_output) {
|
||||
switch (dsp->sb_8_format) {
|
||||
case 0x00: /* Mono unsigned As the manual says, only the left channel is recorded */
|
||||
sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read] >> 8) ^ 0x80);
|
||||
dsp->dma_writeb(dsp->dma_priv, (dsp->record_buffer[dsp->record_pos_read] >> 8) ^ 0x80);
|
||||
dsp->sb_8_length--;
|
||||
dsp->record_pos_read += 2;
|
||||
dsp->record_pos_read &= 0xFFFF;
|
||||
break;
|
||||
case 0x10: /* Mono signed As the manual says, only the left channel is recorded */
|
||||
sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read] >> 8));
|
||||
dsp->dma_writeb(dsp->dma_priv, (dsp->record_buffer[dsp->record_pos_read] >> 8));
|
||||
dsp->sb_8_length--;
|
||||
dsp->record_pos_read += 2;
|
||||
dsp->record_pos_read &= 0xFFFF;
|
||||
break;
|
||||
case 0x20: /* Stereo unsigned */
|
||||
sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read] >> 8) ^ 0x80);
|
||||
sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read + 1] >> 8) ^ 0x80);
|
||||
dsp->dma_writeb(dsp->dma_priv, (dsp->record_buffer[dsp->record_pos_read] >> 8) ^ 0x80);
|
||||
dsp->dma_writeb(dsp->dma_priv, (dsp->record_buffer[dsp->record_pos_read + 1] >> 8) ^ 0x80);
|
||||
dsp->sb_8_length -= 2;
|
||||
dsp->record_pos_read += 2;
|
||||
dsp->record_pos_read &= 0xFFFF;
|
||||
break;
|
||||
case 0x30: /* Stereo signed */
|
||||
sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read] >> 8));
|
||||
sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read + 1] >> 8));
|
||||
dsp->dma_writeb(dsp->dma_priv, (dsp->record_buffer[dsp->record_pos_read] >> 8));
|
||||
dsp->dma_writeb(dsp->dma_priv, (dsp->record_buffer[dsp->record_pos_read + 1] >> 8));
|
||||
dsp->sb_8_length -= 2;
|
||||
dsp->record_pos_read += 2;
|
||||
dsp->record_pos_read &= 0xFFFF;
|
||||
@@ -1459,31 +1503,31 @@ sb_poll_i(void *p)
|
||||
if (dsp->sb_16_enable && !dsp->sb_16_pause && (dsp->sb_pausetime < 0LL) && !dsp->sb_16_output) {
|
||||
switch (dsp->sb_16_format) {
|
||||
case 0x00: /* Unsigned mono. As the manual says, only the left channel is recorded */
|
||||
if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read] ^ 0x8000))
|
||||
if (dsp->dma_writew(dsp->dma_priv, dsp->record_buffer[dsp->record_pos_read] ^ 0x8000))
|
||||
return;
|
||||
dsp->sb_16_length--;
|
||||
dsp->record_pos_read += 2;
|
||||
dsp->record_pos_read &= 0xFFFF;
|
||||
break;
|
||||
case 0x10: /* Signed mono. As the manual says, only the left channel is recorded */
|
||||
if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read]))
|
||||
if (dsp->dma_writew(dsp->dma_priv, dsp->record_buffer[dsp->record_pos_read]))
|
||||
return;
|
||||
dsp->sb_16_length--;
|
||||
dsp->record_pos_read += 2;
|
||||
dsp->record_pos_read &= 0xFFFF;
|
||||
break;
|
||||
case 0x20: /* Unsigned stereo */
|
||||
if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read] ^ 0x8000))
|
||||
if (dsp->dma_writew(dsp->dma_priv, dsp->record_buffer[dsp->record_pos_read] ^ 0x8000))
|
||||
return;
|
||||
sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read + 1] ^ 0x8000);
|
||||
dsp->dma_writew(dsp->dma_priv, dsp->record_buffer[dsp->record_pos_read + 1] ^ 0x8000);
|
||||
dsp->sb_16_length -= 2;
|
||||
dsp->record_pos_read += 2;
|
||||
dsp->record_pos_read &= 0xFFFF;
|
||||
break;
|
||||
case 0x30: /* Signed stereo */
|
||||
if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read]))
|
||||
if (dsp->dma_writew(dsp->dma_priv, dsp->record_buffer[dsp->record_pos_read]))
|
||||
return;
|
||||
sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read + 1]);
|
||||
dsp->dma_writew(dsp->dma_priv, dsp->record_buffer[dsp->record_pos_read + 1]);
|
||||
dsp->sb_16_length -= 2;
|
||||
dsp->record_pos_read += 2;
|
||||
dsp->record_pos_read &= 0xFFFF;
|
||||
|
Reference in New Issue
Block a user