输入两个数字并在NASM上相乘和除以它们

时间:2018-04-09 01:26:11

标签: assembly nasm dosbox

大家晚上好。我一直在研究这个代码,用户将输入两个数字,然后将它们相乘并分割并显示结果。我正在使用程序来分离进程。我的问题是:不知何故,如果我只进行乘法,程序将结束,一切都将清晰。如果我调用这两个程序,程序似乎在乘法调用后保持不变,并且不再继续。 (比如说10和2.期望乘法是20,商5是0剩余,或12和5,其中乘法是60,除法是2余数2)也许我的逻辑可能是错误的或我的程序调用错了但我想问是否有人可以借给我另一双眼睛,这样我就可以知道我的错误可能在哪里。谢谢!

这是在DosBox 0.74

上为NASM完成的
;            Input: Requests two integers from the user.
;           Output: Outputs the multiplication and division of the input integers.

%include "io.mac"
.STACK 100H
.DATA
     prompt_msg1  db   "Please input the first number: ",0
     prompt_msg2  db   "Please input second number: ",0
     mul_msg      db   "multiplication N1 * N2 is: ",0
     div_msg      db   "Division N1/N2 is: ", 0
     rem_msg      db   "Remainder N1/N2 is: ", 0

.CODE
      .STARTUP
      PutStr  prompt_msg1    ; request first number
      GetInt  CX             ; CX = first number
      nwln

      PutStr  prompt_msg2    ; request second number
      GetInt  DX             ; DX = second number
      nwln


      ;multiplication call
      call multi             ; returns multiplication in BX
      PutStr mul_msg         ; display multiplication message
      PutInt AX              ; display multiplication result


      ;division call
      call divis             ; returns division in BX
      PutStr div_msg         ; display Division message
      PutInt BX              ; display quotient result
      nwln
      PutStr rem_msg         ; display remainder message
      PutInt DX              ; display remainder result

done:
      .EXIT

multi:
      mov      AX, CX       ; imul= first number
      imul     AX, DX       ; imul = imul * second number
      ret                   ; return 

divis:      
      mov      BX, CX
      div      DX           ; idiv = first number / second number
      ret                   ; return 

更新:

我能够使用社区提供的修复和建议来运行代码,感谢您的所有帮助,这里是更新并运行的代码:

;            Input: Requests two integers from the user.
;           Output: Outputs the multiplication and division of the input integers.

%include "io.mac"
.STACK 100H
.DATA
     prompt_msg1  db   "Please input the first number: ",0
     prompt_msg2  db   "Please input second number: ",0
     mul_msg      db   "multiplication N1 * N2 is: ",0
     div_msg      db   "Division N1/N2 is: ", 0
     rem_msg      db   "Remainder N1/N2 is: ", 0

.CODE
      .STARTUP
      PutStr  prompt_msg1    ; request first number
      GetInt  CX             ; CX = first number
      nwln

      PutStr  prompt_msg2    ; request second number
      GetInt  DX             ; DX = second number
      nwln


      ;multiplication call
      call multi             ; returns multiplication in BX
      PutStr mul_msg         ; display multiplication message
      PutInt AX              ; display multiplication result


      ;division call
      call divis             ; returns division in BX
      PutStr div_msg         ; display Division message
      PutInt AX              ; display quotient result
      nwln
      PutStr rem_msg         ; display remainder message
      PutInt DX              ; display remainder result

done:
      .EXIT

multi:
      mov      AX, CX       ; imul= first number
      imul     AX, DX       ; imul = imul * second number
      ret                   ; return and clear parameters

divis:      
      mov      BX, DX
      mov      AX, CX
      cwd
      idiv     BX           ; idiv = first number / second number
      ret                   ; return and clear parameters

2 个答案:

答案 0 :(得分:2)

div DX一定会失败。

正如您在英特尔手册中所看到的那样:

  

DIV
  由r / m16签名除以DX:AX,结果存储在AX←商,DX←剩余。

进一步向下:

  

temp←DX:AX / SRC; (*签名师*)
  IF(temp> 7FFFH)或(temp <8000H)
  (*如果阳性结果大于7FFFH
  或者否定结果小于8000H *)
  THEN
  #DE; (*除错*)

也就是说,DIV r16实际上会将DXAX形成的双字划分为r16,且商必须符合一个单词,否则您将得到一个划分错误。

DX:AX / DX会为您提供0x1nnnn的商数,但不适合单词。

因此,您需要为除数使用不同的寄存器,并且还应使用CWD将被除数符号扩展为DX:AX。例如:

mov bx,dx
cwd
div bx

答案 1 :(得分:1)

第一个数字位于CX。第二个数字位于DX

divis 除法子程序有3个问题。

  • 当您将第一个号码(CX)放入累加器BX时,会将其带到AX
  • 由于字大小除法实际上将DX:AX除以操作数,因此您需要事先初始化DX
  • 现在,这会带来DX无法同时满足这两个目的(分隔线和扩展分红)的问题。

您可以通过以下方式解决这些问题:

mov  bx, dx   ;Divider (2nd number) to BX
mov  ax, cx   ;Dividend (1st number) to AX
cwd           ;Extend dividend in DX:AX
idiv bx       ;Signed division -> Quotient AX, Remainder DX
PutInt BX              ; display quotient result

为了显示商,你需要写

PutInt AX

来自评论

  

根据我的说明,我知道一旦进行了分割,剩余部分将被存储在较小尺寸的寄存器中(假设AX被DX分割,则quoutient将保留在AX中,但剩下的将是存储在例如AL或AH上)是我的理由还是可能我错了?

根据除数的大小,除法有多种方式。对于股息,你没有自由选择。这总是将成为累加器或累加器及其扩展。

  • 字节除法:将字大小的被除数(总是AX)除以任何字节大小的除数

    div bl   ; Divides AX by BL
    
  • 分词:将双倍大小的红利(总是DX:AX)除以任何单词大小的除数

    div cx   ; Divides DX:AX by CX
    
  • Dword division :将qword大小的红利(始终为EDX:EAX)除以任何双倍大小的除数

    div esi  ; Divides EDX:EAX by ESI
    

商总是在红利的下半部分返回。

  • 字节分割AX的下半部分为AL

  • 分词DX:AX的下半部分为AX

  • Dword division EDX:EAX的下半部分为EAX

余额总是在红利的上半部分返回。

  • 字节分割AX的上半部分为AH

  • 分词DX:AX的上半部分为DX

  • Dword division EDX:EAX的上半部分为EDX