首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >汇编x8086 (emu8086) -在屏幕上显示32位数字

汇编x8086 (emu8086) -在屏幕上显示32位数字
EN

Code Review用户
提问于 2017-03-16 12:14:47
回答 3查看 4.3K关注 0票数 4

这是我的代码(程序集x8086,而不是MIPS,我正在使用emu8086)在屏幕上显示32位数字。当然,基本算法如下:

代码语言:javascript
复制
Input: Number
Set r=0,q=Number,counter=0;
while q > 0 do
divide q by 10
q <- Quotidient, r <- Remainder;
push r;
counter = counter + 1;
end while

while counter > 0 do
pop r;
counter = counter - 1;
display
end while

但是问题是,在x8086处理器上,所有寄存器都是16位的.因此,使用div命令进行32位数的除法没有简单的方法(实际上有一些解决方案,但我发现它们很复杂)。因此,我决定分别处理32位数字的高低部分:

代码语言:javascript
复制
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.

这是我的代码,请给我一些关于美学,代码优化,.非常感谢:

代码语言:javascript
复制
;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
EN

回答 3

Code Review用户

发布于 2017-03-19 22:14:13

让我们首先关注16位版本。

  • 选择时间循环并不是最好的选择。您知道需要至少打印一个字符(即使输入为0),所以重复直到循环更好。这也避免了在开始用DOS输出之前检查CX是否为零。
  • 为什么首先要将剩余部分移动到另一个寄存器,而您只想将其推到堆栈上呢?
  • 在另一个寄存器中来回移动商数也是没有意义的。
  • 当将余数转换为字符(通过添加30h)时,这样做的时间会更短,而余数仍在AL寄存器中。我不会在下面的代码中使用它,因为直接在DX寄存器中弹出更短一些。
  • 清除寄存器最好是用xor自己来完成。
  • 可以通过将寄存器与零进行比较来检查寄存器是否为空,但更短的方法是将寄存器与其自身进行test,然后决定零标志(ZF)的状态。

所有这些加在一起:

代码语言:javascript
复制
    mov  ax, var_32bits_low
    xor  cx, cx   
repeat_loop:
    xor  dx, dx
    div  base_10
    push dx                 ;push remainder
    inc  cx                 ;counter = counter + 1
    test ax, ax
    jnz  repeat_loop 
print_char:
    pop  dx
    add  dl, 30h            ;0 -> '0', 1 ->'1',...
    mov  ah, 02h            ;DOS.PrintChar
    int  21h
    loop print_char

请注意,编写尾注释而不是全行注释可以提供更清晰、更易读的代码。此外,装配编程中的所有内容都是对齐。非常非常重要!

var_32bits_high dw 0 var_32bits_low dw 0 quotidient_32bits_high dw 0 quotidient_32bits_low dw 0 negate_mask equ 0FFFFFh lowest_signed_32bits_high dw 8000 H lowest_signed_32bits_low dw 00h lowest_signed_32bits_string dw "-2147483648$“

以下是以下几点意见,只需看一下这个项目的这一小部分:

  • 对齐!
  • 将等价物与数据定义区分开来就更清楚了。
  • 虽然高变量和低变量是分开使用的,但遵循小endianess的惯例并将低单词存储在高单词之前仍然是个好主意。
  • 您的lowest_signed_32bits_string需要使用db而不是dw来定义。这是个错误。

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

如前所述,使用xor reg, reg清除寄存器。

此外,您可以直接将内存与直接内存进行比较,不需要使用寄存器进行比较。

如果你写了(短)16位版本之上的(长)32位版本,条件跳转可以很容易地达到32位版本。

代码语言:javascript
复制
    xor  ax, ax
    xor  bx, bx             ;bx: quotidient_32bits_high    
    xor  dx, dx             ;dx: quotidient_32bits_low  
    xor  cx, cx             ;counter = 0  
    cmp  var_32bits_high, 0 ;16bits or 32bits ?
    jne  _32bits_routine
_16bits_routine:
    ...
_32bits_routine:
    ...

您会同意,关于16位版本的很多内容也适用于32位版本。老实说,我发现它在评论上太缺乏了,所以我不太愿意对它进行彻底的审查。不过,我将指出下一个优化:

;;;和否定数mov ax,var_32bits_high xor ax,negate_mask mov var_32bits_high,ax

因为negate_mask只是0FFFFFFh,所以这段代码可以编写成一个简单的not

代码语言:javascript
复制
not  var_32bits_high

在这里,您只想在前面的操作有进位时增加qhigh变量

jnc label1 mov ax,qhigh inc ax mov qhigh,ax label1:

