1

我有一个大学项目,我需要添加或减去两个 2 位数字(用户输入数字)。我得到了工作的补充。减法使十位数正确,但在个位数位置给出奇数字符。这就是我的意思(结果图片):

链接到 Flickr 屏幕截图

我用:

  • TASM 和 TLINK
  • x86
  • Windows XP(虚拟盒子)

代码:

.MODEL SMALL
.STACK 100h
.DATA 

    startMsg DB 13,10,'1.) Add ',10,'2.) Subtract',10,'3.) Exit',10,10,'Select a function: $'
    integer1Msg DB 13,10,10,'Enter the first integer: $'
    integer2Msg DB 13,10,'Enter the second integer: $'
    errorOccuredMsg DB 13,10,13,10,'An error occured, please try again! $'

    sumMsg DB 13,10,10,'The sum is: $'
    subMsg DB 13,10,10,'The differance is: $'

    gotNum  DB  0
    func    DB  0

.CODE
start:
    mov ax,@data
    mov ds,ax

    mov gotNum, 0   ; initialize var

    ;display & get the selection
    mov ah,09
    mov dx,OFFSET startMsg
    int 21h
    mov ah,01
    int 21h

    mov func,al

    ;check what the selection was
    cmp func,'1'
    je additionIntermediate
    cmp func,'2'
    je subtractionIntermediate
    cmp func,'3'
    je exit

exit:
    mov ah,4ch
    int 21h

getNum1:
    ;get the first integer (1st digit)
    mov ah,09
    mov dx,OFFSET integer1Msg
    int 21h
    mov ah,01
    int 21h

    ;check that input is a number
    cmp al, 30h  ;0 (ASCII 48)
    jl errorIntermediate  
    cmp al, 39h  ;9 (ASCII 57)
    jg errorIntermediate

    mov bh,al
    sub bh,30h

    ;get the first integer (2nd digit)
    mov ah,01
    int 21h

    ;check that input is a number
    cmp al, 30h  ;0 (ASCII 48)
    jl errorIntermediate
    cmp al, 39h  ;9 (ASCII 57)
    jg errorIntermediate

    mov bl,al
    sub bl,30h

    jmp getNum2

additionIntermediate:
    jmp addition

subtractionIntermediate:
    jmp subtraction

errorIntermediate:
    jmp errorOccured

getNum2:
    ;get the second integer
    mov ah,09
    mov dx,OFFSET integer2Msg
    int 21h
    mov ah,01
    int 21h

    ;check that input is a number
    cmp al, 30h  ;0 (ASCII 48)
    jl errorOccured  
    cmp al, 39h  ;9 (ASCII 57)
    jg errorOccured

    mov ch,al
    sub ch,30h

    ;get the second integer
    mov ah,01
    int 21h

    ;check that input is a number
    cmp al, 30h  ;0 (ASCII 48)
    jl errorOccured  
    cmp al, 39h  ;9 (ASCII 57)
    jg errorOccured

    mov cl,al
    sub cl,30h

    mov gotNum,1

    cmp func,'1'
    je addition
    cmp func,'2'
    je subtraction
    cmp func,'3'
    je errorOccured

getNumIntermediate:
    jmp getNum1

addition:
    cmp gotNum,0
    je getNumIntermediate

    ;add the two numbers and adjust for addition
    mov ah,0
    add bx,cx
    aaa
    or bx,3030h

    ;display result
    mov ah,09
    mov dx,OFFSET sumMsg
    int 21h
    mov dl,bh
    mov ah,02
    int 21h
    mov dl,bl
    mov ah,02
    int 21h

    ;return to beginning
    jmp start

errorOccured:
    lea dx, errorOccuredMsg
    mov ah,09
    int 21h
    jmp start

subtraction:
    cmp gotNum,0
    je getNumIntermediate

    ;determine which subtraction to use
    cmp bx,cx
    jg subtractionPos
    cmp bx,cx
    jl subtractionNeg

