Johnny Cache
Johnny Cache

Reputation: 1073

Assembly 8086 TASM - 0Ah 21h remembers last entry

So I'm writing a uni assignment - a program that subtracts two entered decimals (max 10 characters ea). The first iteration works as intended. However, when I restart the program, for some reason the second operand is remembered. The prompt to enter it does come up, but is then skipped as if I've entered something already - the same thing I entered the first iteration, in fact. The question is: why does it happen and how do I fix it? The first prompt works correctly.

The prompt is under INPUT_2:

    .model small             
    .386                     

    stack       100h         

    dataseg      
inputMsg1   db 0Ah, 0Dh, 'Enter first operand', 0Ah, 0Dh, '$'
inputMsg2   db 0Ah, 0Dh, 'Enter second operand', 0Ah, 0Dh, '$'
inputMax1   db 11
inputLen1   db ?
input1      db 12 dup(?)
input1Packd db 5 dup(0)
inputMax2   db 11
inputLen2   db ?
input2      db 12 dup(?)
input2Packd db 5 dup(0)
packMode    db 0            ;Режим упаковки: 1 - первая цифра, 2 - вторая
resMsg      db 0Ah, 0Dh, 'Result: $'
res         db 9 dup(' '),'$'
retryMsg    db 0Ah, 0Dh
db 'Press Any Key to continue, ESC to quit'
db '$'
errorMsg    db 0Ah, 0Dh, 'Something went wrong. Try again$'
    codeseg
START:
    startupcode

    jmp INPUT_1
INPUT_1_ERROR:
    lea DX, errorMsg
    mov AH, 09h
    int 21h
INPUT_1:
    lea DX, inputMsg1
    mov AH, 09h
    int 21h
    lea DX, inputMax1
    mov AH, 0Ah
    int 21h
    cmp inputLen1, 0
    jz  INPUT_1_ERROR
INPUT_1_PROCESS:
    lea BX, input1
    lea DX, input1Packd
    xor CX, CX
    mov CL, inputLen1
    mov SI, CX
    dec SI
    mov DI, 4
INPUT_1_LOOP:     
    mov AL, [BX][SI]
    cmp AL, '0'
    jb  INPUT_1_ERROR
    cmp AL, '9'
    ja  INPUT_1_ERROR
    and AL, 0Fh
    mov AH, packMode
    cmp AH, 0
    jnz INPUT_1_PACK_SECOND
INPUT_1_PACK_FIRST:
    inc AH
    push BX
    mov BX, DX
    mov [BX][DI], AL
    pop BX
    jmp INPUT_1_PACK_FINISHED
INPUT_1_PACK_SECOND:
    dec AH
    shl AL, 4
    push BX
    mov BX, DX
    or  [BX][DI], AL
    pop BX
    dec DI
INPUT_1_PACK_FINISHED:
    mov packMode, AH
    dec SI
    loop INPUT_1_LOOP
    mov packMode, 0
    jmp INPUT_2
INPUT_2_ERROR:
    lea DX, errorMsg
    mov AH, 09h
    int 21h
INPUT_2:
    lea DX, inputMsg2
    mov AH, 09h
    int 21h
    lea DX, inputMax2
    mov AH, 0Ah
    int 21h
    cmp inputLen2, 0
    jz  INPUT_2_ERROR
INPUT_2_PROCESS:
    lea BX, input2
    lea DX, input2Packd
    xor CX, CX
    mov CL, inputLen2
    mov SI, CX
    dec SI
    mov DI, 4
INPUT_2_LOOP:     
    mov AL, [BX][SI]
    cmp AL, '0'
    jb  INPUT_2_ERROR
    cmp AL, '9'
    ja  INPUT_2_ERROR
    and AL, 0Fh
    mov AH, packMode
    cmp AH, 0
    jnz INPUT_2_PACK_SECOND
INPUT_2_PACK_FIRST:
    inc AH
    push BX
    mov BX, DX
    mov [BX][DI], AL
    pop BX
    jmp INPUT_2_PACK_FINISHED
