簡體   English   中英

在組裝時為什么不能不移動就打印十六進制數?

[英]In assembly why can't a hexadecimal number be printed without shifting?

此代碼取自在線示例。 假設我有要在DL中打印的變量。

DISPLAY_HEX PROC NEAR
    MOV BL,DL   

    MOV BH,0    
    MOV CL,4    

    SHL BX,CL   
    MOV DL,BH   

    CALL ONE_DIGIT  

    MOV CL,4    
    SHR BL,CL   
    MOV DL,BL   

    CALL ONE_DIGIT  

    RET     
DISPLAY_HEX ENDP


ONE_DIGIT PROC NEAR

    CMP DL,9    
    JA LETTER   

    ADD DL,48
    JMP NEXT    

LETTER: ADD DL, 'A'-10  

NEXT:   MOV AH,02H  
    INT 21H 

END:    RET     
ONE_DIGIT ENDP

為什么要換班? 不能像小數一樣打印嗎? 另外,為什么在這里同時使用SHRSHL

在base16(十六進制)中,您有16個可能的數字( 0..F ),因此恰好需要4位來表示一個十六進制數字(log2(16)== 4)。 在這里,我說的是數字的含義( 0..F或base10中的0..15 ),而不是ASCII字符。

因此,一個字節可以容納兩個十六進制數字。 假設DL擁有以下位: XXXXYYYY (其中每個XY都是二進制0或1)。

首先,將16位寄存器BX向左移4位。 BXBL (最低有效字節)和BH (最高有效字節)組成。 BH已設置為0,並且BL包含輸入,因此在移位之前BX包含位00000000XXXXYYYY 移位后將包含0000XXXXYYYY0000
然后, BX的最高有效字節(即BH ,現在包含0000XXXX )被移至DL ,轉換為字符並打印。

對於第二部分,現在包含YYYY0000 BL YYYY0000右移4位,得到0000YYYY 然后將該值轉換為字符並打印。

您的代碼非常復雜,難怪它會令人困惑。 它通過左移BX獲得DL的高半字節,因此將兩個半字節分為BH和BL,但BL中的半字節在前4個字節中。

您需要進行一次移位才能將高4位降低到寄存器的底部。

在實數8086上,使用AND來僅保留低4位會更容易,並且速度快得多(在這種情況下,每個移位的計數需要一個時鍾周期,這與帶有桶形移位器ALU的現代CPU可以在1個時鍾周期內進行任意移位的現代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每條指令僅2個字節,而不是for and dh, 0Fh的3個字節,它使mov脫離了亂序執行的關鍵路徑。

ONE_DIGIT的實現還具有不必要的復雜分支。 (通常,您可以使用查找表實現半字節-> ASCII,但它只需要一個分支,而不是兩個分支。運行額外的add要比額外的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系統調用一次打印兩個數字。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM