我正试图简单地按顺序打印数字,即
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
使用Loop,首先,我将每个数字转换为Hexa打印,它将其重置为十进制增量1,然后打印下一个数字,直到数字等于9,当数字等于9时,我使用DAA来简化数字,在旋转和移位数字后,我最终将结果存储在字符串中。
直到16号,输出都很好,但在16号之后,序列会重复,
所需输出:
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
电流输出1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,11,12,13,18,15
为什么会这样???
这是我的代码,
MOV CX,20 ;Number of Iterations
MOV DX,1
L1:
PUSH DX
ADD DX,30H
MOV AH,02H ;PRINT Content of DX
INT 21H
POP DX
ADD DX,1
CMP DX,09d ;If number is Greater than 9 jump to L2
JA L2
LOOP L1
L2:
PUSH DX
MOV AX,DX
DAA ;Convert to the Decimal
XOR AH,AH ;SET AH to 0000
ROR AX,1
ROR AX,1
ROR AX,1
ROR AX,1
SHR AH,1
SHR AH,1
SHR AH,1
SHR AH,1
ADC AX,3030h
MOV BX,OFFSET Result
MOV byte ptr[BX],5 ; Length of the String
MOV byte ptr[BX+4],'$' ;5th position of string , $=Terminator
MOV byte ptr[BX+3],AH ;2nd Number onto 4th position
MOV byte ptr[BX+2],AL ;3rd number onto 3rd Position
MOV DX,BX
ADD DX,02 ;1st 2 positions of String are type of string and
length respectively
MOV AH,09H ;to print the string
INT 21H
POP DX
ADD DX,1
LOOP L2
MOV AH,4CH ;Return control to the DOS
INT 21H
p.S:我从这张图表中得到了帮助,理解了这些数字。
http://www.cheat-sheets.org/saved-copy/ascii.png
8086代码只允许移位和旋转计数的立即数为1(或cl)。要启用286代码,请在文件顶部告诉Tasm".286"。这只是猜测。
我记得我曾经用al打印两位数的数字:
aam
add ax, 3030h
xchg al, ah
int 29h
mov al, ah
int 29h
只是尝试一下,尽管我不确定,而且我不能快速测试它。
但是,与其使用两个循环,我建议对整组数字使用一个循环。
此外,我觉得这个问题与DAA
指令有关,我不习惯它,因为它在64位模式中不受支持。
不管怎样,我会这么做:
mov cx,20
mov al,1
mov bl,10 ; divisor
mov bp,offset Result ; no need to load this in the loop!!!
L1: mov dx,ax ; save to register, not to stack
cmp ax,09d
ja L2 ; number has two digits
add al,30h ; ASCII addend
; insert your output code here
jmp L3 ; jump over the two digit code
L2: xor ah,ah
div bl ; divides AX by ten (no rotate or shift needed)
; quotient in AL, remainder in AH (correct order for little endian)
add ax,3030h
; insert your output code here (note that the buffer/string address is loaded to BP)
L3: mov ax,dx
inc ax
loop L1
; done
如果你不介意一位数有一个前导零,那就更容易了。
div
指令可能比daa
加ror
加shr
更贵,但您的四进制旋转/移位会更糟:-/
(正如我所说,我不能尝试……把这个留给你……如果它不起作用,请回问。)
—
[更新:
另一种方法,尤其是在这种琐碎的数字分离情况下,为了避免div
,将6加到大于9的数字上(即10d=0ah-(+6)-->16d=10h;这也是daa
的作用),然后您可以使用以前使用的旋转/移位组合。
更好的方法是添加246,然后添加到AX
,之后您可以简单地使用ror ax,8
(或rol
—在这种情况下无关紧要),即10d=0ah-(+246)-->256d=100h,以及15d=0ah-(+446)-->261=105h。分别旋转到0001h或0501h,加3030h,就完成了。
/更新]
[更新级别="2">
多么有趣。。。实际上,我本打算在一级更新中编写它,但不知何故忘记了:而不是rol
乘以8,或者—如果您的TASM真的不支持rol
ling,请立即—八次一次滚动,当然也可以使用xchg
指令,它在寄存器之间交换值,在这种情况下是
xchg al,ah
将完成交换这两个寄存器的内容的工作。
还有一个bswap
指令用于反转寄存器中的字节顺序,但它显然只适用于宽度超过32位的寄存器。
/更新]
.model small
.stack 100
.code
mov ax, 0ffffh ; hex number to find it's bcd
mov bx, 0000
mov dh, 0
l9 : cmp ax, 10000 ; if ax>10000
jb l2
sub ax, 10000 ; subtract 10000
inc dh ; add 1 to dh
jmp l9
l2 : cmp ax, 1000 ; if ax>1000
jb l4
sub ax, 1000
add bx, 1000h ; add 1000h to result
jmp l2
l4 : cmp ax, 100 ; if ax>100
jb l6
sub ax, 100
add bx, 100h ; add 100h to result
jmp l4
l6 : cmp ax, 10 ; if ax>10
jb l8
sub ax, 10
add bx, 10h ; add 10h to result
jmp l6
l8 : add bx, ax ; add remainder
; to result
mov ah, 02
mov cx, 0204h ; Count to display
; 2 digits
go: rol dh, cl
mov dl, dh
and dl, 0fh
add dl, 30h ; display 2 msb digits
int 21h
dec ch
jnz go
mov ch, 04h ; Count of digits to be
; displayed
mov cl, 04h ; Count to roll by 4 bits
l12: rol bx, cl ; roll bl so that msb
; comes to lsb
mov dl, bl ; load dl with data to be
; displayed
and dl, 0fH ; get only lsb
cmp dl, 09 ; check if digit is 0-9 or letter A-F
jbe l14
add dl, 07 ; if letter add 37H else only add 30H
l14: add dl, 30H
mov ah, 02 ; Function 2 under INT 21H (Display character)
int 21H
dec ch ; Decrement Count
jnz l12
mov ah, 4cH ; Terminate Program
int 21H
end