joncampbell123 / dosbox-x

DOSBox-X fork of the DOSBox project
GNU General Public License v2.0
2.66k stars 378 forks source link

Gravis Ultrasound realism, hardware bug: Backwards playback does unsigned voice current_position -= frequency_counter then compares against start #155

Closed joncampbell123 closed 8 years ago

joncampbell123 commented 8 years ago

What this means is: If a voice is playing backwards, and the start position is close enough to 0 or IS 0 such that the voice position could step past it into a negative position value, the GUS will fail to stop or loop at the start position because the hardware acts as if the card then does an unsigned compare against start.

To put this into perspective:

Imagine a voice is playing fast enough that the FC register is 0x40 (step 4 samples per audio sample), and playing backwards. The start position is less than 0x40. The current position is moving backwards as directed and getting closer to 0. Here's what happens:

GUS voice start/positions/end are 24-bit wide.
Upper 20 bits are byte address, lower 4 are fractional position.

position (moving backwards)      start
--------------------------------------------
0x000174                         0x000024
0x000134                         0x000024
0x0000F4                         0x000024
0x0000B4                         0x000024
0x000074                         0x000024
0x000034                         0x000024
0xFFFFF4                         0x000024   <- It *missed* the start point and continued past it, did not loop, change direction, or stop. The current position wrapped around to the top of the GUS memory address space.
0xFFFFB4                         0x000024
(and so on)

If the start position is far enough from 0 that (current_position -= frequency_counter) <= start, then the GUS will stop at the start position as expected:

position (moving backwards)      start
--------------------------------------------
0x000174                         0x000054
0x000134                         0x000054
0x0000F4                         0x000054
0x0000B4                         0x000054
0x000074                         0x000054
0x000054                         0x000054    <- It stopped as expected.
0x000054                         0x000054
0x000054                         0x000054
0x000054                         0x000054
(and so on)

This bug does not happen moving forward, only backwards:

position (moving forwards)       end
--------------------------------------------
0xFFFEF4                         0xFFFFFF
0xFFFF34                         0xFFFFFF
0xFFFF74                         0xFFFFFF
0xFFFFB4                         0xFFFFFF
0xFFFFF4                         0xFFFFFF
0xFFFFFF                         0xFFFFFF   <- It stopped at the end as instructed
0xFFFFFF                         0xFFFFFF
0xFFFFFF                         0xFFFFFF
0xFFFFFF                         0xFFFFFF
(and so on)

This is one way that the GUS emulation could be misleading to developers wishing to target retro hardware. In the interest of hardware, it is recommended that DOSBox-X emulate this unsigned step + compare bug observed on real hardware.

ghost commented 8 years ago

Thank you for the clear and interesting description of the bug. I can sufficiently follow along so I could imagine the effects of a change to that code. :)

Does the GUS have generalized computer chips to do the sound processing and the above error exists in software written to permanent onboard memory?

joncampbell123 commented 8 years ago

I'm not sure how the GF1 chip is wired. I'm assuming so far that it's some sort of specialized DSP core with no branching (since each audio sample output takes a fixed amount of time) and an equally specialized DSP microcode of some kind that has access to ALU units optimized for multipy+add and a memory controller optimized for fetching two sequential samples. Especially for hardware at that era, I'm guessing it's more VLSI than generic CPU.

Then again, I probably don't know what the hell I'm talking about. It's all guessing right now.

ghost commented 8 years ago

Appreciate the overview of how the hardware was generally organized. I've been testing and the gus audio is definitely improved, the sounds seem lower in frequency which matches well to the sb emulation (although I think the GUS emulation sounds better, perhaps more dynamic).

joncampbell123 commented 8 years ago

Exactly. DOSBox's emulation upsampled everything to 44.1KHz (or to your gusrate= setting). The real hardware renders at a sample rate inversely proportional to the number of active channels. Something using 14 active channels @ 44.1KHz should sound better than something using all 32 channels at ~19KHz because that's what the actual hardware does.

Anyway, this bug-for-bug emulation is now done.