您的代码非常复杂,难怪它令人困惑。它是通过左移 BX 得到 DL 的高半字节,所以这两个半字节分为 BH 和 BL,但 BL 中的半字节在前 4 个字节中。
您需要一次移位才能将高 4 位降低到寄存器的底部。
使用 AND 仅保留低 4 位会更容易,并且在真正的 8086 上更快(其中每个移位计数需要一个时钟周期,不像现代 CPU 具有桶形移位器 ALU 可以在 1 个时钟周期内进行任意移位) .
这是一个更简单、更容易理解的实现,它也更紧凑,因此在真正的 8086 上更快更好。
; Input in DL
; clobbers AX, CL, DX
DISPLAY_HEX PROC NEAR
mov dh, dl ; save a copy for later
mov cl, 4
shr dl, cl ; extract the high nibble into an 8-bit integer
CALL ONE_DIGIT
and dh, 0Fh ; clear the high nibble, keeping only the low nibble
mov dl, dh ; and pass it to our function
CALL ONE_DIGIT
RET
DISPLAY_HEX ENDP
为了节省代码大小, mov dl, 0Fh
/and dl, dh
每条指令将只有 2 个字节,而不是 3 个字节and dh, 0Fh
,并且它mov
消除了乱序执行的关键路径。
的实现ONE_DIGIT
也有不必要的复杂分支。(通常你会用一个查找表来实现 nibble -> ASCII,但它只需要一个分支,而不是两个。运行一个 extraadd
比一个 extra 便宜jmp
。)
; input: DL = 0..15 integer
; output: AL = ASCII hex char written
; clobbers = AH
ONE_DIGIT PROC NEAR
CMP DL,9
JBE DIGIT
ADD DL, 'A'-10 - '0'
DIGIT:
ADD DL, '0'
MOV AH,02H
INT 21H ; write char to stdout, return in AL. Checks for ^c/break
RET
ONE_DIGIT ENDP
我们本可以ADD dx, '00'
(并更改cmp
)同时对两个半字节进行操作(在 DH 和 DL 中分别隔离它们之后)。
我们也可以提升MOV AH,02H
,因为int 21h
/ah=2
不会修改 AH。.
如果我们关心性能,我们会创建一个 2 个字符的字符串并使用一个int 21h
系统调用来一次打印两个数字。