subtractionPos: ;integer1 is larger than integer2
    ;subtract
    sub bx,cx
    aas
    or bx,3030h

    ;display result
    mov ah,09
    mov dx,OFFSET subMsg
    int 21h
    mov dl,bh
    mov ah,02
    int 21h
    mov dl,bl
    mov ah,02
    int 21h

    ;return to beginning
    jmp start

subtractionNeg: ;integer2 is larger than integer1
    ;subtract
    sub cx,bx
    aas
    or cx,3030h

    ;display result
    mov ah,09
    mov dx, OFFSET subMsg
    int 21h
    mov ah,06
    mov dl,2dh ;displays the negative sign
    int 21h
    mov dl,ch
    mov ah,02
    int 21h
    mov dl,cl
    mov ah,02
    int 21h

    ;return to beginning
    jmp start

end start

我对组装很陌生,所以任何建议都会很棒。

编辑

;subtract
    sub bx,cx       
    mov ch,bh    ;store the value of bh
    xchg bx, ax
    mov bl,0Ah
    div bl
    xchg ah, al
    xchg ax, bx
    mov bh,ch    ;restore the value of bh
    or bx,3030h
4

2 回答 2

0
;subtract
sub bx,cx
aas
or bx,3030h

AAS指令表示减法后调整Al。它会调整AL,而不是BX。要使用BX,您可以使用以下代码:

sub bx, cx
xchg bx, ax
    mov bl, 0x0A
    div bl
    or ax, 0x3030
xchg ah, al
xchg ax, bx
于 2013-09-07T12:19:44.350 回答
0
add bx,cx
aaa

在此添加之后,使用该指令是没有意义的,因为该指令专门aaa对寄存器进行操作。AX

sub bx,cx
aas

在这个减法之后,使用该指令是没有意义的,因为该指令专门aas对寄存器进行操作。AX

使用aaa

该程序将添加几个从键盘输入的 2 位数字。每个数字都存储在其自己的字节大小的寄存器中。对于第一个数字是BH(十)和BL(一)。对于第二个数字,它是CH(十)和CL(个)。

级联添加的第一步是添加“一”。如果此加法的结果超出范围 [0,9],我们将不得不调整该值并将进位 1 传播到下一步。aaa指令进行此调整。

    mov     al, bl
    add     al, cl          ; Ones
    aaa                     ; -> AL CF
    mov     bl, al

级联加法的第二步是添加上一步的“十”进位。因此,我们将使用adc而不是add. 如果此加法的结果超出范围 [0,9],我们将不得不调整该值并将进位 1 传播到下一步。

    mov     al, bh
    adc     al, ch          ; Tens
    aaa                     ; -> AL CF
    mov     bh, al

第三步将显示“1”,但前提是前一步有进位。这表明加法的结果大于 99。最大和为 198。

使用aas

该程序将减去从键盘输入的几个 2 位数字。每个数字都存储在其自己的字节大小的寄存器中。对于第一个数字是BH(十)和BL(一)。对于第二个数字,它是CH(十)和CL(个)。

级联减法的第一步是减去“一”。如果此减法的结果超出范围 [0,9],我们将不得不调整值并将借位 1 传播到下一步。aas指令进行此调整。

    mov     al, bl
    sub     al, cl          ; Ones
    aas                     ; -> AL CF
    mov     bl, al

级联减法的第二步是从上一步中减去“十”借位。因此,我们将使用sbb而不是sub. 此减法的结果将在 [0,9] 范围内,因为最大差值为 99。

    sbb     bh, ch          ; Tens

该程序的 .COM 版本 (FASM):

        ORG     256

start:
        mov     dx, startMsg
        mov     ah, 09h         ; DOS.PrintString
        int     21h
        mov     ah, 01h         ; DOS.GetCharacter
        int     21h             ; -> AL
        cmp     al, '1'
        je      addition
        cmp     al, '2'
        je      subtraction
        cmp     al, '3'
        je      exit
        jmp     errorOccured

exit:
        mov     ax, 4C00h       ; DOS.Terminate
        int     21h

