크리에이티브 커먼즈 라이센스

홈페이지HOME

PHP

JavaScript

HTML

CSS

드롭다운메뉴

제로보드4

도   움   말

백지 건강강좌/자가임상체험

물박사(자가면역질환...)^미러

전동명(천연물질사전)^미러

竹田 장승옥(블로그)^글목록

계산환산(계산기)^ 단위변환

관주성경 TTS 일반파일 TTS

바이블로 Bible_ro 다운로드

다운로드>폰에 복사
>파일선택...설치됩니다.

[도움말 보기] 바로가기

개선 요구, 충고는
아래 관리자 연락
전화/메일 부탁 드립니다.
최대한 빨리 처리하고
업데이트 올리겠습니다.

asm_07.

(16진수 출력 Ⅰ)



프로그래밍 언어도 하나의 언어입니다.

언어란 하나의 약속입니다.

우리가 약속을 모를 때 우리는 전혀 무능한 사람입니다.

그러나 일단 약속을 알고 나면 우리는 유능한 사람이 됩니다.

우리는 외국 사람들과 대화하기 위하여, 그 외국 사람들 사이의 약속인 해당 외국어를

열심히 배웁니다.

프로그래밍 언어를 배우는 것은 확실히 그보다 쉽습니다.


혹시 필자의 도스 참고서가 필요하신 분은 이 파일과 함께 압축되어 있는 아스키

텍스트 파일을 참고하시기 바랍니다. 11월이나 12월 경에는 윈도우즈 참고서 및 PC

종합 참고서도 출판할 예정이니 프린터로 뽑아 보기가 경제적으로 부담스러운 분은

꼭 필요한 부분만 프린터해 보시고 잠깐 기다려 주시기 바랍니다. // 94년도 글임






제 07 장  16진수 출력 Ⅰ

바로 앞에서 우리는 16진수를 2진수로 출력해 주는 간단한 프로그램을 보았다.

그것은 단순히 bl 레지스터에 이미 존재하는 한 바이트의 16진수를 2진수로 변환하여

출력해 주는 원시적인 것이지만, 우리는 그 프로그램을 만들어 실행해 봄으로써 8088의

레지스터와 캐리 플래그에 대하여 더 이해하게 되었다.

이제는 16진수 자체를 화면에 출력하는 프로그램을 만들어 보자.

이 프로그램은 조금은 복잡할 것이다.

뿐만 아니라, 우리는 이번에는 단지 레지스터에 이미 존재하는 값을 출력하는

것이 아니라 키보드의 입력을 받아 들여 출력하는 프로그램을 만들 것이다.


제 1 절  제로 플래그

앞에서 우리는 8088에 8 개의 플래그가 존재한다는 사실을 알았다.

그 중에서 r <Enter> 명령이나 r f <Enter> 명령을 했을 때 cy 또는

nc 중 하나로 나타나는 캐리 플래그에 관해서는 프로그램 실습까지 해 본 바 있다.






1.  참과 거짓

모든 플래그에서 그 값이 1로 설정되면 참(true)을 뜻하고, 그 값이 0으로 설정되면

거짓(faulse)을 의미한다.  이것은 컴퓨터 언어의 약속이다.

따라서 loop 명령은 자기에게 넘어온 cx 레지스터의 값에서 일단 1을 뺀 후에

그 남은 값이 0이 아닌 다른 값이면 참으로 판단하여 loop <번지> <Enter>

명령을 실행하고 그 결과 순환문의 실행이 계속되지만, 그 빼고 남은 값이 0이 되면

거짓으로 판단하여 loop 명령 자체의 실행을 하지 않고 다음 명령으로 제어를 넘긴

것이며, 그리하여 결국은 cx 레지스터에서 처음 지정한 회수만큼 반복 실행하였다.

이제 우리는 또 하나의 플래그인 제로 플래그를 이해하고 이용해 보자.


