装配 - 添加2个数字作为输入

时间:2017-05-02 17:11:20

标签: assembly x86-16 dos

需要编写一个程序,该程序将两个数字作为输入并打印它们的总和。不知道我在哪里出错了。我觉得这个部门可能有点时髦,但我真的在努力解决为什么我的输出不正确。防爆。输出:输入10和11 - 输出22.我感谢任何帮助!

       .model small
;-----------------------------------------------------
        .stack  64
;-----------------------------------------------------  
        .data
PR      DB      'ENTER: ','$'
Num1    Label   Byte
Max1    DB      3 ; need to hit atmost 3 keys when entering- 2 digits and the enter key
Act1    Db      ?
N1      DB      4 DUP ('$')
Num2    Label   Byte
Max2    DB      3 ; need to hit atmost 3 keys when entering- 2 digits and the enter key
Act2    Db      ?
N2      DB      4 DUP ('$')
Hold    DW      ?
Res     DB      3 DUP ('$')
msg     Db      " Result is $"
;-----------------------------------------------------
        .code
MAIN    proc    FAR
        mov     AX,@data        ; Initialize segment
        mov     DS,AX           ; registers

        call    CLEAR
        call    SET_CURSOR
        call    REQUEST_INPUT
        call    GET_INPUT1
        call    SET_CURSOR2
        call    REQUEST_INPUT
        call    GET_INPUT2
        call    SET_CURSOR3
        call        Convert


        mov     AX,4C00h        ; Exit to DOS
        int     21h
MAIN    endp
;-----------------------------------------------------
CLEAR   proc    NEAR
        mov     AX, 0600H
        mov     BH, 71H
        mov     CX, 0000H
        mov     DX, 184FH
        int     10H
        ret
CLEAR   endp

;-----------------------------------------------------
SET_CURSOR      proc    NEAR
        mov     AH, 02H
        mov     BH, 0           ;sets color of backround 
        mov     DH, 5
        mov     DL, 10
        int     10H
        ret
SET_CURSOR      endp
;-----------------------------------------------------
REQUEST_INPUT   proc    NEAR
        mov     AH, 09H
        lea     DX, PR
        int     21H 
        ret
REQUEST_INPUT   endp

;-----------------------------------------------------
GET_INPUT1       proc    NEAR
        mov     AH, 0AH
        lea     DX,Num1
        int     21H
        mov     BH, 00
        mov     BL, Max1
        mov     N1[BX],'$'
        ret
GET_INPUT1       endp
;-----------------------------------------------------
GET_INPUT2      proc    NEAR
        mov     AH, 0AH
        lea     DX,Num2
        int     21H
        mov     BH, 00
        mov     BL, Max2
        mov     N2[BX],'$'
        ret
GET_INPUT2       endp
;-----------------------------------------------------          
Convert         proc    NEAR
                mov     BX, 0
                    mov     AH, 00h
                mov     Al, N1[BX]   ; Get a character
                Sub Al, 48 ; to get decimel value from character 
                Mov Bx, 10
                Mul Bx                                                  
                mov Cl, Al ; Result of multiplication stored in Al
                 mov     BX, 1
                    mov     BH, 00h
                mov     Bl, N1[BX]   ; Get a character
                Sub BL, 48
                Add Cl, Bl ; Add first digit and second digit
                mov     BX, 0
                    mov     CH, 00h
                mov     Al, N2[BX]   ; Get a character
                    Sub Al, 48 ; to get decimel value from character
                Mov Bx, 10
                Mul Bx                                      
                Mov Bl, Al ; Result of multiplication stored in Al
                 mov     BX, 1
                    mov     BH, 00h
                mov     AL, N2[BX]   ; Get a character
                Sub Al, 48 ;to get decimel value from character 
                Add Al, Bl ; Add first and second digit
                Add Cl, Al ; Add number one and number two
                Mov Ah, 0; zero out ah before devision 
                Mov Al, Cl
                Mov Cl, 10 
                Div Cl

                Add Al, 48  ;Value of int devision 
                Mov Res[0], Al
                Add AH, 48 ;value of remainder 
                Mov Res[1], AH              
                mov     AH,09h
                lea     DX, msg
                int     21H
                mov     AH,09h
                lea     DX, Res
                int     21H
                ret

Convert         endp                
;-----------------------------------------------------
SET_CURSOR2      proc    NEAR
        mov     AH, 02H
        mov     BH, 0           ;sets color of backround 
        mov     DH, 6
        mov     DL, 10
        int     10H
        ret