addition:
        call    GetNumbers      ; -> BX is 1st number, CX is 2nd number (AX DX)
        mov     dx, sumMsg
        mov     ah, 09h         ; DOS.PrintString
        int     21h

        mov     al, bl
        add     al, cl          ; Ones
        aaa
        mov     bl, al
        mov     al, bh
        adc     al, ch          ; Tens
        aaa
        mov     bh, al

        jnc     additionBelow100
        mov     dl, "1"         ; Hundreds
        mov     ah, 02h         ; DOS.PrintCharacter
        int     21h
additionBelow100:
ShowTwoDigits:
        mov     ah, 02h         ; DOS.PrintCharacter
        or      bx, 3030h       ; Convert to characters
        mov     dl, bh          ; Tens
        int     21h
        mov     dl, bl          ; Ones
        int     21h
        jmp     start

subtraction:
        call    GetNumbers      ; -> BX is 1st number, CX is 2nd number (AX DX)
        mov     dx, subMsg
        mov     ah, 09h         ; DOS.PrintString
        int     21h

        cmp     bx, cx
        jae     subtractionPos

        xchg    bx, cx          ; Swap if 1st number < 2nd number
        mov     dl, "-"         ; ... and display negative sign
        mov     ah, 02h         ; DOS.PrintCharacter
        int     21h

subtractionPos:
        mov     al, bl
        sub     al, cl          ; Ones
        aas
        mov     bl, al
        sbb     bh, ch          ; Tens
        jmp     ShowTwoDigits

; ------------------------------

; IN () OUT (bx,cx) MOD (ax,dx)
GetNumbers:
        mov     dx, integer1Msg
        call    GetNumber       ; -> DX (AX)
        mov     bx, dx
        mov     dx, integer2Msg
        call    GetNumber       ; -> DX (AX)
        mov     cx, dx
        ret

; IN (dx) OUT (dx) MOD (ax)
GetNumber:
        mov     ah, 09h         ; DOS.PrintString
        int     21h
        call    GetDigit        ; -> AL (AH)
        mov     dh, al          ; Tens
        call    GetDigit        ; -> AL (AH)
        mov     dl, al          ; Ones
        ret

; IN () OUT (al) MOD (ah)
GetDigit:
        mov     ah, 01h         ; DOS.GetCharacter
        int     21h             ; -> AL
        sub     al, "0"
        cmp     al, 9
        ja      errorOccured
        ret

errorOccured:
        mov     dx, errorOccuredMsg
        mov     ah, 09h         ; DOS.PrintString
        int     21h
        jmp     start


startMsg:        DB 13,10,'1.) Add ',10,'2.) Subtract',10,'3.) Exit',10,10
                 DB 'Select a function: $'
integer1Msg:     DB 13,10,10,'Enter the first integer: $'
integer2Msg:     DB 13,10,'Enter the second integer: $'
errorOccuredMsg: DB 13,10,13,10,'An error occured, please try again! $'

sumMsg:          DB 13,10,10,'The sum is: $'
subMsg:          DB 13,10,10,'The difference is: $'

使用daa

该程序将添加几个从键盘输入的 2 位数字。十位存储在相同字节大小的寄存器的高半字节中,个位数字存储在低半字节中。第一个数字是BL,第二个数字是CL

添加这些压缩数字后,我们使用daa指令调整结果,使其保持表示压缩数字。

mov     al, bl
add     al, cl
daa                     ; -> AL CF

接下来我们显示一个“1”,但前提是使用 有进位daa。这表明加法的结果大于 99。最大和为 198。

使用das

该程序将减去从键盘输入的几个 2 位数字。十位存储在相同字节大小的寄存器的高半字节中,个位数字存储在低半字节中。第一个数字是BL,第二个数字是CL

在减去这些压缩数字之后,我们使用das指令来调整结果,使其保持表示压缩数字。

mov     al, bl
sub     al, cl
das                     ; -> AL CF=0

此减法的结果将在 [0,99] 范围内,因为最大差值为 99。

该程序的 .COM 版本 (FASM):

        ORG     256