2.  제로 플래그의 참과 거짓

캐리 플래그의 참, 거짓 판단과 제로 플래그의 참, 거짓 판단은 서로 다르다.

어떻게 보면 정반대인 것처럼 보인다.

일반적으로 값이 0이면 거짓이고 0이 아니면 참일 것 같지만, 제로 플래그의 경우에는

사정이 달라서 값이 0이라야만 참이 되기 때문이다.

우리가 플래그 입문이란 제목으로 도스 매뉴얼에 나오는 표를 살펴본 일이 있는데,

그 표에서 설정, 해제라는 말 자체를 참, 거짓으로 바꾸어 볼 수도 있다.

제로 플래그에 0이라는 값이 전달되어 제로 플래그가 참이 되면 곧 제로 플래그가

설정되었다고 말할 수 있으며 그 때 제로 플래그는 zr(wero)로 나타난다.

반면에 제로 플래그에 0이 아닌 다른 값이 전달되면 제로 플래그가 거짓이 되어서

해제 상태가 될 것이며, 그 때는 제로 플래그가 nz(not zero)로 보인다.


     zr zero제로

    플래그 설정 - 값 0 -

    참

     nz not zero제로

    플래그 해제 - 0이 아닌 값- 거짓


위의 표로 만든 메모를 보면 간단하게 정리가 될 줄 믿는다.






3.  sub 명령과 제로 플래그

sub ax,bx <Enter> 명령은 ax 값에서 bx 값을 뺀 나머지를 ax 레지스터에

저장한다는 사실은 앞에서 배운 바 있다.

뺄셈을 한 나머지가 0인 경우에는 제로 플래그가 설정되어 zr이 된다.

처음 디버그를 실행한 즉시 r <Enter> 명령을 하여 제로 플래그가 해제된

상태 즉 nz로 보임을 확인한 후 작업을 해 보자.


     - a 100 <Enter>

     ????:0100mov ax,

    aa <Enter>

     ????:0103mov bl,

    aa <Enter>

     ????:0105sub ax,

    bx <Enter>

     ????:0107int 20

    <Enter>

     ????:0109 <Enter>

     -


ax, bx 레지스터의 값을 같이 주고 뺄셈을 했으니, 나머지는 0이 되고 제로 플래그는

당연히 참이 되어 zr로 변하는 사실을 확인하자는 목적이다.

약간 가지를 쳐서, 위의 프로그램에서 동일한 값을 레지스터에 입력해 주었음에도

불구하고 ax 레지스터트와 같이 워드 단위로 지정했을 때는 명령어가 3 바이트를

차지한 반면, bl 레지스터와 같이 바이트 단위로 지정했을 때는 그 명령어가 단지

2 바이트 밖에 차지하지 않았음을 눈치가 빠른 사람은 알아 보았을 것이다.

이제 위의 프로그램을 직접 실행하여 제로 플래그의 변화를 눈으로 확인하자.

디버그로 프로그램을 실행하는 데 크게 두 가지 방법이 있음을 우리는 안다.






4.  일괄 실행, 명령어별 실행

숙달된 후에는 괜찮지만, 프로그램을 실행하기 전에는 항상 r ip <Enter>

명령으로 ip 레지스터가 100임을 확인하고 다른 번지이면 100으로 고쳐 주도록 하자.

만약 r ip <Enter> 명령을 했는데 0100이 나오면 그냥 <Enter>하면

된다.

이제 우리의 프로그램을 일괄 실행해 보자.


     - g <Enter>


     Program terminated normally

     -


다시 r <Enter> 또는 r f <Enter> 명령을 해 보아야 제로 플래그는

nz로 나온다.

(r f <Enter> 명령이 기억나지 않으면 앞의 원고를 뒤지든지 직접 실행해

보라.)

왜 그럴까?

