First post, by DOSferatu
Dear developers of DOSBox!
At first: I don't want to mock around that much. DOSBox is a great tool and you've done great work Oh, and please apologize my English - for I'm German (so English is not my native language).
Oh, and I don't really know anything about bug reports - I hope my text isn't too long.
But, recently I've found some kind of bug in your CPU emulation - or better: A friend of mine, testing one of my self-written tools - in DOSBox (because he don't own a real DOS machine) - found a bug. At first he thought, it's in my tool (and I thought it, either, because of: who humble I am and who expert are the DOSBox developers?) ...
But testing the special part revealed: my tool worked fine in real DOS. Even a test program, using the same opcodes, worked fine in real DOS. Furthermore, both - my tool AND the test program - work fine with DOSBox setting core=dynamic. But with core=normal or core=simple (and core=auto, which I think chose normal/simple in that case, too) the bug appears.
After some research in the mighty Internet about what the "core"-settings do in DOSBox, it makes total sense to me: setting "dynamic" compiles the code into real machine code, so the real CPU does the work here. The other settings make an emulation of the opcodes - and hereby maybe something wrong happens.
The bug(s) are happening with the commands ROL and ROR (rotate left/right) - and only, when it is done at a memory location - not in a register: The behavior corresponding the setting of the CARRY flag is wrong then when someone uses a rotating-count with X lower bits zero when the value is X bits wide. That behavior is (from 80386 and above) totally right - with values of 32 bits. But the "AND 01fh" to the rotate-count happens always, even if the value to be rotated is just 8 or 16 bits wide! So, it is totally "legal" to make something like:
rol byte ptr[cs:1234h],8
At first, it would SEEM to make no sense to rotate an 8-bit memory value 8 times, because the value will stay the same doing so. BUT - the carry flag is set (and has to be set!) as if the whole 8 rotations were done. Why? Because it is an easy way to copy the MSB or LSB (bit 7 or bit 0 in this case) into the carry flag without making some other "stunts" and it works for 8-bit and 16-bit values even on 80386 and above (despite the "masking out" of the upper 3 bits of the rotating-count value since 80386 - the lower 5 bits are still used, nonetheless of the bitwidth of the data to be rotated)
For rotating REGISTERS, DOSBox does it the right way - in ALL settings of core (dynamic, auto, normal, simple). But for rotating memory locations, DOSBox fails, if the lower 8 or 16 bits of the rotating count are zeroes and the value to be rotated is only 8 or 16 bits wide - in this case (except with "core=dynamic"), DOSBox does the CARRY flag ALWAYS SET (=1), even it was clear before and even if the value to be rotated is 00h / 0000h (=all bits zeroes). That is definetely wrong.
Maybe someone tried some kind of "speed hack" here or something. That should be still possible:
rol byte ptr[xxxx],8 -or- rol byte ptr[xxxx],16
should copy bit 0 (LSB) of xxxx into carry.
ror byte ptr[xxxx],8 -or- ror byte ptr[xxxx],16
should copy bit 7 (MSB) of xxxx into carry.
rol word ptr[xxxx],16
should copy bit 0 (LSB) of xxxx into carry.
ror word ptr[xxxx],16
should copy bit 15 (MSB) of xxxx into carry.
I've added a small test tool (for 8-bit values) and some of its output files:
ROLROR.EXE - the tool
MSDOS622.TXT - output from a real machine with real MS-DOS v6.22
DYNAMIC.TXT - output from DOSBox with core=dynamic
AUTO.TXT - output from DOSBox with core=auto
NORMAL.TXT - output from DOSBox with core=normal
SIMPLE.TXT - output from DOSBox with core=simple
Output of the tool uses standard MS-DOS functions, so redirecting output this way is possible:
ROLROR.EXE >example.txt
I hope I didn't bother you all too much - but I guess, an emulation should be correct.
Sincerely,
DOSferatu