More Pro Audio Spectrum 16 work, closes #4313.

This commit is contained in:
OBattler
2024-04-04 03:09:35 +02:00
parent fcbbae181f
commit f93692a045
5 changed files with 322 additions and 99 deletions

View File

@@ -154,10 +154,14 @@ typedef struct pas16_t {
uint16_t base;
uint16_t new_base;
uint16_t sb_compat_base;
uint16_t mpu401_base;
uint16_t dma8_dat;
uint16_t ticks;
uint16_t pcm_dat_l;
uint16_t pcm_dat_r;
int16_t pcm_buffer[2][SOUNDBUFLEN * 2];
int32_t pcm_buffer[2][SOUNDBUFLEN * 2];
int pos;
int midi_r;
@@ -371,7 +375,11 @@ pas16_in(uint16_t port, void *priv)
break;
case 0xec03:
ret = pas16->type ? 0x0c : 0x04;
#ifdef NEWER_PAS16
ret = pas16->type ? 0x0c : 0x06;
#else
ret = pas16->type ? 0x0f : 0x06;
#endif
break;
case 0xf000:
@@ -390,7 +398,13 @@ pas16_in(uint16_t port, void *priv)
break;
case 0xf400:
ret = pas16->compat;
ret = (pas16->compat & 0xf3);
if (pas16->dsp.sb_irqm8 || pas16->dsp.sb_irqm16 || pas16->dsp.sb_irqm401)
ret |= 0x04;
if (pas16->mpu->mode == M_UART)
ret |= 0x08;
break;
case 0xf401:
ret = pas16->compat_base;
@@ -402,11 +416,13 @@ pas16_in(uint16_t port, void *priv)
case 0xfc00: /* Board model */
/* PAS16 or PASPlus */
ret = pas16->type ? 0x04 : 0x01;
ret = pas16->type ? 0x0c : 0x01;
break;
case 0xfc03: /* Master mode read */
/* AT bus, XT/AT timing */
ret = pas16->type ? (0x20 | 0x10 | 0x01) : (0x10 | 0x01);
ret = 0x11;
if (pas16->type)
ret |= 0x20;
break;
default:
@@ -458,7 +474,6 @@ pas16_reset_pcm(void *priv)
pas16->pcm_ctrl = 0x00;
pas16->stereo_lr = 0;
pas16->dma8_ff = 0;
pas16->irq_stat &= 0xd7;
@@ -490,6 +505,7 @@ pas16_reset_regs(void *priv)
pitf_ctr_set_gate(pit, 1, 0);
pas16_reset_pcm(pas16);
pas16->dma8_ff = 0;
pas16->irq_ena = 0x00;
pas16->irq_stat = 0x00;
@@ -522,6 +538,11 @@ pas16_reset(void *priv)
pas16_io_handler(pas16, 1);
pas16->new_base = 0x0388;
pas16->sb_compat_base = 0x0220;
pas16->compat = 0x02;
pas16->compat_base = 0x02;
sb_dsp_setaddr(&pas16->dsp, pas16->sb_compat_base);
}
static void
@@ -546,25 +567,25 @@ pas16_out(uint16_t port, uint8_t val, void *priv)
break;
case 0x0801:
pas16->irq_stat &= ~val;
if (!(pas16->irq_stat & 0x1f))
picintc(1 << pas16->irq);
break;
case 0x0802:
pas16_update(pas16);
pitf_ctr_set_gate(pas16->pit, 1, !!(val & 0x80));
pitf_ctr_set_gate(pas16->pit, 0, !!(val & 0x40));
pas16->stereo_lr = 0;
pas16->dma8_ff = 0;
if ((val & 0x20) && !(pas16->audiofilt & 0x20)) {
pas16_log("Reset.\n");
val = 0x20;
pas16_reset_regs(pas16);
}
pas16_update(pas16);
pitf_ctr_set_gate(pas16->pit, 0, 1);
pitf_ctr_set_gate(pas16->pit, 1, 1);
// pas16->pit->counters[0].gate = !!(val & 0x40);
// pas16->pit->counters[0].enabled = !!(val & 0x40);
// pas16->pit->counters[1].gate = !!(val & 0x80);
// pas16->pit->counters[1].enabled = !!(val & 0x80);
pas16->stereo_lr = 0;
pas16->irq_stat &= 0xdf;
pas16->dma8_ff = 0;
pas16->audiofilt = val;
if (val & 0x1f) {
pas16->filter = 1;
switch (val & 0x1f) {
@@ -595,6 +616,10 @@ pas16_out(uint16_t port, uint8_t val, void *priv)
break;
case 0x0803:
pas16->irq_ena = val & 0x1f;
pas16->irq_stat &= ((val & 0x1f) | 0xe0);
if (!(pas16->irq_stat & 0x1f))
picintc(1 << pas16->irq);
break;
case 0x0c00:
@@ -607,7 +632,7 @@ pas16_out(uint16_t port, uint8_t val, void *priv)
if ((val & PAS16_PCM_ENA) && !(pas16->pcm_ctrl & PAS16_PCM_ENA)) {
/* Guess */
pas16->stereo_lr = 0;
pas16->irq_stat &= 0xdf;
pas16->irq_stat &= 0xd7;
/* Needed for 8-bit DMA to work correctly on a 16-bit DMA channel. */
pas16->dma8_ff = 0;
}
@@ -713,10 +738,10 @@ pas16_out(uint16_t port, uint8_t val, void *priv)
break;
case 0xf400:
pas16->compat = val;
pas16->compat = val & 0xf3;
pas16_log("PCM compression is now %sabled\n", (val & 0x10) ? "en" : "dis");
if (pas16->compat & 0x02)
sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200);
sb_dsp_setaddr(&pas16->dsp, pas16->sb_compat_base);
else
sb_dsp_setaddr(&pas16->dsp, 0);
if (pas16->compat & 0x01)
@@ -726,14 +751,17 @@ pas16_out(uint16_t port, uint8_t val, void *priv)
break;
case 0xf401:
pas16->compat_base = val;
pas16->sb_compat_base = ((pas16->compat_base & 0xf) << 4) | 0x200;
pas16_log("SB Compatibility base: %04X\n", pas16->sb_compat_base);
if (pas16->compat & 0x02)
sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200);
sb_dsp_setaddr(&pas16->dsp, pas16->sb_compat_base);
if (pas16->compat & 0x01)
mpu401_change_addr(pas16->mpu, ((pas16->compat_base & 0xf0) | 0x300));
break;
case 0xf802:
pas16->sb_irqdma = val;
mpu401_setirq(pas16->mpu, pas16_sb_irqs[val & 7]);
sb_dsp_setirq(&pas16->dsp, pas16_sb_irqs[(val >> 3) & 7]);
sb_dsp_setdma8(&pas16->dsp, pas16_sb_dmas[(val >> 6) & 3]);
pas16_log("pas16_out : set SB IRQ %i DMA %i.\n", pas16_sb_irqs[(val >> 3) & 7],
@@ -774,18 +802,33 @@ pas16_out(uint16_t port, uint8_t val, void *priv)
alongside the previous sample;
- A 16-bit sample always takes two ctr_clock() ticks.
*/
static uint16_t
pas16_dma_channel_read(pas16_t *pas16, int channel)
{
int status;
uint16_t ret;
if (pas16->pcm_ctrl & PAS16_PCM_DMA_ENA) {
if (pas16->dma >= 5) {
dma_channel_advance(pas16->dma);
status = dma_channel_read_only(pas16->dma);
} else
status = dma_channel_read(pas16->dma);
ret = (status == DMA_NODATA) ? 0x0000 : (status & 0xffff);
} else
ret = 0x0000;
return ret;
}
static uint16_t
pas16_dma_readb(pas16_t *pas16, uint8_t timer1_ticks)
{
uint16_t ret;
if (pas16->pcm_ctrl & PAS16_PCM_DMA_ENA)
ret = dma_channel_read(pas16->dma);
else
ret = 0x0000;
ret = pas16_dma_channel_read(pas16, pas16->dma);
for (uint8_t i = 0; i < timer1_ticks; i++)
pitf_ctr_clock(pas16->pit, 1);
pas16->ticks += timer1_ticks;
return ret;
}
@@ -795,16 +838,14 @@ pas16_dma_readw(pas16_t *pas16, uint8_t timer1_ticks)
{
uint16_t ret;
if (pas16->pcm_ctrl & PAS16_PCM_DMA_ENA) {
ret = dma_channel_read(pas16->dma);
if (pas16->dma >= 5)
ret = pas16_dma_channel_read(pas16, pas16->dma);
else {
ret = pas16_dma_channel_read(pas16, pas16->dma);
ret |= (pas16_dma_channel_read(pas16, pas16->dma) << 8);
}
if (pas16->dma < 5)
ret |= (dma_channel_read(pas16->dma) << 8);
} else
ret = 0x0000;
for (uint8_t i = 0; i < timer1_ticks; i++)
pitf_ctr_clock(pas16->pit, 1);
pas16->ticks += timer1_ticks;
return ret;
}
@@ -812,20 +853,19 @@ pas16_dma_readw(pas16_t *pas16, uint8_t timer1_ticks)
static uint16_t
pas16_readdmab(pas16_t *pas16)
{
static uint16_t temp;
uint16_t ret;
if (pas16->dma >= 5) {
if (pas16->dma8_ff)
temp >>= 8;
pas16->dma8_dat >>= 8;
else
temp = pas16_dma_readb(pas16, 1);
pas16->dma8_dat = pas16_dma_readb(pas16, 1);
pas16->dma8_ff = !pas16->dma8_ff;
} else
temp = pas16_dma_readb(pas16, 1);
pas16->dma8_dat = pas16_dma_readb(pas16, 1);
ret = ((temp & 0xff) ^ 0x80) << 8;
ret = ((pas16->dma8_dat & 0xff) ^ 0x80) << 8;
return ret;
}
@@ -844,8 +884,9 @@ static uint16_t
pas16_readdmaw_stereo(pas16_t *pas16)
{
uint16_t ret;
uint16_t ticks = (pas16->sys_conf_1 & 0x02) ? (1 + (pas16->dma < 5)) : 2;
ret = pas16_dma_readw(pas16, 2);
ret = pas16_dma_readw(pas16, ticks);
return ret;
}
@@ -895,17 +936,17 @@ pas16_pit_timer0(int new_out, UNUSED(int old_out), void *priv)
pas16_t *pas16 = (pas16_t *) pit->dev_priv;
uint16_t temp;
pas16_update(pas16);
if (!pas16->pit->counters[0].gate)
return;
if (!dma_channel_readable(pas16->dma))
return;
pas16_update_irq(pas16);
pas16->irq_stat |= PAS16_INT_SAMP;
if (pas16->irq_ena & PAS16_INT_SAMP) {
pas16_log("INT SAMP.\n");
picint(1 << pas16->irq);
}
if (((pas16->pcm_ctrl & PAS16_PCM_ENA) == PAS16_PCM_ENA) && (pit->counters[1].m & 2) && new_out) {
pas16->ticks = 0;
if (((pas16->pcm_ctrl & PAS16_PCM_AND_DMA_ENA) == PAS16_PCM_AND_DMA_ENA) &&
dma_channel_readable(pas16->dma) && (pit->counters[1].m & 2) && new_out) {
if (pas16->pcm_ctrl & PAS16_PCM_MONO) {
temp = pas16_readdma_mono(pas16);
@@ -929,7 +970,22 @@ pas16_pit_timer0(int new_out, UNUSED(int old_out), void *priv)
pas16->irq_stat = (pas16->irq_stat & 0xdf) | (pas16->stereo_lr << 5);
}
}
}
if (pas16->ticks) {
for (uint8_t i = 0; i < pas16->ticks; i++)
pitf_ctr_clock(pas16->pit, 1);
pas16->ticks = 0;
}
pas16->irq_stat |= PAS16_INT_SAMP;
if (pas16->irq_ena & PAS16_INT_SAMP) {
pas16_log("INT SAMP.\n");
picint(1 << pas16->irq);
}
pas16_update(pas16);
}
}
static void
@@ -938,16 +994,15 @@ pas16_pit_timer1(int new_out, UNUSED(int old_out), void *priv)
pitf_t *pit = (pitf_t * )priv;
pas16_t *pas16 = (pas16_t *) pit->dev_priv;
if (!pas16->pit->counters[1].gate)
return;
/* At new_out = 0, it's in the counter reload phase. */
if ((pas16->pcm_ctrl & PAS16_PCM_ENA) && (pit->counters[1].m & 2) && new_out) {
if (pas16->irq_ena & PAS16_INT_PCM) {
pas16->irq_stat |= PAS16_INT_PCM;
pas16_log("pas16_pcm_poll : cause IRQ %i %02X\n", pas16->irq, 1 << pas16->irq);
picint(1 << pas16->irq);
pas16->stereo_lr = 0;
pas16->irq_stat &= 0xdf;
pas16->dma8_ff = 0;
}
}
}
@@ -1019,14 +1074,19 @@ pas16_update(pas16_t *pas16)
for (; pas16->pos < sound_pos_global; pas16->pos++) {
pas16->pcm_buffer[0][pas16->pos] = 0;
pas16->pcm_buffer[1][pas16->pos] = 0;
#ifdef CROSS_CHANNEL
if (pas16->pcm_ctrl & 0x08)
pas16->pcm_buffer[0][pas16->pos] += pas16->pcm_dat_l;
pas16->pcm_buffer[0][pas16->pos] += (int16_t) pas16->pcm_dat_l;
if (pas16->pcm_ctrl & 0x04)
pas16->pcm_buffer[0][pas16->pos] += pas16->pcm_dat_r;
pas16->pcm_buffer[0][pas16->pos] += (int16_t) pas16->pcm_dat_r;
if (pas16->pcm_ctrl & 0x02)
pas16->pcm_buffer[1][pas16->pos] += pas16->pcm_dat_l;
pas16->pcm_buffer[1][pas16->pos] += (int16_t) pas16->pcm_dat_l;
if (pas16->pcm_ctrl & 0x01)
pas16->pcm_buffer[1][pas16->pos] += pas16->pcm_dat_r;
pas16->pcm_buffer[1][pas16->pos] += (int16_t) pas16->pcm_dat_r;
#else
pas16->pcm_buffer[0][pas16->pos] += (int16_t) pas16->pcm_dat_l;
pas16->pcm_buffer[1][pas16->pos] += (int16_t) pas16->pcm_dat_r;
#endif
}
}
}
@@ -1039,11 +1099,11 @@ pas16_get_buffer(int32_t *buffer, int len, void *priv)
sb_dsp_update(&pas16->dsp);
pas16_update(pas16);
for (int c = 0; c < len * 2; c++) {
buffer[c] += (int16_t) (sb_iir(0, c & 1, (double) pas16->dsp.buffer[c]) / 1.3) / 2;
buffer[c] += (int32_t) (sb_iir(0, c & 1, (double) pas16->dsp.buffer[c]) / 1.3) / 2;
if (pas16->filter)
buffer[c] += (low_fir_pas16(0, c & 1, (double) pas16->pcm_buffer[c & 1][c >> 1])) / 2.0;
buffer[c] += (low_fir_pas16(0, c & 1, (double) pas16->pcm_buffer[c & 1][c >> 1]) / 1.3) / 2.0;
else
buffer[c] += (pas16->pcm_buffer[c & 1][c >> 1] / 2);
buffer[c] += ((pas16->pcm_buffer[c & 1][c >> 1] / 1.3) / 2);
}
pas16->pos = 0;
@@ -1086,9 +1146,11 @@ pas16_init(const device_t *info)
sb_dsp_init(&pas16->dsp, SB2, SB_SUBTYPE_DEFAULT, pas16);
pas16->mpu = (mpu_t *) malloc(sizeof(mpu_t));
memset(pas16->mpu, 0, sizeof(mpu_t));
mpu401_init(pas16->mpu, 0, 0, M_UART, device_get_config_int("receive_input401"));
mpu401_init(pas16->mpu, 0, 0, M_INTELLIGENT, device_get_config_int("receive_input401"));
sb_dsp_set_mpu(&pas16->dsp, pas16->mpu);
pas16->sb_compat_base = 0x0000;
io_sethandler(0x9a01, 0x0001, NULL, NULL, NULL, pas16_out_base, NULL, NULL, pas16);
pas16->this_id = 0xbc + pas16_next;