앞에서 우리는 그 이유를 공부한 바 있다.


    디버그는 g <Enter> 명령을 받으면, 그 명령을 실행하기 전에 모든

    레지스터의 값을 보존해 두었다가 모든 명령을 실행하고 나서 int 20h 명령어를

    만나면 모든 레지스터의 원래 값을 복구해 주기 때문이다.

    그리고 ip 레지스터 값도 0100으로 원상복구시켜 둔다.


지금 r <Enter> 명령을 해 보면 ip 레지스터의 값을 확인할 수 있다.

이제 제로 플래그의 변화를 확인하기 위해 한 명령어씩 실행해 보자.


     - t <Enter>

     .................... (여러 줄 생략)

     .................. SUB AX,BX

     - t <Enter>

     .................................

     ....................... zr ......


sub ax, bx 명령이 실행된 후 제로 플래그의 표시가 zr로 바뀜을 알 수 있다.

주의할 것은 명령어별 실행에서 int 20h 이후는 실행하지 말라는 점이다.






제 2 절  점프 명령

점프 명령은 조건 분기 명령어(conditional jump instruction)라는 것이다.

점프 명령은 그 명령어에 속한 어떤 조건이 참이 되면 지정한 메모리 번지의 다른

명령어로 제어를 넘기는 수도 있고, 그 조건이 거짓이 되어야 지정한 메모리 번지의

다른 명령어로 제어를 넘기는 경우도 있다.

제로 플래그과 관련된 두 가지 점프 명령은 jz와 jnz이다.

jz(jump if zero)는 문자 그대로 최근 연산의 결과가 0일 때만 지정 주소로 이동한다.

 즉 제로 플래그를 조사하여 그것이 0 즉 참이 되어 zr로 설정되어 있다면 베이직의

if...then 문장과 마찬가지로 지정된 주소로 이동한다는 말이다.

반대로 jnz(jumpo if not zero)는 역시 문자 그대로 최근 연산의 결과가 0이 아닌

경우에, 즉 제로 플래그가 해제되어 nz일 때에만 지정된 주소로 이동한다.

물론 두 가지 경우 다, 제시한 조건 즉 zr 또는 nz가 거짓이 되였다면 점프 명령을

실행하지 않고 단순히 순서상 뒤에 나오는 명령어로 제어를 넘기게 된다.

이 절에서는 먼저 제로 플래그를 참조하는 점프 명령어로 시작하여, cmp 명령어의

연산 결과를 참조하는 점프 명령 등을 알아 보아서 16진수 출력 프로그램을 만들기

위해 필요한 몇 가지 지식을 익혀 두기로 한다.






1.  주어진 값에서 1씩 계속 빼는 프로그램

jnz 명령을 이용하면, 먼저 일정한 값을 주고 그 값에서 1씩 빼는 계산을 그 값이

0이 될 때까지 계속해서 수행하도록 하는 프로그램을 만들 수 있다.

이것은 아주 간단한 프로그램이다.


     - a 100 <Enter>

     ????:0100 moval, 09 <Enter>

     ????:0102 subal, 01 <Enter>

     ????:0104 jnz0102 <Enter>

     ????:0106 int20 <Enter>

     ????:0108 <Enter>

     -


al 레지스터에 9h를 입력한 후 1씩 빼어 나가서 0이 될 때까지 빼게 된다.

나머지가 0이 되는 순간 제로 플래그가 zr로 변할 것이고, jnz 명령의 조건은

거짓이 되므로 점프 명령은 실행되지 않으며, 따라서 그 뒤의 int 20 명령으로 제어가

넘어가 이 프르그램은 실행을 끝마치게 된다.

위 프로그램을 g <Enter> 명령으로 실행할 수도 있느나 과정을 확인할 길이

없다.

t <Enter> 명령으로 하나씩 실행해 가면서 ax 레지스터의 값이 변하는 것을

주시하라.  그리고 간간이 제로 플래그도 확인해 보라.

