您好我试图显示实际时间小时/分钟/秒这是我的代码示例:
'Leicester City'
'Tottenham Hotspur'
'Arsenal FC'
'Manchester City'
'Manchester United'
'Southampton FC'
'West Ham United'
'Liverpool FC'
'Chelsea FC'
'Stoke City'
'Swansea City'
'Everton FC'
'Watford FC'
'Crystal Palace'
'West Bromwich Albion'
'AFC Bournemouth'
'Sunderland AFC'
'Newcastle United'
'Norwich City'
'Aston Villa'
'Channel Boleyn emotion'
'Channel Boleyn emotion'
您可以在这里查看控制台正在显示的内容
答案 0 :(得分:3)
您需要一个打印例程来将字节打印为数字,而不是将它们作为字符直接写入屏幕。幸运的是,因为您只需处理0到59之间的值,并且因为您需要前导零,所以问题非常简单。假设要在AX中打印的值:
print2Digits:
;; input in AX (0-99)
;; clobbers AX and DX, save them if needed
MOV DL, 0Ah ; divide by: 10
DIV DL ; first digit in AL (quotient), second digit in AH (remainder)
MOV DX, AX ; save the digits
ADD AL, 30h ; ASCII '0'
MOV AH, 0Eh ; set up print
INT 10h ; print first digit.
MOV AL, DH ; retrieve second digit
ADD AL, 30h
INT 10h ; print it
RET
答案 1 :(得分:2)
您正尝试将CH
,CL
和DH
个寄存器中的值(时间)显示为aschi字符。
假设您的CH
包含值15h。
现在,当您将此值放入AL
并调用int 10h
时,它会显示与值15h匹配的aschi字符。如果要显示15h的十进制数字,那么您将不得不调用一个显示例程,该例程将破坏寄存器中的值并提取其中的数字以显示 - 而不仅仅是该值中的aschi表示。
假设您在注册表中有小数85。现在你需要在屏幕上打印" 8"和" 5"。因此,您必须将值85转换为aschi-56(" 8")和aschii-53(" 5")。然后将它们一个接一个地放入寄存器中并拨打int 10
两次以显示" 85"。
hobbs的答案显示了如何做到这一点。
Here是另一个教程
答案 2 :(得分:2)
请参阅x86标签wiki以获取指令集参考手册,以及许多指向参考资料和教程的良好链接。
需要足够的代码将整数分成ASCII数字,你应该把它分解成函数。
这是@ hobbs的print2Digits功能的优化和修复版本。 (我也在他的答案中修改了版本,所以它也是正确的,但保留了这个版本的优化。)
print2Digits:
;; input in AL (0-99).
;; clobbers AX and DX
cbw ; zero AH. Sign-extending AL does the job because AL is only allowed to be 0-99.
; omit this step if you can easily have the caller use the full AX, i.e. zero AH for us
mov dl, 10
div dl ; quotient in AL(first (high) digit), remainder in AH(second (low) digit)
add ax, 0x3030 ; add '0' to al and ah at the same time.
mov dl, ah ; save the 2nd digit
mov ah, 0x0E ; DOS system call number for printing a single character
int 0x10 ; print high digit first. Doesn't clobber anything, so AH still holds 0x0E after
mov al, dl
int 0x10 ; print the low digit 2nd
ret
由于我们使用div
将整数拆分为两个base10数字,因此我们需要ah
为零。如果来电者cbw
或某事,我们可以将movzx ax, ch
保存为零ah
。
(除了8086没有movzx
,所以你必须实际xor ax,ax
/ mov al, ch
。)
有一个用于打印整个字符串的DOS系统调用,因此您可以将字符存储到一个小缓冲区中并一次打印它们,就像我在AMD64 Linux FizzBuzz
中所做的那样 还可以使用aam
将AL(而不是AX)除以10 ,从而避免首先需要将AH归零。它在当前的Intel和AMD CPU上比div r8
略快。但是,它将结果放在div
的相反寄存器中,这意味着aam
之后的额外指令。这可以平衡mov dl, 10
和cbw
print2Digits:
;; input in AL (0-99). (Ignores AH because we use AAM instead of div)
;; clobbers AX and DX
aam ; like `div` by 10, but with the outputs reversed, and input from AL only
; quotient in AH (high digit), remainder in AL(low digit). (Opposite to div)
add ax, 0x3030 ; add '0' to al and ah at the same time.
mov dl, al ; save the low digit
mov al, ah ; print high digit first
mov ah, 0x0E ; DOS system call number for printing a single character
int 0x10 ; print first digit. Doesn't clobber anything, so AH still holds 0x0E after
mov al, dl
int 0x10 ; print second digit
ret
即使我们想要存储到一个字符串(并调用一个打印字符串函数或系统调用),我们必须在将AX存储到内存之前交换al和ah(例如{{1}在现代硬件上更有效,xchg al,ah
)。 rol ax,8
以正确的顺序生成它们。
对于32位地址大小可用的386 ,我们可以保存一条指令:
div
lea dx, [eax + 0x3030] ; need a 32bit addressing mode to use eax as a source reg. Adds '0' to both digits at once, with a different destination.
mov al, dh
需要一个地址大小的前缀和一个2字节的mod / rm,以及一个32位的位移,因此在代码大小上会丢失很多,但它会保存一条指令。
在lea
写lea
之后eax
使用div
来读取Sandybridge系列CPU可能会更快,尤其是Haswell和后来,但在英特尔pre-SnB上,部分寄存器停止将使得使用纯16bit版本以及单独的add和mov指令更好。