あなたのコードは非常に複雑すぎて、混乱したのも不思議ではありません。BX を左シフトすることで DL の上位ニブルを取得しているため、2 つのニブルは BH と BL に分割されますが、BL のニブルは上位 4 バイトにあります。
上位 4 ビットをレジスターの最下位に移動するには、1 つのシフトが必要です。
AND を使用して下位 4 ビットのみを保持する方が簡単で、実際の 8086 でははるかに高速です (1 クロック サイクルで任意のシフトを実行できるバレル シフター ALU を備えた最新の CPU とは異なり、シフトの各カウントにクロック サイクルが必要でした)。 .
これはよりシンプルで理解しやすい実装であり、よりコンパクトであるため、実際の 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
は命令ごとに 3 バイトではなく 2 バイトにand dh, 0Fh
なりmov
、アウトオブオーダー実行のクリティカル パスから外れます。
の実装にONE_DIGIT
は、不必要に複雑な分岐もあります。(多くの場合、ルックアップ テーブルを使用してニブル -> ASCII を実装しますが、必要なブランチは 2 つではなく 1 つだけです。extra を実行すると、extraadd
よりも安価です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
(DH と DL でそれぞれを分離した後) 両方のニブルを一度に操作するようにADD dx, '00'
(および を変更して)実行することもできます。cmp
/は AH を変更しないMOV AH,02H
ため、をホイストすることもできます。.int 21h
ah=2
ただし、パフォーマンスを気にする場合は、2 文字の文字列を作成し、1 つのint 21h
システム コールを使用して両方の数字を一度に出力します。