ax 레지스터의 값이 0009에서 0008, 0007 차례로 줄어드는 것이 보이지만 제로

플래그는 항상 nz로 변함이 없을 것이다.  그러다가, ax 레지스터의 값이 0으로

변함과 동시에 제로 플래그도 zr로 변하는 사실을 확인할 수 있으면 좋다.


2.  cmp 명령과 jl 점프 명령

두 수를 비교하여 그 차이를 알아 보는 명령어로 우리는 sub 명령을 알고 있다.

그런데 sub ax, bx <Enter> 명령은 결국 ax 값을 변경시킨다.

그와 달리 cmp 명령을 사용하면 두 값을 비교하되 값을 변경시키지는 않는다.

따라서 cmp 명령어와 함께 jl(jump if less than) 명령어를 사용한다면 16진수를

출력하는 프로그램을 만드는 데 한 발 성큼 다가설 수 있게 된다.






일단 프로그램을 만들어 보고 이론적인 면을 계속해서 공부하기로 하자.


     - a 100 <Enter>

     ????:0100mov ah,

    02 <Enter>

     ????:0102mov dl,

    bl <Enter>

     ????:0104add dl,

    30 <Enter>

     ????:0107cmp dl,

    3a <Enter>

     ????:010Ajl010f

    <Enter>

     ????:010Cadd dl,

    07 <Enter>

     ????:010Fint 21

    <Enter>

     ????:0111int 20

    <Enter>

     ????:0113 <Enter>

     -


위의 프로그램을 정확하게 입력하여 만들었다면 이제 실행을 해 보도록 하자.

그대로 g <Enter> 명령을 하면 다음과 같은 결과를 보게 될 것이다.


     - g <Enter>

     0

     Program terminated normally

     -


왜 위와 같은 결과가 나왔을까?

r <Enter> 명령으로 확인할 수 있는 바와 같이, bl(bx) 레지스터의 값은

우리가 아무 값도 입력하지 않았으므로 0이다.  따라서 add bl,30 <Enter>

명령을 만나 bl 값은 30으로 변한다.  다음 cmp 명령을 만나 30을 37과 비교하여

30이 더 작으므로 jl 명령의 조건(less than)을 만족시키므로 int 21h 명령으로 점프하게

된다.

결국 디버그는 코드값 30h에 해당되는 0이라는 문자를 화면에 출력한 것이다.

이것은 아직 우리가 원하는 완성된 프로그램은 아니다.

그러나 당장 r bx <Enter> 명령으로 bl 레지스터에 한 자리의 16진수를

입력한 후에 g <Enter> 명령으로 프로그램을 실행해 보면 입력된 문자를 그대로

출력해 주는 것을 확인할 수 있을 .  보게 i      耐 면 만족할 수 있을

.  


3.  프로그램 저장

무심코 디버그를 끝내고 나면, 위 프로그램을 다시 한 번 실행해 보았으면 하는

아쉬움이 남기 마련이다.

이런iㅃ 프로그램을 저장해 두면 다시 처음부터 입력하는 수고를 덜게 된다.






프로그램을 저장하는 실습도 해 본 지 오래이므로 복습 겸해서 한 번 저장하자.

먼 i프로그램의 이름을 지어 주어야 된다.

그리고는 프로그램의 크기를 cx 레지스터에 입력해 주어야 된다.

그리고 나서는 w <Enter> 명령으로 저장하면 끝난다.


     - n 16.com <Enter>

     - r cx <Enter>

     CX 0000

     : 113 <Enter>

     - w <Enter>

     Writing 00113 bytes

     -


이제는 혹시 디버그를 끝낸 후에 다시 이 프로그램을 사용해 보고 싶은 마음이

생긴다면 debug 16.com <Enter> 명령으로 프로그램을 호출하여 실행할 수 있다.

이제 안심하고 r bx <Enter> 명령으로 1 자리의 16진수 즉 0, 1, 2, ...

