.model large
.386
.stack 100h
.data
num word 0f3f2h
.code
L_start:
mov ax, @data
mov ds, ax
mov dx, num
call printDecimal
mov ah, 4ch
int 21h
;---------------------------------
; 헥스값을 10진수로 변환
; 입력값 dx : 16-bit unsigned
;
; F3F2라는 숫자를 10진수로 출력하려면 F3F2라는 숫자를 10으로 나누어
; 나머지를 스택에 차례로 저장했다가 복원하면서 하나씩 아스키문자로
; 변환해서 출력해 주면 됩니다.
; F3F2 / 10 = 1865....0
; 1865 / 10 = 270.....5
; 270 / 10 = 3E......4
; 3E / 10 = 6.......2
; 6 / 10 = 0.......6
; 각 자리를 푸쉬하는 이유는 각 연산의 결과 05426이 됩니다. 그렇기
; 때문에 자리를 뒤집어서 찍어줘야 합니다. 이런 경우 스택을 사용하면
; 간단히 해결할 수 있습니다. 스택의 구조는 후입선출로서 나중에 들어
; 간 것이 먼저 나오므로 각 연산의 결과를 스택에 푸쉬해 두고 차례로
; 팝하면서 찍어주면 62450이 정상적으로 찍히게 됩니다.
;
; 각 자리를 10으로 나누기 때문에 9이상의 숫자가 나머지로 나올 수
; 없습니다. 10이 나온다면 10으로 나누어 떨어져 결국 나머지는 0이기
; 때문입니다.
; 0~9는 10진수와 16진수가 공통으로 가지고 있는 부분이기
; 때문에 다른 변환없이 바로 사용할 수 있습니다. 때문에 16진수를
; 출력하는 프로시져로 출력해도 정상적인 10 진수를 출력할 수 있습니다.
printDecimal proc
pusha ; 레지스터 보호
mov ax, dx ; 피젯수를 ax에 저장
mov si, 10 ; 젯수를 si에 저장
xor cx, cx ; cx를 0으로 초기화
NONE_ZERO:
xor dx, dx ; dx를 0으로 초기화
div si ; ax의 내용을 si의 값으로 나눔
push dx ; 나머지 dx를 스택에 저장
inc cx ; cx 증가시킴
or ax, ax ; ax 가 0인가 ?
jne NONE_ZERO ; 0이 아니면 NONE_ZERO로 이동
WRITE_DIGIT_LOOP:
pop dx ; 푸쉬한 수만큼 스택에서 꺼내면서 출력하기
call printHex ; 16진수 출력 루틴
loop WRITE_DIGIT_LOOP
END_DECIMAL:
popa ; 레지스터 보호 해제
ret ; 프로시져 리턴
printDecimal endp
;--------------------------------
; 헥스값이나 10진수 값을 화면에 출력
; 입력값 dl : 8-bit 의 출력하고자하는 니블의 값
printHex proc
push dx ; 레지스터 보호
push ax
cmp dl, 10 ; dl을 10과 비교
jae HEX_LETTER ; 10보다 크거나 같으면 16진수 A~F에 해당하는 아스키 출력
add dl, '0' ; 10보다 작으면 '0'의 아스키코드 30h를 더해 실제 아스키코드 만듦
; 가령 dl이 9이면 30+9=39 39는 아스키코드 '9'임
jmp short WRITE_DIGIT ; 아스키코드 출력 루틴으로 이동
HEX_LETTER:
add dl, 'A'-10 ; 10이상인 경우 10~15까지의 숫자가 A~F로 할당된다. dl이 11이라면
; 'A'에 해당하는 아스키코드 41h + 0Bh = 4Ch가 되어 'L'에 해당하는
; 아스키코드가 되어 버린다. 여기서 변환하는 목적은 실제 수를 변환
; 하거나 연산하는 것이 아니고, 단순히 그 숫자에 해당하는 아스키
; 코드를 찍어주는 것이다. 그러므로 10~15의 숫자중 1의 자리에 해당
; 하는 0~5만 있으면 A~F의 아스키코드에 짝지울 수 있다.
; 그래서 아스키코드'A'에서 10을 빼주는 것이다. dl이 11이면 10을
; 빼서 1로 만들고 거기에 아스키코드'A'를 더해주면 아스키코드'B'
; 가 나와서 정확한 수치표현을 할 수 있다. 여기서 sub dl, 0Ah를
; 하고 add dl, 'A'를 하지 않는 이유는 불필요한 코드를 줄이기 위해서
; 이다. 'A'-10은 컴파일시에 자동으로 41h-0Ah=37h 하여 37h값으로
; 대치하여 컴파일 해준다. 어째됐건 우리의 목표인 10을 빼는데 문제
; 가 없으므로 필요없는 2줄의 코드를 한줄로 줄여주는 효과가 있다.
WRITE_DIGIT:
mov ah, 2 ; 도스기능 호출 2번으로 dl에 저장된 하나의 문자를 출력
int 21h
pop ax ; 레지스터 복원
pop dx
ret
printHex endp
end L_start
'Assembly' 카테고리의 다른 글
[DOS] Queue (0) | 2010.01.05 |
---|---|
[DOS] 각 숫자의 on된 비트수 세기와 버블 소팅 (0) | 2010.01.05 |
[DOS] 문자열을 입력받아 끝에 $ 추가해서 출력하기 (0) | 2010.01.05 |
[DOS] 어셈블리에서 클래스 구현 (0) | 2010.01.05 |
[DOS] 간단한 Assembly 문법 정리 (1) | 2010.01.05 |