使用AddWithCarry adc指令编写这个非常简单的代码:

代码语言:javascript
复制
    adc  qhigh, 0
票数 5
EN

Code Review用户

发布于 2017-03-22 05:20:19

这是罗兰工作的直接翻译(java -> asm)。为了清晰起见,我没有做任何努力来优化(尽管有巨大的诱惑)。注释是相关的java行。

请注意,尽管我很担心,但这确实正确地工作了:

代码语言:javascript
复制
; using 123456789 aka 75B CD15
mov dx, 075bh
mov ax, 0cd15h

; input:
;   dx:ax = number to be divided by 10
; output:
;   dx:ax = old dx:ax div 10
;   bx = remainder
;   cx, si, di, flags undefined

; cx = 10;
mov cx, 10

; si = dx;
mov si, dx

; di = (short) ((ax >> 8) & 0xff);
mov di, ax
shr di, 8
and di, 0ffh

; bx = (short) (ax & 0xff);
mov bx, ax
and bx, 0ffh

; dx = 0;
mov dx, 0

; ax = si;
mov ax, si

; udiv_cx();
div cx

; si = ax;
mov si, ax

; ax = (short) (((dx & 0xff) << 8) | di);
mov ax, dx
and ax, 0ffh
shl ax, 8
or ax, di

; dx = 0;
mov dx, 0

; udiv_cx();
div cx

; di = ax;
mov di, ax

; ax = (short) (((dx & 0xff) << 8) | bx);
mov ax, dx
and ax, 0ffh
shl ax, 8
or ax, bx

; dx = 0;
mov dx, 0

; udiv_cx();
div cx

; cx = ax;
mov cx, ax

; bx = dx;
mov bx, dx

; dx = si;
mov dx, si

; ax = di;
mov ax, di

; ax <<= 8;
shl ax, 8

; ax |= cx;
or ax, cx

在输出方面,dx:ax是BC614E(又名12345678),正如承诺的那样。我没有对此进行广泛的测试,但这似乎是有道理的。既然我有了翻译,我就想和大家分享。

票数 1
EN

Code Review用户

发布于 2017-03-19 23:42:59

在我看来,代码看起来太长了。因此,我实现了一个不同的算法。我用Java编写了它,但是将它转换成8086程序集应该是很简单的。

代码语言:javascript
复制
public class Div32 {

    short ax, bx, cx, dx, si, di;

    // input:
    //   dx:ax = number to be divided by 10
    // output:
    //   dx:ax = old dx:ax div 10
    //   bx = remainder
    //   cx, si, di, flags undefined
    void udiv32_10() {
        cx = 10;

        si = dx;
        di = (short) ((ax >> 8) & 0xff);
        bx = (short) (ax & 0xff);

        dx = 0;
        ax = si;
        udiv_cx();
        si = ax;

        ax = (short) (((dx & 0xff) << 8) | di);
        dx = 0;
        udiv_cx();
        di = ax;

        ax = (short) (((dx & 0xff) << 8) | bx);
        dx = 0;
        udiv_cx();
        cx = ax;

        bx = dx;
        dx = si;
        ax = di;
        ax <<= 8;
        ax |= cx;
    }

    // emulates the 8086 "udiv cx" instruction, ignoring overflow,
    // since that cannot happen in this program
    void udiv_cx() {
        int x = (dx & 0xffff) << 16 | (ax & 0xffff);
        ax = (short) (x / cx);
        dx = (short) (x % cx);
    }

    void print32() {
        byte[] out = new byte[20]; // to be allocated on the call stack
        int outptr = 20;
        out[--outptr] = '其基本思想是提供一个做32位除法的函数.在那之后,剩下的就变得简单了。要计算aa:bb:cc:dd / 10,代码如下:t1    = aa:bb % 10
aa:bb = aa:bb / 10
t2    = t1:cc % 10
cc    = t1:cc / 10
rem   = t2:dd % 10
dd    = t2:dd / 10; // string terminator for int 21h, function 09h
        do {
            udiv32_10();
            out[--outptr] = (byte) ((bx & 0xff) + '0');
        } while (ax != 0);
        System.out.println(new String(out, outptr, 20 - outptr));
    }

    void testPrint() {
        int x = 123456789;
        dx = (short) (x >> 16);
        ax = (short) (x & 0xffff);
        print32();
    }

    public static void main(String[] args) {
        new Div32().testPrint();
    }
}

其基本思想是提供一个做32位除法的函数.在那之后,剩下的就变得简单了。

要计算aa:bb:cc:dd / 10,代码如下:

A1

票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/157926

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档