e, f 중 하나를 입력한 후 g <Enter> 명령을 해 보면 입력된 그대로 출력되는

것을 보게 된다.


제 3 절  16진수 출력 프로그램 분석

초보자를 위하여, 위에서 만든 프로그램을 그대로 옮겨 두고 어째서 우리가 입력한

16진수를 그대로 출력해 주는가 하는 실행 구조를 설명하기로 한다.

필자가 방금 한 말 자체를 이해하지 못하는 왕초보자도 있을 것이다.

그러나, 아스키 코드값 표를 보면 금방 이해할 수 있다.

16진수와 그 값으로 표시하는 아스키 문자를 처음부터 살펴 보면, 16진수 0으로부터

2f까지에는 특수 문자가 배당되어 있으며, 16진수 30으로부터 39까지가 숫자 0으로부터

9까지의 문자에 배당되어 있다.


     16진수(Hex)0 ∼ 2F 30

    31 32 33 34 35 36 37 38 39

     아스키 문자특수문자0

     1  2  3  4  5  6  7  8  9


따라서, dl 레지스터에 0에서 9까지의 16진수를 입력하여 그대로 출력하면 입력된

숫자와는 다른 특수문자가 출력될 것이다.

이제 우리의 프로그램을 옮겨 두고 보면서 설명을 계속하기로 한다.






설명하기 편하도록 명령어마다 (1) (2) 등의 줄 번호를 붙이고 시작하자.


     - a 100 <Enter>

     ????:0100mov ah,

    02 <Enter>(1)

     ????:0102mov dl,

    bl <Enter>  (2)

     ????:0104add dl,

    30 <Enter>  (3)

     ????:0107cmp dl,

    3a <Enter>  (4)

     ????:010Ajl010f

    <Enter>(5)

     ????:010Cadd dl,

    07 <Enter>  (6)

     ????:010F   21

    <Enter>(7)

     ????:0111   20

    <Enter>(8)

     ????:0113 <Enter>

     -


명령어 (1) (2) (7) (8)만으로도 프로그램을 만들 수는 있다.

만약 그렇게 모아서 프로그램을 만든다면, 방금 지적한 바와 같이 우리가 입력한

16진수 1 자리 숫자에 대응하는 특수문자들이 출력될 뿐이다.

이것은 우리가 의도한 바의 목적에는 맞지 않는 것이다.

따라서 (3) 명령어가 필요하게 되는 것이다.

그러므로 명령어 (1) (2) (3) (7) (8)을 모아서 프로그램을 만들어 볼 수 있다.

그러면, 우리가 0 내지 9까지의 16진수를 입력하면 프로그램이 그 수 각각에 30을

보태어 30 내지 39라는 16진수로 바꾼 후 그 코드값에 대응하는 0 내지 9까지의 문자를

출력해 준다.  이것은 우리의 목적에 부함하는 것이다.

이것으로 우리의 목적이 모두 달성되었다면 cmp, jl 등을 사용하는 명령어 줄들인

(4) (5) (6)은 불필요할 것이다.

그러나, 16진수 1 자리 숫자로는 0에서 9까지 말고도 a에서 f까지 6 개가 있다.

그 숫자를 동일한 문자로 출력하기 위해서는 그 문자의 아스키 코드값이 16진수로

얼마에 해당되는지를 살펴 볼 필요가 있다.

아스키 코드값 표의 해당되는 부분을 살펴 보도록 하자.


     16진수(Hex)3A 3B 3C 3D 3E 3F 40 41 42  43

    44  45 46

     아스키 문자: ; <

     =  >  ?  @  A  B  C  D  E

     F


코드값 3a로부터 40까지 7 개의 자리에는 콜론(:) 등 특수문자가 배당되어 있다.

만약, 그 7 개가 빠져 있다면 조금 전에 우리가 추려 모았던 (1) (2) (3) (7)

