100以下的倍数的TASM代码不显示输出

时间:2016-06-20 17:26:15

标签: assembly tasm

这就是代码的作用。假设用户输入数字20.它将其与计数器CX相乘,设置为1,并且每次迭代都会增加。当结果达到或超过100(数字20的4次迭代)时,它返回并通过推入并弹出到堆栈中打印所有这些。 添加每个数字,然后分成单个数字,然后使用02功能显示。

MOV CX, 01D
MOV AX, 0
MOV DX, BX ; BX contains the number 
MOV DI, 01 ;
MOV SI, 01 ;  used for addressing offsets of BX 


MULTIPLY: 
MOV AX, DX  
MUL CX
CMP AX, 100D
JGE FINISHED
MOV [BX+DI], AX
INC CX
INC DI ; will be changed to ADD DI, 2
JMP MULTIPLY

此代码段存在问题。我试图让它将输入乘以1,然后是2乘以3,依此类推,直到结果达到100.我在这里错过了什么?

2 个答案:

答案 0 :(得分:0)

代码中的一个问题:在标签multiply之前,您将输入数字存储在DX中:

MOV DX, BX ; BX contains the number

但在标签multiply之后使用mul,这会破坏DX。解决方案是使用另一个寄存器,例如BP,而不是DX。

另一个重要问题是您将倍数存储在[BX+DI]中,但BX所指向的数据段中没有变量。解决方案是创建一个数组(" buf")。

现在让我们将这两个解决方案应用到您的原始代码中,我添加了一个逗号来分隔数字,更改由箭头指向(;<===):

 .MODEL  SMALL
 .STACK  100H
 .DATA

  S1 DB 13,10, "Enter a number below 100  :" , '$' 
  S3 DB 13,10, "The multiples are: ", '$'
  buf dw 100 dup(?)    ;<=== ARRAY OF MULTIPLES.
  comma db ",$"        ;<=== SEPARATOR BETWEEN MULTIPLES ON SCREEN.

  .CODE
  MAIN PROC 
  MOV AX,@DATA
  MOV DS,AX

LEA DX, S1
MOV AH, 09 ; ENTER A NUMBER?
INT 21H

CALL INPUT ;ACCEPTS A NUMBER

LEA DX, S3
MOV AH, 09 ; THE MULTIPLES ARE:
INT 21H
MOV CX, 01D
MOV AX, 0
MOV bp, BX             ;<=== PRESERVE INPUT NUMBER IN BP.
mov di, offset buf     ;<=== DI POINTS TO ARRAY OF MULTIPLES.
;MOV DI, 01
;MOV SI, 01


MULTIPLY:  ;where the good stuff happens
MOV AX, BP            ;<=== MUL WILL CHANGE DX, THAT'S WHY WE USE BP.
MUL CX                ;AX*CX = RESULT IN DX:AX.
CMP AX, 100D
JGE FINISHED
MOV [di], AX           ;<=== STORE MULTIPLE IN ARRAY.
INC CX
;INC DI
add di,2               ;<=== EACH MULTIPLE IS TWO BYTES.
JMP MULTIPLY

FINISHED:   

;WHEN PREVIOUS BLOCK FINISHES "DI" POINTS AT THE END OF "BUF".

;MOV CX, 0             ;<=== CX IS ZERO 6 LINES BELOW.
MOV DX,0
MOV BX,10D

mov si, offset buf     ;<=== SI POINTS TO THE ARRAY OF MULTIPLES.
OUTER:
MOV CX, 0              ;<=== CX MUST BE HERE (IT'S DIGIT COUNTER).
MOV AX,[SI]            ;<=== RETRIEVE A MULTIPLE FROM ARRAY.
SHOW:            ;push to stack and print digit by digit     
MOV DX,0 
DIV BX                       
PUSH DX                       
INC CX                       
CMP AX,0                       
JNZ SHOW
PRINT:                     
MOV DX,0                      
MOV AH,02H                      
POP DX                      
ADD DL,30H                      
INT 21H
LOOP PRINT
;DISPLAY COMMA SEPARATOR.
  mov ah,9
  mov dx,offset comma
  int 21h
;INC SI
add si, 2              ;<=== NEXT MULTIPLE TO DISPLAY.
CMP SI, DI             ;<=== IF SI IS NOT IN THE END
JNE OUTER

INPUT PROC
ACCEPT:
MOV AH,01H
INT 21H                  

CMP AL,0DH
JZ CONTINUE

MOV AH,0
SUB AL,30H
PUSH AX
MOV AX,10D
MUL BX

POP BX
ADD BX,AX
JMP ACCEPT
CONTINUE:
RET
INPUT ENDP

EXIT:
MOV AH,4CH
INT 21H
ENDP MAIN
END MAIN

答案 1 :(得分:0)

我有点想知道为什么你为此使用甚至MUL(除非你因为分配规则而真的有)。如果这在生产中是真正的问题,你可以用更简单的方式编写整个事情,例如:

    ...
    ; bx = input number (valid 1..99)

    ; prepare es:di for STOS instruction to store results
    MOV     ax,@DATA
    MOV     es,ax
    MOV     di,OFFSET multipliedNumbers
    CLD
    ; init loop variables
    XOR     ax,ax
    XOR     cx,cx
multiplyLoop:
    ADD     ax,bx   ; calculate next result
    CMP     ax,100
    JGE     endMultiplyLoop
    STOSW           ; store result
    INC     cx      ; counting results
    JMP     multiplyLoop
endMultiplyLoop:
    ; multipliedNumbers array contains cx numbers

    ...

    ; BTW, to process them, set ds:si to results array
    MOV     si,OFFSET multipliedNumbers
        ; I assume ds already points to @DATA here
        ; and DF is still 0 (no STD since CLD)
    ; cx should be still number of stored results
readNumbersLoop:
    LODSW   ; ax = number, si+=2
    ; do whatever you want with ax *here*
    ; but keep ds:si and cx intact (or PUSH/POP them)
    LOOP readNumbersLoop

.DATA
multipliedNumbers   DW  100 DUP (?)

虽然这种变体在现代CPU上绝不是最佳表现者,但它应该是非常“人性”的可读性而且难以理解。我喜欢在这些情况下使用STOS / LODS,因为它们可以避免像原始INC DI而不是ADD DI,2这样的错误。

当我意识到Pentium / 686周围的某个地方MOV [di],ax ADD di,2更快(特别是与其他操作交错时)时,我觉得有点难过。就像现在一样,人们使用ADD reg,1代替INC。可怜的增量,从CPU的一开始就在这里,现在又没用了......;):D

编辑:

如果您真的必须使用MUL,那么您将无法完成家庭工作(将dxMUL r16一起使用):/。

手头有一份指导参考指南,并经常检查指令的详细信息(比如哪些标志受到严重影响等)。

如果你曾经碰巧做过一些256B的介绍,那么它有助于不时阅读所有这些内容,回想起像XLAT这样奇怪的东西可以使整个世界变得不同(在拟合到这256个字节之间,或者不是)。

与TASM一起提供的原始参考指南非常方便,小而短,基于英特尔文档,并且在我的修订版中已包含386条说明。我担心我忘了把它还给大学,因为我用得太多了......