start:
        mov     dx, startMsg
        mov     ah, 09h         ; DOS.PrintString
        int     21h
        mov     ah, 01h         ; DOS.GetCharacter
        int     21h             ; -> AL
        cmp     al, '1'
        je      addition
        cmp     al, '2'
        je      subtraction
        cmp     al, '3'
        je      exit
        jmp     errorOccured

exit:
        mov     ax, 4C00h       ; DOS.Terminate
        int     21h

addition:
        call    GetNumbers      ; -> BL is 1st number, CL is 2nd number (AX DX)
        mov     dx, sumMsg
        mov     ah, 09h         ; DOS.PrintString
        int     21h

        mov     al, bl
        add     al, cl
        daa
        jnc     additionBelow100
        push    ax              ; (1)
        mov     dl, "1"         ; Hundreds
        mov     ah, 02h         ; DOS.PrintCharacter
        int     21h
        pop     ax              ; (1)
additionBelow100:
ShowPackedDigits:
        aam     16              ; -> AH is Tens, AL is Ones
        add     ax, 3030h       ; Convert to characters
        xchg    bx, ax
        mov     dl, bh          ; Tens
        mov     ah, 02h         ; DOS.PrintCharacter
        int     21h
        mov     dl, bl          ; Ones
        int     21h
        jmp     start

subtraction:
        call    GetNumbers      ; -> BL is 1st number, CL is 2nd number (AX DX)
        mov     dx, subMsg
        mov     ah, 09h         ; DOS.PrintString
        int     21h

        cmp     bl, cl
        jae     subtractionPos

        xchg    bl, cl          ; Swap if 1st number < 2nd number
        mov     dl, "-"         ; ... and display negative sign
        mov     ah, 02h         ; DOS.PrintCharacter
        int     21h

subtractionPos:
        mov     al, bl
        sub     al, cl
        das
        jmp     ShowPackedDigits

; ------------------------------

; IN () OUT (bl,cl) MOD (ax,dx)
GetNumbers:
        mov     dx, integer1Msg
        call    GetNumber       ; -> AX (DL)
        mov     bl, al
        mov     dx, integer2Msg
        call    GetNumber       ; -> AX (DL)
        mov     cl, al
        ret

; IN (dx) OUT (ax) MOD (dl)
GetNumber:
        mov     ah, 09h         ; DOS.PrintString
        int     21h
        call    GetDigit        ; -> AL (AH)
        mov     dl, al          ; Tens
        call    GetDigit        ; -> AL (AH)
        mov     ah, dl
        aad     16              ; AX = (TensFromAH * 16) + OnesFromAL
        ret

; IN () OUT (al) MOD (ah)
GetDigit:
        mov     ah, 01h         ; DOS.GetCharacter
        int     21h             ; -> AL
        sub     al, "0"
        cmp     al, 9
        ja      errorOccured
        ret

errorOccured:
        mov     dx, errorOccuredMsg
        mov     ah, 09h         ; DOS.PrintString
        int     21h
        jmp     start


startMsg:        DB 13,10,'1.) Add ',10,'2.) Subtract',10,'3.) Exit',10,10
                 DB 'Select a function: $'
integer1Msg:     DB 13,10,10,'Enter the first integer: $'
integer2Msg:     DB 13,10,'Enter the second integer: $'
errorOccuredMsg: DB 13,10,13,10,'An error occured, please try again! $'

sumMsg:          DB 13,10,10,'The sum is: $'
subMsg:          DB 13,10,10,'The difference is: $'

该程序使用aad 16指令来组合寄存器中的十位和个位AL(用于存储):

aad                     ; AH = 0, AL = (AH * 10) + AL
aad     16              ; AH = 0, AL = (AH * 16) + AL

该程序使用该aam 16指令将两个半字节与AL寄存器分开(用于打印):

aam                     ; AH = AL / 10, AL = AL mod 10
aam     16              ; AH = AL / 16, AL = AL mod 16

这两个程序都在 DOSBox 中进行了测试并且运行良好。

于 2022-02-02T22:24:29.633 回答