装配8086 TASM - 0Ah 21h记住最后一个条目

时间:2018-05-24 04:00:30

标签: string assembly interrupt x86-16

所以我写了一个uni赋值 - 一个减去两个输入小数的程序(最多10个字符ea)。第一次迭代按预期工作。但是,当我重新启动程序时,由于某种原因会记住第二个操作数。 输入它的提示确实出现了,但是然后被跳过,好像我已经输入了一些东西 - 事实上我进入第一次迭代时也是如此。 问题是:为什么会发生,我该如何解决?第一个提示正常工作。

提示符在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

任何更好的代码建议也会受到欢迎,但如果您对此问题没有答案,则不需要。

1 个答案:

答案 0 :(得分:1)

DOS缓冲输入功能0Ah允许您在所提供的输入缓冲区的存储空间中具有预设文本。有关此DOS函数的完整说明,请参阅how buffered input works

您的程序第一次运行 inputLen1 inputLen2 字段为空时,因为您使用db ?在源中定义它们的方式转换为零。
但是当你重新运行代码时,情况就不再如此了!长度仍显示您在上一次运行中获得的内容。在相同的输入缓冲区上再次调用函数0Ah之前,需要将这两个字段归零。

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

MATH 循环在CF方面存在一些问题。

  • sbb al, ah指令取决于进位标志中的值,但是忽略确保它在此循环的第一次迭代时关闭。只需添加clc

    即可
        clc
    MATH:
        lea BX, input1Packd
        mov AL, [BX][SI]
        lea BX, input2Packd
        mov AH, [BX][SI]
        sbb AL, AH
    
  • das指令使用从sbb指令获得的进位标志,但它是您需要保留的das指令的进位标志/ restore让它通过循环传播。

        sbb AL, AH
        das
        pushf
    
  

...减去两个输入小数的程序(最多 10 个字符ea)......

如果您输入9或10个字符,那么这些最高有效数字将不会被考虑在内,因为 MATH_SETUP 确实将您限制为8个字符(这反过来又是一个很好的事情,因为 res 缓冲区只有空间显示8个字符)!

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