From 28115c46509e8e9eee068f4fb9e6d9f9c9bb5628 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 12 Apr 2020 00:18:55 +0200 Subject: [PATCH] Overhauled SB DSP IRQ's and masking and also how it attaches to the MPU-401, fixes IBM OS/2 2.11 among other things. --- src/include/86box/snd_mpu401.h | 13 ++- src/include/86box/snd_sb_dsp.h | 9 +- src/sound/snd_azt2316a.c | 2 +- src/sound/snd_mpu401.c | 103 +++++++++++++++---- src/sound/snd_sb.c | 26 ++--- src/sound/snd_sb_dsp.c | 182 +++++++++++++++++++++------------ 6 files changed, 219 insertions(+), 116 deletions(-) diff --git a/src/include/86box/snd_mpu401.h b/src/include/86box/snd_mpu401.h index b1691b483..75eeb8261 100644 --- a/src/include/86box/snd_mpu401.h +++ b/src/include/86box/snd_mpu401.h @@ -72,8 +72,7 @@ typedef struct mpu_t { uint16_t addr; int uart_mode, intelligent, - irq, irq_mask, - midi_thru, + irq, midi_thru, queue_pos, queue_used; uint8_t rx_data, is_mca, status, @@ -135,12 +134,15 @@ typedef struct mpu_t uint16_t prchg_mask; } filter; struct { - int on; - uint8_t chan, trmask; - uint32_t key[4]; + int on; + uint8_t chan, trmask; + uint32_t key[4]; } chanref[5], inputref[16]; pc_timer_t mpu401_event_callback, mpu401_eoi_callback, mpu401_reset_callback; + void (*ext_irq_update)(void *priv, int set); + int (*ext_irq_pending)(void *priv); + void *priv; } mpu_t; extern int mpu401_standalone_enable, mpu401_already_loaded; @@ -154,6 +156,7 @@ extern void mpu401_setirq(mpu_t *mpu, int irq); extern void mpu401_change_addr(mpu_t *mpu, uint16_t addr); extern void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode, int receive_input); extern void mpu401_device_add(void); +extern void mpu401_irq_attach(mpu_t *mpu, void (*ext_irq_update)(void *priv, int set), int (*ext_irq_pending)(void *priv), void *priv); extern int MPU401_InputSysex(void *p, uint8_t *buffer, uint32_t len, int abort); extern void MPU401_InputMsg(void *p, uint8_t *msg); diff --git a/src/include/86box/snd_sb_dsp.h b/src/include/86box/snd_sb_dsp.h index 47cc2570f..263897711 100644 --- a/src/include/86box/snd_sb_dsp.h +++ b/src/include/86box/snd_sb_dsp.h @@ -62,8 +62,8 @@ typedef struct sb_dsp_t uint8_t sb_test; int sb_timei, sb_timeo; - int sb_irq8, sb_irq16; - int sb_irqm8, sb_irqm16; + int sb_irq8, sb_irq16, sb_irq401; + int sb_irqm8, sb_irqm16, sb_irqm401; uint8_t sb_asp_regs[256]; @@ -91,6 +91,8 @@ typedef struct sb_dsp_t int pos; uint8_t azt_eeprom[AZTECH_EEPROM_SIZE]; /* the eeprom in the Aztech cards is attached to the DSP */ + + mpu_t *mpu; } sb_dsp_t; @@ -98,7 +100,7 @@ void sb_dsp_input_msg(void *p, uint8_t *msg); int sb_dsp_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort); -void sb_dsp_set_mpu(mpu_t *src_mpu); +void sb_dsp_set_mpu(sb_dsp_t *dsp, mpu_t *src_mpu); void sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent); void sb_dsp_close(sb_dsp_t *dsp); @@ -115,5 +117,6 @@ void sb_dsp_poll(sb_dsp_t *dsp, int16_t *l, int16_t *r); void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo); void sb_dsp_update(sb_dsp_t *dsp); +void sb_update_irq(sb_dsp_t *dsp); #endif /* SOUND_SND_SB_DSP_H */ \ No newline at end of file diff --git a/src/sound/snd_azt2316a.c b/src/sound/snd_azt2316a.c index 1cc777ee9..9e534a1d9 100644 --- a/src/sound/snd_azt2316a.c +++ b/src/sound/snd_azt2316a.c @@ -1179,7 +1179,7 @@ azt_init(const device_t *info) mpu401_init(azt2316a->mpu, azt2316a->cur_mpu401_addr, azt2316a->cur_mpu401_irq, M_UART, device_get_config_int("receive_input401")); } else azt2316a->mpu = NULL; - sb_dsp_set_mpu(azt2316a->mpu); + sb_dsp_set_mpu(&azt2316a->sb->dsp, azt2316a->mpu); if (device_get_config_int("receive_input")) midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &azt2316a->sb->dsp); diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index c17531dba..c9523c026 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -155,9 +155,13 @@ MPU401_QueueByteEx(mpu_t *mpu, uint8_t data, int irq) return; } - if ((mpu->queue_used == 0) && !mpu->irq_mask) { - mpu->state.irq_pending = 1; - picint(1 << mpu->irq); + if (mpu->queue_used == 0) { + if (mpu->ext_irq_update) + mpu->ext_irq_update(mpu->priv, 1); + else { + mpu->state.irq_pending = 1; + picint(1 << mpu->irq); + } } if (mpu->queue_used < MPU401_QUEUE) { @@ -181,6 +185,20 @@ MPU401_QueueByte(mpu_t *mpu, uint8_t data) } +static int +MPU401_IRQPending(mpu_t *mpu) +{ + int irq_pending; + + if (mpu->ext_irq_pending) + irq_pending = mpu->ext_irq_pending(mpu->priv); + else + irq_pending = mpu->state.irq_pending; + + return irq_pending; +} + + static void MPU401_RecQueueBuffer(mpu_t *mpu, uint8_t *buf, uint32_t len, int block) { @@ -204,10 +222,14 @@ MPU401_RecQueueBuffer(mpu_t *mpu, uint8_t *buf, uint32_t len, int block) } if (mpu->queue_used == 0) { - if (mpu->state.rec_copy || mpu->state.irq_pending) { - if (mpu->state.irq_pending) { - picintc(1 << mpu->irq); - mpu->state.irq_pending = 0; + if (mpu->state.rec_copy || MPU401_IRQPending(mpu)) { + if (MPU401_IRQPending(mpu)) { + if (mpu->ext_irq_update) + mpu->ext_irq_update(mpu->priv, 0); + else { + mpu->state.irq_pending = 0; + picintc(1 << mpu->irq); + } } return; } @@ -229,7 +251,12 @@ MPU401_ClrQueue(mpu_t *mpu) mpu->rec_queue_used = 0; mpu->rec_queue_pos = 0; mpu->state.sysex_in_finished = 1; - mpu->state.irq_pending = 0; + if (mpu->ext_irq_update) + mpu->ext_irq_update(mpu->priv, 0); + else { + mpu->state.irq_pending = 0; + picintc(1 << mpu->irq); + } } @@ -240,12 +267,20 @@ MPU401_Reset(mpu_t *mpu) #ifdef DOSBOX_CODE if (mpu->mode == M_INTELLIGENT) { - picintc(1 << mpu->irq); - mpu->state.irq_pending = 0; + if (mpu->ext_irq_update) + mpu->ext_irq_update(mpu->priv, 0); + else { + mpu->state.irq_pending = 0; + picintc(1 << mpu->irq); + } } #else - picintc(1 << mpu->irq); - mpu->state.irq_pending = 0; + if (mpu->ext_irq_update) + mpu->ext_irq_update(mpu->priv, 0); + else { + mpu->state.irq_pending = 0; + picintc(1 << mpu->irq); + } #endif mpu->mode = M_INTELLIGENT; @@ -1037,10 +1072,15 @@ MPU401_EOIHandler(void *priv) } else UpdateTrack(mpu, mpu->state.track); } - if (mpu->state.rec_copy || !mpu->state.sysex_in_finished) + if (mpu->state.rec_copy || !mpu->state.sysex_in_finished) return; - mpu->state.irq_pending = 0; + if (mpu->ext_irq_update) + mpu->ext_irq_update(mpu->priv, 0); + else { + mpu->state.irq_pending = 0; + picintc(1 << mpu->irq); + } if (!(mpu->state.req_mask && mpu->clock.active)) return; @@ -1081,13 +1121,21 @@ void MPU401_ReadRaiseIRQ(mpu_t *mpu) { /* Clear IRQ. */ - picintc(1 << mpu->irq); - mpu->state.irq_pending = 0; + if (mpu->ext_irq_update) + mpu->ext_irq_update(mpu->priv, 0); + else { + mpu->state.irq_pending = 0; + picintc(1 << mpu->irq); + } - if (mpu->queue_used && !mpu->irq_mask) { + if (mpu->queue_used) { /* Bytes remaining in queue, raise IRQ again. */ - mpu->state.irq_pending = 1; - picint(1 << mpu->irq); + if (mpu->ext_irq_update) + mpu->ext_irq_update(mpu->priv, 1); + else { + mpu->state.irq_pending = 1; + picint(1 << mpu->irq); + } } } @@ -1234,8 +1282,9 @@ MPU401_Event(void *priv) } #endif - if (mpu->state.irq_pending) goto next_event; - + if (MPU401_IRQPending(mpu)) + goto next_event; + if (mpu->state.playing) { for (i = 0; i < 8; i++) { /* Decrease counters. */ @@ -1287,7 +1336,8 @@ MPU401_Event(void *priv) } } } - if (!mpu->state.irq_pending && mpu->state.req_mask) + + if (MPU401_IRQPending(mpu) && mpu->state.req_mask) MPU401_EOIHandler(mpu); next_event: @@ -1703,6 +1753,15 @@ mpu401_mca_feedb(void *p) } +void +mpu401_irq_attach(mpu_t *mpu, void (*ext_irq_update)(void *priv, int set), int (*ext_irq_pending)(void *priv), void *priv) +{ + mpu->ext_irq_update = ext_irq_update; + mpu->ext_irq_pending = ext_irq_pending; + mpu->priv = priv; +} + + static void * mpu401_standalone_init(const device_t *info) { diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 7a981c098..e96e02c19 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -624,8 +624,7 @@ void sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *p) mixer->regs[0x83] = 0xff; sb->dsp.sb_irqm8 = 0; sb->dsp.sb_irqm16 = 0; - if (sb->mpu != NULL) - sb->mpu->irq_mask = 0; + sb->dsp.sb_irqm401 = 0; } else { @@ -697,18 +696,9 @@ void sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *p) case 0x83: /* Interrupt mask. */ sb->dsp.sb_irqm8 = !(val & 0x01); - if (sb->dsp.sb_irqm8) - sb_irqc(&sb->dsp, 1); sb->dsp.sb_irqm16 = !(val & 0x02); - if (sb->dsp.sb_irqm16) - sb_irqc(&sb->dsp, 0); - if (sb->mpu != NULL) { - sb->mpu->irq_mask = !(val & 0x04); - if (sb->mpu->irq_mask) { - picintc(1 << sb->mpu->irq); - sb->mpu->state.irq_pending = 0; - } - } + sb->dsp.sb_irqm401 = !(val & 0x04); + sb_update_irq(&sb->dsp); break; case 0x84: @@ -721,6 +711,7 @@ void sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *p) else if ((val & 0x06) == 0x02) mpu401_change_addr(sb->mpu, 0); } + break; } mixer->output_selector = mixer->regs[0x3C]; @@ -854,9 +845,8 @@ uint8_t sb_ct1745_mixer_read(uint16_t addr, void *p) case 0x82: /* 0 = none, 1 = digital 8bit or SBMIDI, 2 = digital 16bit, 4 = MPU-401 */ /* 0x02000 DSP v4.04, 0x4000 DSP v4.05 0x8000 DSP v4.12. I haven't seen this making any difference, but I'm keeping it for now. */ - temp = ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0) | 0x4000; - if (sb->mpu) - temp |= ((sb->mpu->state.irq_pending) ? 4 : 0); + temp = ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0) | + ((sb->dsp.sb_irq401) ? 4 : 0) | 0x4000; ret = temp; break; @@ -1278,7 +1268,7 @@ void *sb_16_init(const device_t *info) mpu401_init(sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq"), M_UART, device_get_config_int("receive_input401")); } else sb->mpu = NULL; - sb_dsp_set_mpu(sb->mpu); + sb_dsp_set_mpu(&sb->dsp, sb->mpu); if (device_get_config_int("receive_input")) midi_in_handler(1, sb_dsp_input_msg, sb_dsp_input_sysex, &sb->dsp); @@ -1322,7 +1312,7 @@ void *sb_awe32_init(const device_t *info) sb->mpu = (mpu_t *) malloc(sizeof(mpu_t)); memset(sb->mpu, 0, sizeof(mpu_t)); mpu401_init(sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq"), M_UART, device_get_config_int("receive_input401")); - sb_dsp_set_mpu(sb->mpu); + sb_dsp_set_mpu(&sb->dsp, sb->mpu); } else sb->mpu = NULL; emu8k_init(&sb->emu8k, emu_addr, onboard_ram); diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index a33d2cda4..5a8c239f8 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -44,8 +44,6 @@ static int sbe2dat[4][9] = { { 0x01, -0x02, 0x04, -0x08, -0x10, 0x20, -0x40, 0x80, 90 } }; -static mpu_t *mpu; - static int sb_commands[256]= { -1, 2,-1,-1, 1, 2,-1, 0, 1,-1,-1,-1,-1,-1, 2, 1, @@ -179,28 +177,81 @@ recalc_sb16_filter(int playback_freq) } +void +sb_update_irq(sb_dsp_t *dsp) +{ + int irq_pending; + + irq_pending = (dsp->sb_irq8 && !dsp->sb_irqm8) || + (dsp->sb_irq16 && !dsp->sb_irqm16) || + (dsp->sb_irq401 && !dsp->sb_irq401); + + if (irq_pending) + picint(1 << dsp->sb_irqnum); + else + picintc(1 << dsp->sb_irqnum); +} + + +void +sb_update_status(sb_dsp_t *dsp, int bit, int set) +{ + switch (bit) { + case 0: + default: + dsp->sb_irq8 = set; + break; + case 1: + dsp->sb_irq16 = set; + break; + case 2: + dsp->sb_irq401 = set; + break; + } + + sb_update_irq(dsp); +} + + void sb_irq(sb_dsp_t *dsp, int irq8) { - sb_dsp_log("IRQ %i %02X\n", irq8, pic.mask); - if (irq8 && !dsp->sb_irqm8) - dsp->sb_irq8 = 1; - else if (!irq8 && !dsp->sb_irqm16) - dsp->sb_irq16 = 1; - - picint(1 << dsp->sb_irqnum); + sb_update_status(dsp, !irq8, 1); } void sb_irqc(sb_dsp_t *dsp, int irq8) { - if (irq8) - dsp->sb_irq8 = 0; - else - dsp->sb_irq16 = 0; + sb_update_status(dsp, !irq8, 0); +} - picintc(1 << dsp->sb_irqnum); + +static void +sb_dsp_irq_update(void *priv, int set) +{ + sb_dsp_t *dsp = (sb_dsp_t *) priv; + + sb_update_status(dsp, 2, set); +} + + +static int +sb_dsp_irq_pending(void *priv) +{ + sb_dsp_t *dsp = (sb_dsp_t *) priv; + + return dsp->sb_irq401; +} + + +void +sb_dsp_set_mpu(sb_dsp_t *dsp, mpu_t *mpu) +{ + dsp->mpu = mpu; + + if (mpu != NULL) + mpu401_irq_attach(mpu, sb_dsp_irq_update, sb_dsp_irq_pending, dsp); } @@ -217,8 +268,10 @@ sb_dsp_reset(sb_dsp_t *dsp) dsp->sb_8_length = 0xffff; dsp->sb_8_autolen = 0xffff; - sb_irqc(dsp, 0); - sb_irqc(dsp, 1); + dsp->sb_irq8 = 0; + dsp->sb_irq16 = 0; + dsp->sb_irq401 = 0; + sb_update_irq(dsp); dsp->sb_16_pause = 0; dsp->sb_read_wp = dsp->sb_read_rp = 0; dsp->sb_data_stat = -1; @@ -853,8 +906,8 @@ sb_read(uint16_t a, void *priv) switch (a & 0xf) { case 0xA: /* Read data */ - if (mpu && dsp->uart_midi) { - ret = MPU401_ReadData(mpu); + if (dsp->mpu && dsp->uart_midi) { + ret = MPU401_ReadData(dsp->mpu); } else { dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp]; if (dsp->sb_read_rp != dsp->sb_read_wp) { @@ -912,69 +965,64 @@ sb_read(uint16_t a, void *priv) } -/* This should not even be needed. */ -void -sb_dsp_set_mpu(mpu_t *src_mpu) -{ - mpu = src_mpu; -} - void sb_dsp_input_msg(void *p, uint8_t *msg) { - sb_dsp_t *dsp = (sb_dsp_t *) p; - - sb_dsp_log("MIDI in sysex = %d, uart irq = %d, msg = %d\n", dsp->midi_in_sysex, dsp->uart_irq, msg[3]); + sb_dsp_t *dsp = (sb_dsp_t *) p; + uint8_t len = msg[3], i = 0; - if (!dsp->uart_irq && !dsp->midi_in_poll && (mpu != NULL)) { - MPU401_InputMsg(mpu, msg); - return; - } + sb_dsp_log("MIDI in sysex = %d, uart irq = %d, msg = %d\n", dsp->midi_in_sysex, dsp->uart_irq, msg[3]); - if (dsp->midi_in_sysex) { - return; - } - - uint8_t len = msg[3]; - uint8_t i = 0; - if (dsp->uart_irq) { - for (i=0;isb_irq8); - if (!dsp->sb_irq8) - picint(1 << dsp->sb_irqnum); - } else if (dsp->midi_in_poll) { - for (i=0;iuart_irq && !dsp->midi_in_poll && (dsp->mpu != NULL)) { + MPU401_InputMsg(dsp->mpu, msg); + return; + } + + if (dsp->midi_in_sysex) + return; + + if (dsp->uart_irq) { + for (i = 0; i < len; i++) + sb_add_data(dsp, msg[i]); + sb_irq(dsp, 1); + } else if (dsp->midi_in_poll) { + for (i = 0; i < len; i++) + sb_add_data(dsp, msg[i]); + } } + int sb_dsp_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) { - sb_dsp_t *dsp = (sb_dsp_t *) p; - - uint32_t i; - - if (!dsp->uart_irq && !dsp->midi_in_poll && (mpu != NULL)) - return MPU401_InputSysex(mpu, buffer, len, abort); + sb_dsp_t *dsp = (sb_dsp_t *) p; + uint32_t i; - if (abort) { - dsp->midi_in_sysex = 0; - return 0; - } - dsp->midi_in_sysex = 1; - for (i=0;isb_read_rp == dsp->sb_read_wp) { - sb_dsp_log("Length sysex SB = %d\n", len-i); - return (len-i); - } - sb_add_data(dsp, buffer[i]); - } + if (!dsp->uart_irq && !dsp->midi_in_poll && (dsp->mpu != NULL)) + return MPU401_InputSysex(dsp->mpu, buffer, len, abort); + + if (abort) { dsp->midi_in_sysex = 0; return 0; + } + + dsp->midi_in_sysex = 1; + + for (i = 0; i < len; i++) { + if (dsp->sb_read_rp == dsp->sb_read_wp) { + sb_dsp_log("Length sysex SB = %d\n", len - i); + return (len - i); + } + + sb_add_data(dsp, buffer[i]); + } + + dsp->midi_in_sysex = 0; + + return 0; } + void sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent) { @@ -986,7 +1034,7 @@ sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent) dsp->sb_irqnum = 7; dsp->sb_8_dmanum = 1; dsp->sb_16_dmanum = 5; - mpu = NULL; + dsp->mpu = NULL; sb_doreset(dsp);