n 小于 100 的倍数的 TASM 代码不显示输出

TASM code for multiples of n under 100 doesnt show output

这就是代码的作用。假设用户输入数字 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。我在这里错过了什么?

代码中的一个问题:在标签 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

我有点想知道为什么你甚至为此使用 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 中绝不是表现最好的,但它应该 "human" 可读性强,而且不难理解。我喜欢在这些情况下使用 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 条指令。恐怕我忘了return它回到大学,因为我用得太多了...