Print decimal in 8086 emulator

前端 未结 3 1810
感动是毒
感动是毒 2020-12-04 04:23

I implemented the multiplication of two big integer in emu8086 with code as below :

; MULTIPLY N1 * N2 = RES
MULTIPLY PROC
    MOV BH, 0H                


        
相关标签:
3条回答
  • 2020-12-04 04:34

    Unfortunately, converting a value to decimal is not as simple as converting it to hexadecimal. This is because base-10 is not a related base of base-2 (i.e. 10 is not a power of 2). We need to use modulus and division to achieve the conversion. The general algorithm in C would look something like this :

    unsigned int val = 58932; // assume int is 32-bit
    char buf[11] = { 0 }, *chr = buf+9; // 11 characters is enough because log10(2^32) = 9,63, +1 for \0
    do
    {
        *chr = (val % 10) + '0'; // to ascii
        --chr;
    } while((val /= 10) != 0);
    ++chr;
    

    Upon completion, chr will point to a null-terminated char* array which will hold the ASCII representation of the base-10 value of val.

    You can achieve it in assembly with the DIV instruction. Most optimizing C compilers optimize it out to a multiplication operation, which is much faster than division (it can be done only if the divisor is constant, though).

    0 讨论(0)
  • 2020-12-04 04:37

    I solved my problem with changing my code as below :

    NORMALIZE PROC
        MOV CH, 0H
        MOV CL, L1
        ADD CL, L2
        DEC CX
    
        NOMRALIZE_LOOP:
            MOV BX, CX
            DEC BX
            MOV AL, RES[BX]
            MOV AH, 1H
            MUL AH
            AAM            
            MOV RES[BX], AL
            ADD RES[BX-1], AH
        LOOP NOMRALIZE_LOOP
        RET
    NORMALIZE ENDP
    
    ; MULTIPLY N1 * N2 = RES
    MULTIPLY PROC
        MOV CH, 0H
        MOV CL, L1
    
        MOV AL, '0'
    
        MOV BH, 0H
    
        SUB_N1:
            MOV BL, CL 
            DEC BL
            SUB N1[BX], AL
        LOOP SUB_N1
    
        MOV CL, L2
    
        SUB_N2:
            MOV BL, CL
            DEC BL
            SUB N2[BX], AL
        LOOP SUB_N2
    
        MOV CH, 0H
        MOV CL, L1
    
        MUL_1:
            MOV COUNTER, CL
            MOV CL, L2  
    
            MUL_2:
                MOV BH, 0H
                MOV BL, COUNTER
                DEC BL
                MOV AL, N1[BX]
    
                MOV BL, CL
                DEC BL
    
                MUL N2[BX]
    
                AAM
    
                MOV BH, 0H
                MOV BL, COUNTER
                ADD BX, CX
                DEC BX
                DEC BX
    
                ADD RES[BX], AL
                ADC RES[BX-1], AH
                ADC RES[BX-2], 0H
            LOOP MUL_2     
    
            MOV CL, COUNTER
        LOOP MUL_1
    
        RET
    MULTIPLY ENDP
    

    I changed the multiplication and storing numbers with AAM function. At the end, i add NORMALIZE function to convert result to decimal. :)

    Hope others can use it :)

    0 讨论(0)
  • 2020-12-04 04:47

    UPDATE: I previously posted a way to print only a 16-bits number, but now I have found a way to print 32-bits number as well, so I decided to delete the previous solution. Here is the general idea: - Check if the number is negative or positive - If it's negative, negate it using two's complement. But we must take care of a corner case: a signed 32-bits number goes from -2^31 to 2^31-1 so we can see that there is no positive equivalent of -2^31. So we must single out this case and store the corresponding number (in string format) and print it - If it's positive, then we repeatedly divide by 10, take the remainder, push it onto the stack, afterwards pop back and print each number consecutively (this is easy since Assembly x8086 has provided the appropriate routines) By the way, in my code I also checked if the 16-bit upper part is zero, then go to the _16bits_routine, which is based on the same principle. However, dividing by 10 is not trivial in 32-bits since the div function does not support it, so here's what I do:

    Let A be the number in question, we now divide by 10:
    A = q*10 + r (0 <= r <= 9)
    now separate A into the high and low parts:
    A_high * 2^16 + A_low = q*10 + r (0 <= r <= 9)
    our task is to find q and r. To do that we first divide the high part:
    A_high = q_high * 10 + r_high (0<= r_high <= 9)
    => A_high * 2^16 = (q_high*2^16)*10 + r_high * 2^16 . Note that r_high is from 0 to 9, so to divide r_high * 2^16 by 10, we simply need to perform the calculations and then store the results in a lookup table! The result:
    r_high * 2^16 = q_high_redundant * 10 + r_high_redundant (0 <= r_high_redundant <= 9) (found by using a lookup table) (an interesting note: q_high_redundant is only 16 bits!)
    Now divide the low part:
    A_low = q_low * 10 + r_low
    => A = A_high * 2^16 + A_low = (q_high*2^16 + q_low + q_high_redundant)*10 + r_low + r_high_redundant
    Now you just have to divide r_low + r_high_redundant and add in to the quotient, then you get the results.
    

    Here is the code, it's not terribly fast but not too slow, so I hope you find it useful:

    ;Written by Dang Manh Truong
    .stack      100h
    .data 
    base_10     dw      10     
    var_32bits_high     dw      0
    var_32bits_low     dw      0
    quotidient_32bits_high      dw      0
    quotidient_32bits_low       dw      0
    negate_mask         equ      0FFFFh  
    lowest_signed_32bits_high        dw     8000h
    lowest_signed_32bits_low         dw     0000h
    lowest_signed_32bits_string      dw     "-2147483648$"
    qhigh       dw      0
    rhigh       dw      0
    qlow        dw      0
    rlow        dw      0
    qhigh_redundant     dw      0
    rhigh_redundant     dw      0
    q_0         dw      0     
    qhigh0      equ     0h
    rhigh0      equ     0h
    qhigh1      equ     1999h
    rhigh1      equ     6h
    qhigh2      equ     3333h
    rhigh2      equ     2h
    qhigh3      equ     4CCCh
    rhigh3      equ     8h
    qhigh4      equ     6666h
    rhigh4      equ     4h
    qhigh5      equ     8000h
    rhigh5      equ     0h
    qhigh6      equ     9999h
    rhigh6      equ     6h
    qhigh7      equ     0B333h
    rhigh7      equ     2h
    qhigh8      equ     0CCCCh
    rhigh8      equ     8h
    qhigh9      equ     0E666h
    rhigh9      equ     4h   
    
    .code
    main        proc
    ;Initialization  
        mov     ax,@data
        mov     ds,ax     
    ;example: 7654321 = 0074CBB1h
    ;    mov     ax,74h
    ;    mov     var_32bits_high,ax
    ;    mov     ax,0CBB1h  
    ;    mov     var_32bits_low,ax  
    
    ;example: 10223803 = 009C0BBh
    ;    mov     ax,9Ch
    ;    mov     var_32bits_high,ax
    ;    mov     ax,0BBh
    ;    mov     var_32bits_low,ax
    
    ;example: 32763    
    ;    mov     ax,0h
    ;    mov     var_32bits_high,ax
    ;    mov     ax,32763
    ;    mov     var_32bits_low,ax   
    
    ;example: 86420 = 00015194h
    ;    mov     ax,1h
    ;    mov     var_32bits_high,ax
    ;    mov     ax,5194h
    ;    mov     var_32bits_low,ax   
    
    ;example: 2147483647 (2^31 - 1) = 7FFFFFFFh
    ;    mov     ax,7FFFh
    ;    mov     var_32bits_high,ax
    ;    mov     ax,0FFFFh
    ;    mov     var_32bits_low,ax   
    
    ;example: -2147483648 (-2^31)= 80000000h
    ;    mov     ax,8000h
    ;    mov     var_32bits_high,ax
    ;    mov     ax,0000h
    ;    mov     var_32bits_low,ax
    
    ;example: -1 = FFFF FFFFh
        mov     ax,0FFFFh
        mov     var_32bits_high,ax
        mov     ax,0FFFFh
        mov     var_32bits_low,ax    
    
        mov     ax,0
        mov     bx,0        ;bx: quotidient_32bits_high    
        mov     dx,0        ;dx: quotidient_32bits_low  
        mov     cx,0        ;counter = 0  
    ;16bits or 32bits ?
        mov     ax,var_32bits_high
        cmp     ax,0
        jne     _32bits_routine
        jmp     _16bits_routine
    
    ;;;        
    _32bits_routine:
        mov     cx,0
    ;if == -2147483648 (-2^31)   
        mov     ax,var_32bits_high
        cmp     ax,lowest_signed_32bits_high
        jne     check_if_neg
        mov     ax,var_32bits_low
        cmp     ax,lowest_signed_32bits_low
        jne     check_if_neg
    ;then 
        lea     dx,lowest_signed_32bits_string 
        mov     ah,9
        int     21h
        jmp     return_to_dos
    ;if < 0
    check_if_neg:
        mov     ax,var_32bits_high
        cmp     ax,0
        jnl      preparations
    ;then print "-" ...
        mov     ah,2
        mov     dl,'-'
        int     21h 
    ;... and negate number
        mov     ax,var_32bits_high 
        xor     ax,negate_mask
        mov     var_32bits_high,ax
        mov     ax,var_32bits_low
        xor     ax,negate_mask
        inc     ax  
        mov     var_32bits_low,ax
        jnc     preparations
        mov     ax,var_32bits_high
        inc     ax
        mov     var_32bits_high,ax           
    preparations:    
        mov     ax,var_32bits_high
        mov     quotidient_32bits_high,ax
        mov     ax,var_32bits_low
        mov     quotidient_32bits_low,ax
    while_32bits:
    ; while >0 do
        mov     ax,quotidient_32bits_high
        cmp     ax,0
        jne     div_high_part
        mov     ax,quotidient_32bits_low
        cmp     ax,0
        jne     div_high_part
        jmp     print_char    
    div_high_part:           
    ;divide high part
        mov     dx,0
        mov     ax,quotidient_32bits_high
        div     base_10
        mov     qhigh,ax
        mov     rhigh,dx
    ;case rhigh
        mov     ax,rhigh
        cmp     ax,0
        je      _rhigh0
        cmp     ax,1
        je      _rhigh1
        cmp     ax,2
        je      _rhigh2
        cmp     ax,3
        je      _rhigh3
        cmp     ax,4
        je      _rhigh4
        cmp     ax,5
        je      _rhigh5
        cmp     ax,6
        je      _rhigh6
        cmp     ax,7
        je      _rhigh7
        cmp     ax,8
        je      _rhigh8
        cmp     ax,9
        je      _rhigh9
    _rhigh0:
        mov     ax,qhigh0
        mov     qhigh_redundant,ax
        mov     ax,rhigh0
        mov     rhigh_redundant,ax
        jmp     _aftercase
    _rhigh1:
        mov     ax,qhigh1
        mov     qhigh_redundant,ax
        mov     ax,rhigh1
        mov     rhigh_redundant,ax
        jmp     _aftercase
    _rhigh2:
        mov     ax,qhigh2
        mov     qhigh_redundant,ax
        mov     ax,rhigh2
        mov     rhigh_redundant,ax    
        jmp     _aftercase
    _rhigh3:
        mov     ax,qhigh3
        mov     qhigh_redundant,ax
        mov     ax,rhigh3
        mov     rhigh_redundant,ax
        jmp     _aftercase
    _rhigh4:
        mov     ax,qhigh4
        mov     qhigh_redundant,ax
        mov     ax,rhigh4
        mov     rhigh_redundant,ax
        jmp     _aftercase
    _rhigh5:
        mov     ax,qhigh5
        mov     qhigh_redundant,ax
        mov     ax,rhigh5
        mov     rhigh_redundant,ax
        jmp     _aftercase
    _rhigh6:
        mov     ax,qhigh6
        mov     qhigh_redundant,ax
        mov     ax,rhigh6
        mov     rhigh_redundant,ax
        jmp     _aftercase
    _rhigh7:
        mov     ax,qhigh7
        mov     qhigh_redundant,ax
        mov     ax,rhigh7
        mov     rhigh_redundant,ax
        jmp     _aftercase
    _rhigh8:
        mov     ax,qhigh8
        mov     qhigh_redundant,ax
        mov     ax,rhigh8
        mov     rhigh_redundant,ax
        jmp     _aftercase
    _rhigh9:    
        mov     ax,qhigh9
        mov     qhigh_redundant,ax
        mov     ax,rhigh9
        mov     rhigh_redundant,ax
        jmp     _aftercase
    _aftercase:
    ;divide low part
        mov     ax,0
        mov     q_0,ax
        mov     dx,0
        mov     ax,quotidient_32bits_low
        div     base_10
        mov     qlow,ax
        mov     rlow,dx
        mov     ax,rlow
        add     ax,rhigh_redundant          
    ;if remainder >= 10 
        cmp     ax,base_10
        jl      after_if
        sub     ax,base_10
        mov     dx,1 
        mov     q_0,dx     
    after_if:
        mov     rlow,ax
        mov     ax,q_0
        add     ax,qlow
        mov     qlow,ax
        jnc     label1
        mov     ax,qhigh
        inc     ax
        mov     qhigh,ax     
    label1:    
        mov     ax,qlow
        add     ax,qhigh_redundant
        mov     qlow,ax
        jnc     label2
        mov     ax,qhigh
        inc     ax
        mov     qhigh,ax
    label2:    
    ;push remainder to stack    
        mov     ax,rlow
        push    ax     
        inc     cx
        mov     ax,qhigh
        mov     quotidient_32bits_high,ax
        mov     ax,qlow
        mov     quotidient_32bits_low,ax
        jmp     while_32bits
    
    ;;;        
    _16bits_routine:
        mov     ax,var_32bits_low
        mov     bx,0   ;bx: quotient 
        mov     cx,0   
    while_loop:
        cmp     ax,0
        je      print_char    
        mov     dx,0
        div     base_10
        mov     bx,ax ;ax stores quotidient  
        mov     ax,dx ;dx stores remainder
    ;push remainder
        push    ax  
    ;counter = counter + 1
        inc     cx       
    ;numerator = quotidient
        mov     ax,bx
        jmp     while_loop 
    print_char:
        cmp     cx,0
        je      return_to_dos
        pop     ax
    ;because at this point 0 <= ax <= 9, setting ah = 2 does not change the results
        mov     ah,2
        mov     dl,al
        add     dl,30h   ;0-> '0',1->'1',....
        int     21h
        dec     cx
        jmp     print_char
    
    return_to_dos:
        mov     ah,4ch
        int     21h
    main        endp
        end     main
    
    0 讨论(0)
提交回复
热议问题