#260 Auxiliary flag borrow not working correctly



I'm using Linux and I'm writing an 8086 interpreter to
run Kings Bounty (VGA, PC speaker sound, no mouse). I'm
using DOSBox 0.65 to run FreeDOS Debug v0.98 and I am
currently writing a routine to set the auxiliary flag
on subtraction. So I entered into Debug a simple test
(numbers are hex) :-

0100: B9 11 00 MOV CX,11
0103: 49 DEC CX
0104: EB FD JMP 0103

I get an auxiliary carry (AC) on 11 to 10 and no
auxiliary carry (NA) on 10 to 0F! This is wrong. The AC
flag should be set on a borrow from the high nibble to
the low nibble. So I carried on testing and got an AC
on 01 to 00 and NA on 00 to FF. It would appear that
the auxiliary carry on subtraction is not functioning

I went onto my WinXP machine and used debug.exe and it
worked correcty as expected, so I thought maybe it was
a problem with FreeDOS Debug v0.98. I copied debug.exe
from WinXP onto Linux and ran it under DOSBox. I got
the same errors, therefore it is a bug in DOSBox. The
auxiliary flag is correctly set on addition with a
carry from the low to high nibble. I get an AC on EF to
F0 and FF to 00 which is correct.



  • Simcon

    Logged In: YES

    Ok, so far I have found a typo in lazyflags.h:41 "extern
    LazyFlags lfags;" (lfags should be lflags) no real problem
    as the correct extern is lower down at line 56.

    This auxiliary flag bug occurs with AX,BX,CX,AL,BL,CL etc
    with DEC. The bug doesn't happen with SUB CX,1 so it is a
    DEC issue.

    I have not yet found the location of the bug, although I
    have spent a few hours tonight searching.

  • Peter Veenstra
    Peter Veenstra

    Logged In: YES

    at I think the code you are looking for is in
    src/cpu/flags.cpp around line: 161

    lf_res{bwd} would be the result of the operation (so the
    result of the dec)
    The sub cx,1 variant can be found at line 148
    lf_var{12}{bwd} would be the 2 operants for the function. in
    questions (the different type of functions are t_SUB (for
    SUB) and t_DEC (for decrease)

    I might be wrong, but this is how I've always interpreted
    this code. (I didn't write this part though).

  • c2woody

    Logged In: YES

    I think FillFlags() in flags.cpp is wrong for DEC
    (get_AF() is correct, that's why it behaves wrong in
    the debugger only and in some other cases).

    In FillFlags(), line 795ff try to change the aux flag
    setting at case t_DECb/w/d to
    SET_FLAG(AF,(lf_resb & 0x0f) == 0x0f); (resw/resd
    accordingly), that is change the ==0 to ==0x0f.

  • Simcon

    Logged In: YES

    Last night I knew the code in get_AF(void) t_DECb/w/d was
    correct (return (lf_resb & 0x0f) == 0x0f;) so I was assuming
    this code wasn't being correctly run. I never got to
    FillFlags() because I was attempting to follow the t_DECb
    back through the program. I got to op.h and the "switch
    (inst.code.op) {" and I commented out the t_DECb/w/d code
    and it didn't make any difference. I though this is weird,
    this code isn't being executed.

    c2woody, it is indeed this code in FillFlags() that is
    wrong. In FillFlags() for t_DECb/w/d the "== 0" must be
    replaced with "== 0x0f" and it works correctly. I have just
    compiled and tested it and it now does what is should. I
    haven't updated your source code.

    You state that this bug only happens in the debugger and
    some other cases. I wrote a small test program last night
    using DOS debug and ran it on the command line :-

    MOV AX,11
    DEC AX // this causes the bug
    POP AX // get flags in ax
    AND AX,10 // isolate ac flag
    MOV CL,4
    SHR AX,CL // aux carry is 1, no aux is 0
    ADD AX,30 // convert it to ascii
    MOV AH,2
    INT 21 //print the aux carry flag
    INT 20

    This code did show the AC bug on the command line. It would
    print "1".

    So what then is the function of get_AF() in flags.cpp?

  • c2woody

    Logged In: YES

    DEC AX // this causes the bug

    The pushf uses FillFlags() as well, so it'll have the wrong
    value for AF as well.

    So what then is the function of get_AF() in flags.cpp?

    Used for lazy evaluation of the auxiliary flag, that is
    when only AF (or AF+CF and similar combinations) is needed
    for a following opcode, e.g. conditional jumps.
    Opcodes that rely on a lot of flags (interrupt to the
    debugger, pushf in your case) use FillFlags() to evaluate
    all flags at once.

    Again thanks for reporting this issue.

  • Peter Veenstra
    Peter Veenstra

    Logged In: YES

    The bug has been fixed.
    Wait for the upcoming new version to see it.


    The updated source is available by cvs.

    See the link on top of the screen for information on how to get
    the new sources.

    The DOSBox Team

  • Peter Veenstra
    Peter Veenstra

    Logged In: YES

    c2woody has commited a fix.