2017-10-22 1 views
-2

간단한 어셈블리 코드를 작성하여 화면에 16 진수 값을 출력하려고합니다. print_screen.asm은 다른 모듈과 함께 작동하는 두 개의 파일입니다. 16 진수를 문자열로 변환하려고 할 때 문제가 내 논리에 있다고 생각합니다. 내 코드는 다음과 같습니다16 진수를 문자열로 변환하여 인쇄하는 NASM 모듈. 조립하지만 예상대로 작동하지 않습니다

[org 0x7c00] 

xor dx,dx 
xor ax,ax 
xor bx,bx 

mov dx, 0x1fb6 

call print_hex 

jmp endi; 

print_hex: 
    pusha 

    mov ax,0x0001 
    and ax,dx 
    add ah,48 
    mov byte [HEX_OUT+5],ah 

    mov ax,0x0010 
    and ax,dx 
    add ah,48 
    mov byte [HEX_OUT + 4],ah 

    mov ax,0x0100 
    and ax,dx 
    add ah,48 
    mov byte [HEX_OUT + 3],ah 

    mov ax,0x1000 
    and ax,dx 
    add ah,48 
    mov byte [HEX_OUT + 2],ah 

    mov bx,HEX_OUT 
    call print_string 

    popa 
    ret 

jmp endi 

%include "print_string.asm" 

endi: 
;data 
HEX_OUT: db '0x0000',0 

SAMPLE: db 'a',0 
times 510 - ($-$$) db 0 
dw 0xaa55 

print_screen.asm (다른 모듈과 작업) : 위에서

print_string: 
    pusha 
    cld 
    mov ah,0x0e 

config: mov al,[bx] 
    ;Comparing the strings 
    cmp byte [bx],0x00 ;Comparing for null 
    jne print 
    je end 

print: int 0x10 
    add bx,1 
    jmp config 

end: popa 
    ret 
+0

당신 그것을 제자리에 두십시오. – Jester

+0

'mov ax, 0x0010;을 할 때 여러분은 어떻게 생각하십니까? 도끼, dx'? 예를 들어 어떤 가치를 부여하고 어떤 결과가 나오는지보십시오. – Jester

+0

@Jester 나는 F. Dang baup을 사용해야합니다. 고마워. 그리고 사실 그 가치를 계속 변화시키고 있습니다. 다시 한번 감사드립니다. –

답변

2
mov ax,0x0001 
and ax,dx 
add ah,48 
mov byte [HEX_OUT+5],ah 

당신은 당신이 4 개 비트를 유지할 필요가 단일 비트를 유지 니펫을 .
결과가 AL 인 경우 AH에서 추가 작업을 수행합니다.
ASCII 세트가 구성되어 있기 때문에 48을 추가하여 16 진수로 변환 할 수는 없습니다. '9'(57)의 인코딩과 'A'(65)의 인코딩 사이에는 간격이 있습니다. 귀하의 코드는 이것을 설명 할 필요가 있습니다! 최하위 16 진수의 경우

:

mov ax, dx  ;Original number 
    and al, 15  ;Keep 4 bits 
    add al, '0' ;Make text 
    cmp al, '9' 
    jbe .LessA  ;Already fine for '0' to '9' 
    add al, 7  ;Bridge the gap to reach 'A' to 'F' 
.LessA: 
    mov [HEX_OUT + 5], al 

다음 hexdigit를 들어이 될 것입니다 :

mov ax, dx  ;Original number 
    shr ax, 4 
    and al, 15  ;Keep 4 bits 
    add al, '0' ;Make text 
    cmp al, '9' 
    jbe .LessA  ;Already fine for '0' to '9' 
    add al, 7  ;Bridge the gap to reach 'A' to 'F' 
.LessA: 
    mov [HEX_OUT + 4], al 

을 다음 hexdigit를 들어이 될 것입니다 다음의 경우

mov ax, dx  ;Original number 
    shr ax, 8 
    and al, 15  ;Keep 4 bits 
    add al, '0' ;Make text 
    cmp al, '9' 
    jbe .LessA  ;Already fine for '0' to '9' 
    add al, 7  ;Bridge the gap to reach 'A' to 'F' 
.LessA: 
    mov [HEX_OUT + 3], al 

다음 hexdigit이됩니다 :


6,빠르게 훨씬 더 좋을 것 루프를 사용하여, 우리를 위해 좋은보다 더있어이.
다음 솔루션은 하이 엔드에서 시작되지만 최종 결과는 다릅니다. (4)이 루프를 반복하고 DX의 개수가 4 배마다 회전이 있으므로

mov bx, 2  ;Position for most significant digit 
.Next: 
    ror dx, 4  ;Bring digit in lowest 4 bits 
    mov al, dl  ;Copy number 
    and al, 15  ;Keep 4 bits 
    add al, '0' ;Make text 
    cmp al, '9' 
    jbe .LessA  ;Already fine for '0' to '9' 
    add al, 7  ;Bridge the gap to reach 'A' to 'F' 
.LessA: 
    mov [HEX_OUT + bx], al 
    inc bx 
    cmp bx, 6  ;Did we fill chars at +2 +3 +4 +5 ? 
    jb .Next  ;Not yet 

, DX는 결국 원래의 값을 유지한다. 그것을 보존 할 필요가 없습니다.


jmp endi; 

이 달성 무슨 뜻이야? 이것은 데이터으로 점프하고 있으며 이는 확실히 실행 코드가 아닙니다! 당신이 다음 무한 루프를 원하는 경우 단순히 쓰기 :

jmp $ 

다른 파일이 당신이 말하는 다른 모듈과 작동하는지, 엉망입니다!
누구나이 문제를 계속 무시하지만 BIOS 텔레타이프 기능을 사용하려면 BH 레지스터에 원하는 디스플레이 페이지가 있어야합니다. 따라서 BX을 문자열 포인터로 사용하는 것은 항상 나쁜 생각입니다.
다음은 (BX의 사용에 관한) 기존의 모든 코드를 변경할 필요가없는 좋은 솔루션입니다 : 당신은 또한 4 대신 한 번에 1 개 비트를 마스킹하는

print_string: 
    pusha 
    mov  si, bx 
    mov  bh, 0  ;Display page 0 
    ;mov  bl, 7  ;Color if this were a graphical screen 
    cld    ;Required to use LODSB correctly 
    jmp  .start 
    .write: 
    mov  ah, 0x0E ;BIOS.Teletype 
    int  0x10 
    .start: 
    lodsb    ;Increments the pointer automatically 
    cmp  al, 0  ;Comparing for null 
    jne  .write 
    popa 
    ret 
관련 문제