There are two special cases that the DSP accelerator handles in a
special way: when the end address is of the form xxxxxxx0 or
xxxxxxx1.
For these two cases, the normal overflow handling doesn't apply.
Instead, the overflow check is different, the ACCOV exception never
fires at all, the predscale register is not updated, reads are not
suspended, and if the end address is 16-byte aligned, the DSP loops
back to start_address + 1 instead of the regular start_address.
When an ACCOV is triggered, the accelerator stops reading back anything
and updating the current address until the YN2 register is set.
This is kept track of internally by the DSP; this state is not exposed
via any register.
However, we need to emulate this behaviour correctly because some
ucodes rely on it (notably AX GC); failure to emulate it will result
in reading past the end and start address for non-looped voices.
When the current address is xxxxxxxf, after doing the standard ADPCM
decoding and incrementing the current address as usual to get the
next address, the DSP will update the predscale register by reading
2 bytes from memory, and add two to get the next address.
This means xxxxxx10 cannot be a current address, as the DSP goes
from 0f to 12 directly.
A more serious issue with the old code is that if the start address
is 16-byte aligned, some samples will always be skipped, even when
that should not be the case.
An easy way to test whether this behaviour is correct is to check
the current address register and the predscale after each read.
Old code:
...
ACCA=00000002, predscale=<value>
ACCA=00000003, predscale=<value>
...
ACCA=0000000f, predscale=<value>
ACCA=00000010, predscale=<another value>
ACCA=00000013, predscale=<another value>
ACCA=00000014, predscale=<another value>
...
New code (and console):
...
ACCA=00000002, predscale=<value>
ACCA=00000003, predscale=<value>
...
ACCA=0000000f, predscale=<value>
ACCA=00000012, predscale=<another value>
ACCA=00000013, predscale=<another value>
...
Slightly cleaner, allows DSP accelerator behaviour to be
added to both HLE and LLE pretty easily, and makes the accelerator
easier to unit test.
I chose to include all accelerator state as private members, and
to expose state that is accessible via registers with getters/setters.
It's more verbose, yes, but it makes it very clear what is part of
the accelerator state and what isn't (e.g. coefs).
This works quite well for registers, since the accelerator can do
whatever it wants internally. For example, the start/end/current
addresses are masked -- having a getter/setter makes it easier to
enforce the mask.
The logic is entirely the same; only the inputs and outputs are
different, so deduplicating makes sense.
This will make fixing accelerator issues easier.
Ideally Common.h wouldn't be a header in the Common library, and instead be renamed to something else, like PlatformCompatibility.h or something, but even then, there's still some things in the header that don't really fall under that label
This moves the version strings out to their own version header that doesn't dump a bunch of other unrelated things into scope, like what Common.h was doing.
This also places them into the Common namespace, as opposed to letting them sit in the global namespace.
Based on hardware tests, masking occurs for the accelerator registers.
This fixes Red Steel and Far Cry Vengeance, which rely on this behavior
when reading back the current playback position from the DSP.
CNTVCT_EL0 is force-enabled on all linux plattforms.
Windows is untested, but as this is the best way to get *any* low
overhead performance counters, they likely use it as well.
Within Cleanup(), it is called at *every* end of the block. This generates bigger code,
but it is the only way to handle blocks with multiple exit nodes.
Since all queues are FIFO data structures, the name wasn't informative
as to why you'd use it over a normal queue. I originally thought it had
something to do with the hardware graphics FIFO.
This renames it using the common acronym SPSC, which stands for
single-producer single-consumer, and is most commonly used to talk about
lock-free data structures, both of which this is.
Prevents resource managers that shouldn't be visible from being exposed
to titles.
This adds a new function to get features for an IOS version, and also
moves the version checks from the modules themselves to VersionInfo.
This hopefully documents some of the differences between IOS better
and should be slightly cleaner than having random version checks.