这就是代码的作用。假设用户输入数字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.我在这里错过了什么?
答案 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
这样的错误。
MOV [di],ax ADD di,2
更快(特别是与其他操作交错时)时,我觉得有点难过。就像现在一样,人们使用ADD reg,1
代替INC
。可怜的增量,从CPU的一开始就在这里,现在又没用了......;):D
编辑:
如果您真的必须使用MUL
,那么您将无法完成家庭工作(将dx
与MUL r16
一起使用):/。
手头有一份指导参考指南,并经常检查指令的详细信息(比如哪些标志受到严重影响等)。
如果你曾经碰巧做过一些256B的介绍,那么它有助于不时阅读所有这些内容,回想起像XLAT
这样奇怪的东西可以使整个世界变得不同(在拟合到这256个字节之间,或者不是)。
与TASM一起提供的原始参考指南非常方便,小而短,基于英特尔文档,并且在我的修订版中已包含386条说明。我担心我忘了把它还给大学,因为我用得太多了......