Anyone with a PS/2 or other MCA system will know: Sound Blaster cards hate Micro Channel. I've spent the weekend getting a Sound Blaster working in MAME on the PS/2, and I finally got it figured out. The problem wasn't really on my end - the problem was a combination of the bus design and crappy audio libraries.
The Sound Blaster is made to play back digital audio via the PC's DMA controller, the Intel 8237. The 8237 is from the 8085 device family, not the x86 device family. As implemented on an AT or PS/2, the DMA controller is extremely slow (it always operates at 4.77MHz), can only address 16MB of memory, and transfers can't cross a 64KB block. Nearly everything will bypass it and perform bus operations via the CPU.
If you're transferring a lot of small blocks of data and don't necessarily need speed, then you can use it. Generally the PC's floppy drive reads and writes sectors via DMA, for example.
The early Sound Blaster cards are pretty limited in their digital audio playback - 8-bit mono PCM at up to 22KHz is the name of the game. Fortunately, that means it doesn't require much data to play back digital audio, so the DMA controller is perfect and frees the CPU from having to shove data at the card constantly. The Sound Blaster raises a DMA request and the controller duly forwards bytes to it as long as there are bytes to send.
If you set up the DMA controller properly, you end up with a ring buffer that allows seamless playback of your audio, bouncing between two buffers - one for the CPU to write, one for the Sound Blaster to read. That's your DMA channel in the game's SETUP.EXE.
When the DMA controller runs out of data to transfer (because it reached the end of its current block in the ring buffer) the Sound Blaster will raise an IRQ to ask for more data. That's your IRQ number in the game's SETUP.EXE.
Interrupts are handled on the PC by the Intel 8259 Programmable Interrupt Controller. An AT or PS/2 has two of them, providing IRQ0 through IRQ15. Here's where ISA and MCA split.
On ISA systems, interrupts are edge-triggered. The PIC senses that an IRQ line has been asserted, signals the CPU, and sends along the interrupt vector for the CPU to figure out what needs attention. With edge-triggered interrupts, if a device is holding an IRQ line high, only one interrupt is triggered. You need to clear the interrupt to get another one on that line.
The problem with that is the infamous IRQ conflict - that's when multiple devices are on the same IRQ. The system doesn't know who raised the request, and interrupts will disappear because you can't raise a line that's already raised. A very common example is LPT1 and a Sound Blaster - LPT1 is on IRQ 7 and a Sound Blaster is usually on IRQ 7 as well. The PIC can only handle one device per channel.
For the PS/2, IBM wanted to allow IRQs to be shared between devices. On MCA systems, interrupts are level-triggered. The PIC senses that an IRQ line has been asserted and will keep signalling the interrupt to the CPU for as long as the IRQ is held.
If the printer is asserting IRQ 7 and the Sound Blaster is asserting IRQ 7, the IRQ will be signaled to the CPU as long as either device is holding the line high. The OS will see IRQ 7 and is supposed to chain through its interrupt handlers until the IRQ is no longer held.
The Sound Blaster will keep holding its IRQ until the CPU reads from its status port. On an ISA system, that only results in one IRQ 7. On an MCA system, the PIC will continue signaling IRQ 7 for as long as the Sound Blaster is demanding attention. If your interrupt handler doesn't clear the Sound Blaster's interrupt flag, the PIC will keep sending IRQ 7s forever, or at least until it runs out of stack space and your system crashes.
Doom's digital audio interrupt handler acknowledges the interrupt from the PIC, which is correct behavior, but it doesn't clear the request coming from the Sound Blaster, so it just receives IRQs until the stack overflows. Whoops.
