jeffpar / pcjs

The original IBM PC and other machine emulations in JavaScript

Home Page:https://www.pcjs.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Incorrect handling of the AF flag on x86 CPU

LinoMastro opened this issue · comments

The pcx86 CPU emulation doesn't seem to handle the AF bit in the flags correctly, at least in some cases involving logical operations and the DAA instruction.

Here's a small test case, which can be compiled with NASM to a COM file for DOS:

    mov ax, 20bh
    daa
    and al, 0fh
    daa
    or al, 30h
    mov dl, al
    int 21h  ; print the character in DL
    int 20h  ; exit

I expect the first DAA to set the AF flag to 1, then the AND instruction to set it to zero and the second DAA to set AL to 1. Then the example above calls DOS to print "1". But when running in PCjs the program above prints "7" instead, because the AF flag is still set to 1 when the second DAA is executed.

There's some x86 documentation that states that the AF flag is undefined after an AND instruction but on real hardware (at least on my recent AMD CPU running in 16-bit mode) and in other emulators (dosbox, PCem and QEMU) the behavior of AND in the example above is to clear AF, resulting in a "1" output.

There's also a second related test case which is even weirder (note that the first two instructions are different here):

    mov ax, 20fh
    add al, ah
    and al, 0fh
    daa
    or al, 30h
    mov dl, al
    int 21h
    int 20h

Again in this case I expect the output to be "1" and indeed if running this second program directly from the DOS prompt in PCjs it does print "1", but when I single-step through the code the behavior changes and again it prints "7". This happens with both MS-DOS debug.exe and PCjs builtin debugger.

I'm not sure why for the second example the bug only appears in debuggers. Maybe when running directly the ADD instruction fails to set the AF flag to 1, hiding the fact that then AND fails to clear AF? Just speculating, I checked the pcx86 code but I don't fully understand flag handling.

I can reproduce the issue on an emulated IBM PC AT machine running MS-DOS 6.22. I did my tests with https://www.pcjs.org/software/pcx86/sys/dos/microsoft/6.22/

It does seem that logical instructions (at least AND, OR, and TEST) clear AF on actual hardware, so I went ahead and added a call to clearAF() in the setLogicResult() function. Fingers crossed that this doesn't have any unexpected side-effects. I'm going to push this to the website shortly -- you should see the displayed pcx86 version as 2.22 when it's available.

Thanks for the fast response.

The new 2.22 version with 5a85a07 is now live and it seems to have fixed the problem for me.