byuusan wrote:Some tests I did today:
http://byuu.org/spc/spc_decadjust.zip
This validates the behavior of daa/das with C/H set and clear, for a total of 8 * 256 tests, 2 bytes per test (one result, one PSW value).
Overload's formula is perfect.
ZSNES has problems with both the results and flags, but daa seems to be more correct-ish than das.
Zsnes uses the x86 DAA/DAS instructions and doesn't do any work to emulate those except setting up flags. [as of 0909 wip]
As near as I can tell, Bsnes uses the algorithm Overload posted. However, the algorithms described for DAA/DAS in the
Intel instruction set reference doc appear to be completely equivalent to Overload's (as long as the x86 Auxiliary-carry flag and Carry flag are
set to the SPC's H flag and C flag before the DAA/DAS is executed).
Here are the algorithms described in that doc, in pseudo-C code:
Code: Select all
//Note: AF=auxiliary carry flag (x86 half-carry flag)
/****** DAA ******/
if (((AL & 0x0F) > 9) || AF == 1) {
AL = AL + 6;
CF = CF OR CarryFromLastAddition; /* CF OR carry from AL = AL + 6 */
AF = 1;
} else {
AF = 0;
}
if ((AL & 0xF0) > 0x90) || CF == 1) {
AL = AL + 0x60;
CF = 1;
} else {
CF = 0;
}
/****** DAS ******/
if (((AL & 0x0F) > 9) || AF == 1) {
AL = AL - 6;
CF = CF OR BorrowFromLastSubtraction; /* CF OR borrow from AL = AL - 6 */
AF = 1;
} else {
AF = 0;
}
if ((AL > 0x9F) || CF = 1) {
AL = AL - 60H;
CF = 1;
} else {
CF = 0;
}
Now if you compare these algorithms with Overload's, they seem equivalent? The order of the if-tests is switched around, and the x86 handles AF=1 as a forced carry/borrow into the upper digit, but an assembler implementation that sets AF=H and CF=C and uses x86 DAA/DAS should work fine, should it not? (And since zsnes basically does this... is there something wrong with the flag-manipulating part of the zsnes code for these insns?)
[EDIT: AHA... I think I notice something.. in order to match Overload's, you have to set up the x86 AF flag to have the value of the SPC's H flag *before* doing the DAA/DAS (no need to write it back after). Correction above
in red.
I use SAHF to do set this flag and the carry flag at the same time, as that is easiest with my flags representation.]
Also regarding DIV, I was looking with puzzlement at byuu's implementation of it in bsnes v0.012, which seemed to be different from both zsnes and snes9x. I was wondering where that code came from... I now realize it's blargg's algorithm (cool

) and there's this experimental evidence to back it up. Since zsnes and snes9x seem to both use a different algorithm (do a plain unsigned divide, and special-case X=0) and since I tested plain unsigned divide against blargg's algorithm and got completely different results from blargg's algorithm in many many cases, I currently believe that the DIV implementation in zsnes and snes9x produces wrong results. Is it just that there are no SPC programs out there that rely on this instruction's results in the overflow cases?