(8) 등 5 줄의 명령어만으로도 0에서 f까지 16진수 1 자리 숫자를 다 표현할 수 있다.

그러나, 원하지 않는 7 문자가 사이에 끼어 있기 때문에 우리는 부득이 프로그램을

복잡하게 만들어 실행하지 않을 수 없는 것이다.

서론은 이 정도로 마치고, 프로그램의 전체적인 흐름을 정리하자.






명령 (1)에서는 나중에 int 21h가 실행될 때 dl 레지스터의 값에 대응하는 아스키

문자를 출력하기 위해 미리 준비해 두는 것이다.

명령 (2)는 아직 미완성이 이 프로그램에서는 사족과 같은 것이지만, 나중에 디버그에

의존하지 않고 독립된 프로그램으로 16진수를 읽어 들여 그 값을 dl 레지스터로 복사하는

모양을 미리 연습하는 의미가 있다고 생각하고 약간 수고하자.

다시 말해서 이 프로그램에서는 (2) 명령줄을 생략하고, 실행하기 전에 16진수

1 자리를 곧장 dl 레지스터로 입력해도 마찬가지로 실행이 된다.

명령 (3)은 16진수의 첫 문자 0이 코드값 30에 배당되어 있기 때문에 입력된 문자에

30을 더해 주어 입력된 숫자와 같은 문자를 출력하는 명령이다.

그러나 이 명령의 효력은 입력된 16진수가 0에서 9까지의 범위에 들어 있어야만

정상적으로 나타난다.  만약 a에서 f 사이의 숫자가 입력되면 문제는 달라진다.

그 문제를 해결하기 위해 명령 (4) (5) (6)이 필요한 것이다.

그 3 줄의 명령을 다시 나누어 살펴 볼 필요가 있다.

명령 (3)에서 30을 보탠 결과 dl 레지스터의 값이 39 이하이면 입력된 16진수는

0에서 9까지에 들어 있으므로 곧장 int 21h 명령으로 출력하면 그만이다.

그 내용이 (4) (5) 명령줄에 포함되어 있는 것이다.

(4) 명령은 입력된 16진수에 30을 더한 결과 증가한 dl 값을 3a와 비교하는 것이며,

이어지는 (5) 명령은 만약 dl 값이 3a보다 작은 경우 jl 명령의 조건(less than)이

참이므로 int 21h 명령으로 점프하여 그대로 출력하게 된다.

그러나 만약 증가된 dl 값이 3a보다 작지 않으면(같거나 크면), 보다 작다는 조건이

거짓이 되므로 점프 명령은 무시되고 그 다음의 (6) 명령이 실행된다.

(6) 명령에서는 코드값 3a로부터 40까지 7 자리를 차지하고 개 밥에 도토리같이

끼어 있는 7 개의 특수문자를 무시하기 위하여 dl 값에 다시 7을 보탠다.

마지막 (7) 명령은 앞의 명령 (5)에서 점프되어 넘어온 코드값 30 내지 39에 해당되는

16진수 0 내지 9를 출력하기도 하고, 또는 앞의 명령 (6)까지 거쳐 온 코드값 41

내지 46에 해당되는 16진수 a 내지 f를 출력하기도 한다.

물론, 명령 (1)에서 저장해 둔 ah 값 02를 참조한 작업이다.

이상의 설명이 다소 어려우면, 그냥 읽고 넘어가기 바란다.

나중에 다시 보면 완전히 이해가 될 것이다.



ID:
PW:

     0 분
     4 분

자유게시판

건강백과 HOME

홈페이지 HOME

조   약     HOME

생활지혜 HOME

서식양식 HOME

법원 전산양식 검색

In Na zum

비공개 HOME

백과넷 포탈 : 건강/법률(메인)/홈피/서식/조약/생활지혜

◁ 2002.9.1.~2021.4.11. ▷

관리자 연락(저작권 의심 신고) : 김병희 010-6204-4973 k8z7@hanmail.net