SET_CURSOR2     endp
;-----------------------------------------------------  
SET_CURSOR3      proc    NEAR
        mov     AH, 02H
        mov     BH, 0           ;sets color of backround 
        mov     DH, 7
        mov     DL, 10
        int     10H
        ret
SET_CURSOR3      endp                   
;------------------------------------------------------------           




            ;formula ()N1[0]-48)*10 + (N1[1]-48)
            ;same for N2
            ;before printing need to divide result of N1+N2 by 10. the quation is the frist character remainder is the second character- quaotiant will be in AL, Remainder in AH
            ;then need to add 48 before putting them into the array Res
            ;To go back Add Al,48-Mov Res[0], AL


;-----------------------------------------------------------'
                end     MAIN

1 个答案:

答案 0 :(得分:2)

8086在您的代码中重复使用了3个以上的寄存器axbxcx

虽然您的代码正在执行大量不必要的值重置,但您设法避免任何冲突,直到Mov Bl, Al(存储N2 [0] * 10的结果),然后mov bx,1覆盖这个值。

如果你使用调试器,你可能会注意到你失去了价值。

如果你知道,你将访问例如N2 [1],不要打扰bx,只需写mov al,[N2+1]

如果您执行mul bx,那么您正在执行dx:ax = bx * ax(如果您不确定它是如何工作的,请经常documentation查看说明),在您的2位数字的特殊情况下乘以10,你可以设置al(0-9值)并执行mul bl(10),这会将结果放入ax(0-90值),清除上限8位ax为你。

如果我已经通过尝试只做不可避免的事情来解决清理代码问题,那么如何完全删除一个mul

如果你有数字x,y存储为x 1 ,x 0 和y 1 ,y 0 ,其中n =Σn i * 10 i ,则:
x +y⇔x 1 * 10 + x 0 * 1 + y 1 * 10 + y 0 * 1⇔
⇔10*(x 1 + y 1 )+(x 0 + y 0

所以在你的代码中你可以这样做:

mov al,[N1+0]  ; ASCII x1
add al,[N2+0]  ; ASCII y1 (no real overflow risk, 8b is enough)
sub al,2*'0'   ; convert from ASCII to value
mov ah,10
mul ah         ; ax = 10 * (x1+y1) (value is 0 to 180)
add al,[N1+1]  ; add ASCII x0 (48-57 value)
add al,[N2+1]  ; add ASCII y0
; max possible AL value = 180 + 57 + 57 = 294
; -> may overflow, but doesn't matter, conversion will "fix" it
sub al,2*'0'   ; convert x0,y0 from ASCII to values
; will "fix" overflow by ignoring AH all the time, keeping it 0
; ax = result here (0 to 188 value = fits to 8 bits)

因为2位输入约束(这远远不是通用的加法例程,实际上使用了该约束的每一位),因此可以仅使用Convert PROC来编写ax LEA保持代码非常简单和简短。)

BTW,如果你要使用386+(32位)指令集,那么* 10可以使用; eax = 0-9 value add eax,eax ; *2 lea eax,[eax+eax*4] ; *5 指令在两条指令中完成,如下所示:

mul

这完全避免了imul eax,eax,10,这曾经很慢......最新的x86 CPU实际上做add可能会更快,因为它的单指令与两个简单指令相比,但多年来,这两个新成员(leamul)更便宜了#34;而不是单imul / ; al = 0-9 value add al,al ; AL = 2*value mov dl,al ; copy 2*value to DL add al,al ; AL = 4*value add al,al ; AL = 8*value add al,dl ; AL = 10*value

在最初的8086上,完成所有这样的添加仍然会更快:

mul bl

export class MyDirective { constructor($interval) { 'ngInject'; this.template = '<div id=chart></div>'; this.restrict = 'E'; this.scope = {} this.$interval = $interval; } compile(tElement) { tElement.css('position', 'absolute'); } link(scope, element) { this.$interval(() => this.chart(), 1000); } chart() { c3.generate({ bindto: '#chart', data:{ columns: [ ['data1', 30, 200, 100, 400, 150, 250], ['data2', 130, 100, 140, 200, 150, 50] ], type: 'bar' }, bar: { width: { ratio: 0.5 // this makes bar width 50% of length between ticks } // or //width: 100 // this makes bar width 100px } }); } } ,在原始8086上需要大约70-77个时钟计算,上面的代码只需要原始8086上的4 * 3 + 2 = 14个时钟。