INPUT_2_PACK_SECOND:
    dec AH
    shl AL, 4
    push BX
    mov BX, DX
    or  [BX][DI], AL
    pop BX
    dec DI
INPUT_2_PACK_FINISHED:
    mov packMode, AH
    dec SI
    loop INPUT_2_LOOP

MATH_SETUP:
    mov SI, 4
    mov CX, 4
    mov DI, 7
MATH:
    lea BX, input1Packd
    mov AL, [BX][SI]
    lea BX, input2Packd
    mov AH, [BX][SI]
    sbb AL, AH
    pushf
    das
    dec SI
    mov AH, AL
    lea BX, res
    and AL, 0Fh
    or AL, 30h
    mov [BX][DI], AL
    dec DI
    shr AH, 4
    or AH, 30h
    mov [BX][DI], AH
    dec DI
    popf
    loop MATH


    lea BX, res
    mov CX, 7
    mov SI, 0
SHORTEN:
    mov AL, [BX][SI]
    cmp AL, '0'
    jnz WRAPUP
    inc SI
    loop SHORTEN

WRAPUP:
    push CX
    lea DX, resMsg
    mov AH, 09h
    int 21h
    lea DX, res
    pop CX
    cmp CX, 0
    jz SKIP_SHORTEN
PRINT_SHORTEN:
    add DX, 7
    sub DX, CX
    jmp FINISH_SHORTEN
SKIP_SHORTEN:
    add DX, 6
FINISH_SHORTEN:
    mov AH, 09h
    int 21h 
    lea DX, retryMsg
    mov AH, 09h
    int 21h
    mov AH, 01h
    int 21h
    cmp AL, 1Bh
    jz QUIT
    lea BX, input1Packd
    mov DX, 1
BCD_CLEANUP:
    mov DI, 0
    mov CX, 5
BCD_CLEANUP_LOOP:
    mov [BX][DI], 0
    inc DI
    loop BCD_CLEANUP_LOOP
    lea BX, input2Packd
    cmp DX, 1
    mov DX, 0
    jz BCD_CLEANUP
    jmp START
QUIT:               
    exitcode 0  

end START

Any better code suggestions welcome as well, but not needed if you don't have an answer for the question.

Upvotes: 2

Views: 773

Answers (1)

Sep Roland
Sep Roland

Reputation: 39556

The DOS buffered input function 0Ah allows you to have a preset text in the storage space of the input buffer that you provide. For a complete explanation of this DOS function see how buffered input works.

The first time that your program runs the inputLen1 and inputLen2 fields are empty because of how you defined them in the source using db ? which translates to zero.
But when you re-run the code this is no longer the case! The lengths still show what you got in the previous run. You need to zero both these fields before invoking function 0Ah again on the same input buffers.

    mov DX, 0
    jz  BCD_CLEANUP
    mov inputLen1, DL   ;DL=0
    mov inputLen2, DL   ;DL=0
    jmp START

The MATH loop has a couple of problems regarding the CF.

  • The sbb al, ah instruction depends on the value in the carry flag, but you neglect to make sure it is off on the first iteration of this loop. Just add clc:

        clc
    MATH:
        lea BX, input1Packd
        mov AL, [BX][SI]
        lea BX, input2Packd
        mov AH, [BX][SI]
        sbb AL, AH
    
  • The das instruction consumes the carry flag that you get from the sbb instruction, but it's the carry flag that you get from the das instruction that you need to preserve/restore to have it propagate through the loop.

        sbb AL, AH
        das
        pushf
    

...a program that subtracts two entered decimals (max 10 characters ea)...

If ever you enter 9 or 10 characters, those most significant digits will not be taken into account because MATH_SETUP really limits you to 8 characters (which in turn is a good thing since the res buffer only has room to show 8 characters)!

MATH_SETUP:
    mov SI, 4   <-- Could permit 10 packed BCD digits
    mov CX, 4   <-- Max 8 characters
    mov DI, 7   <-- Max 8 characters

Upvotes: 2

Related Questions