이번호에서는 지난호에서 알아본 프로그래밍 전반에 대한 기본적인 내용들을 마음 속에 두면서, 어셈블리 언어를 이용한 프로그래밍의 첫번째 단계로 모든 프로그래밍에서 그러하듯이 데이터를 전송하는 방법과 키보드에서의 입력과 화면으로의 출려겡 대해서 다루어 보고자 한다.
1. 기초지식
먼저 데이터의 전송에 들어가기에 앞서 어셈블리 언어에서 사용되는 데이터의 형에는 어떤 것들이 있으며 이런 데이터의 형들이 가지는 의미는 무엇인가에 대해서 간단히 다루어 보고자 한다.
* 비트Bit
컴퓨터는 전기의 흐름과 끊김의 두가지 상태를 이용해서 모든 데이터를 처리하게 된다. 즉 전류가 흐르는 경우를 ‘1’이라는 상태로 간주한다면 그 반대의 상태인 ‘0’은 전기가 흐르지 않는 상태가 되는 것이다.이처럼 두가지의 상태만을 가지고 데이터를 처리하는 이유는 물론 효율이라는 관점에서는 전기의 전압을 여러단계로 나누어서 한번의 흐름으로 여러상태를 나타내는 경우에 비하면 뒤떨어지기는 하지만, 컴퓨터에서 무엇보다도 중요한 정확도라는 관점에서 전기의 흐름과 끊김을 이용하는 방법이 전압을 여러 단계로 나누어서 사용하는 것보다 훨씬 정확하기 때문에 이 방법이 사용되고 있는 것이다.그리고 이 ‘0’ 혹은 ‘1’의 상태를 나타내는 가장 작은 데이터의 단위를 가르켜서 우리는 ‘비트Bit‘라고 한다.
* 바이트Byte
‘바이트’라는 단위는 컴퓨터를 사용하면서 가장 많이 접하게 되는 단위로 RAM이나 ROM의 크기, 혹은 하드/플로피 디스크의 용량 등을 나타내는 데에 사용된다.이 단위는 ‘비트’가 확대된 단위로, 영어 분화권에서 사용되는 기호 체계를 표현하기 위한 최소 비트인 8개의 비트가 모여서 만들어진 새로운 단위이다.
* 다른 단위들
‘비트’와 ‘바이트’를 제외한 다른 단위들을 <표 1>에서 보는 것처럼 ‘바이트’를 기준으로 해서 만들어진다.이것으로 어셈블리 언어를 이용하는 경우에 사용가능한 데이터의 크기에 대해서는 간단히 알아보았다. 다음절에서는 지금까지 알아본 데이터의 형태를 어셈블리 언어에서 표현하는 방법에 대해서 알아보기로 하자.
[표1] 정보의 크기를 나타내는 단위
2. 데이터형 선언
데이터를 정의하기 윙해서는 데이터 정의 의사명령이라는 것을 사용한다. 정의하는 데이터의 크기에 대해 어떤 종류의 명령이 사용되는지는 <표 2>를 참조하기로 하고, 여기서는 바이트를 정의하는 DB 의사명령을 예로해서 설명을 진행하기로 하자.DB 의사명령의 사용법은 다음 형태를 따라야 한다.
<라벨> DB <데이터>
[표2] 데이터형의 종류
물론 데이터는 특별히 지정하지 않을 수도 있다. 하지만 라벧은 반드시 사용되어져야 한다.데이터를 초기화하는 방법은 <데이터>의 위치에 초기화하고자 하는 값을 지정하면 된다. 일례로 Character_A 라는 라벧에 ‘A’라는 값을 할당하는 경우를 들어보자. 이 경우에 데이터를 초기화하는 방법에는 두가지으 가방법이 있다. 하나는 ‘A’라는 문자를 직접 지정하는 경우이고, 다른 하나는 ‘A’라는 문자 대신에 그 문자가 가지는 코드값을 <데이터>라는 위치에 위치시키는 경우이다.
Character_A DB ‘A’
Character_A DB 41H
위의 두가지의 경우에는 원시 프로그램에서만 차이가 있지, 컴파일 단계를 거치게 되면 문자로 표현된 Character_A의 경우도 ‘A’라는 문자에 해당하는 코드값으로 바뀌게 된다.이제는 하나의 문자가 아닌 연속된 문자를 생각해 보기로 하자. 이 경우도 앞에서와 같이 두가지의 방법이 있을 수 있다. 하지만 대부분의 사람들이 코드값으로 초기화하기 보다는 출력될 문자열로 지정하는 방법을 선호한다.화면에 출력될 문자열을 초기화하는 방법은 한 문자의 경우와 마찬가지로 문자열을 ”로 둘러싸면 된다. 아래처럼
String_Degine DB ‘Copyright (C) 1991-12-31 By Wild Horse!!!’
바이트 형을 기준으로 해서 데이터를 초기화하고 선언하는 방법을 알아 보았는데 이 방법은 다른 데이터의 형에도 같은 방법으로 적용될 수 있다.<리스트 1>에서는 프로그램이 어떤 특정한 기능을 하는 것이 아니라, 데이터의 형들이 어떤 형태로 선언되는가 하는 내용을 보이기 위한 예제일 뿐이다. 때문에 실행만 될 뿐 아무런 기능도 하지 않는다.
[리스트1] 데이터 형의 선언 방법
3. 데이터 전송명령
위에서 데이터의 크기에는 여러가지의 종류가 있음을 알아보았다. 이제는 데이터에서 데이터로 혹은 레지스터에서 레지스터로, 레지스터에서 데이터로의 전송을 다루어 보기로 하자.
* 세그먼트의 전송
세그먼트와 오프셋은 지난호에서 살펴본 것처럼 16Bit(Word 단위)이므로 Byte 단위의 레지스터나 데이터(변수)와는 전송이 불가능하고, 반드시 16BitWord 단위의 레지스터나 데이터에만 전송이 가능하다.
* 레지스터에 값을 전송
레지스터에 수치값을 전송하는 방법에는 여러가지의 경우가 있다. 이와 같이 여러가지의 구분이 되는 것은 전송되는 수치의 값이 어떤 진수의가 값인가에 따라 결정된다. <리스트 1>에서 보인 것처럼 10진수의 경우는 수치값의 맨 뒤에 아무런 기호도 붙지 않는다. 2 진수의 경우는 ‘B’를, 16진수의 경우는 ‘H’를 8진수의 경우는 ‘O’을 붙여서 수치의 값이 어떤 진수의 값인가를 구분한다.
* 레지스터에 데이터 값을 전송
레지스터에 데이터 값을 지정하는 경우에는 데이터의 값이 어떤 형의 데이터로 선언되었는가에 따라서 전송되는 데이터를 담을 레지스터의 형이 결정된다.
* 데이터에 레지스터 값을 전송
레지스터의 값이 어떤 크기인가에 따라서 데이터의 크기가 결정된다.
* 데이터 간의 전송
데이터 간의 전송인 경우에는 그 데이터의 크기를 같게만 하면 별다른 문제는 없을 것이다.
* 레지스터 간의 전송
레지스터 간의 전송인 경우에는 그 레지스터의 크기를 같게만 한다면 별다른 문제는 없을 것이다.
<MOV 명령어>
형태:MOV 제 1 오퍼랜드, 제 2 오퍼랜드
의미:제 2 오퍼랜드의 값을 제 1 오퍼랜드로 옮긴다.
주의:제 1 오퍼랜드와 제 2 오퍼랜드의 크기를 반드시 같게 한다.
4. 인터럽트Interrupt
8086 CPU에서는 256가지의 인터럽트를 지원하고 있다. 각각의 내용은 <표 3>를 참조하기로 하고, 지금은 인터럽트가 발생한 경우에 내부적으로 일어나는 처리의 매커니즘에 대해서만 간단히 알아보기로 하자.프로그램의 실행 중에 인터럽트가 발생하게 되면 메모리 0-3FFH에 위치한 인터럽트벡터 테이블을 참조하여 인터럽트의 내용이 있는 부분으로 점프하여 그 부분에 위치한 내용을 처리한 후에 IRET 명령에 의해서 인터럽트가 발생한 바로 다음의 위치로 돌아오게 된다. 인터럽트 벡터 테이블의 구성은 하나의 인터럽트가 4 Byte를 차지하는데 두 바이트씩 묶어서 인터럽트의 내용이 위치한 세그먼트와 오프셋을 가리키게 된다.<리스트 3>에서는 PC 인터럽트의 내용을 이용하는 간단한 예로 보통 키보드의 Print Screen 키를 눌러서 화면의 내용을 프린터를 통해서 프린트하는 것을 프로그램을 통해서 구현해 보았다. 프로그램의 사용시 주의해야 할 것은 키보드를 사용한 경우, 프린터가 준비가 되어 있지 않은 상태에서 Print Screen을 눌러도 시스템이 다운되는 일은 없지만 인터럽트를 부르는 경우에는 프린터가 준비되어 있지 않은 상태에서 프로그램을 실행하게 되면 시스템이 다운되게 되므로 사용하기 전에 주의를 해야 한다.
[표3] PC인터럽트의 종류
5. 키보드에서 입력
지금까지는 프로그램 내부에서의 데이터 전송에 대해서 알아보았다. 이제는 전송의 범위를 좀더 광범위하게 확대하여 키보드와 화면을 대상으로 한 전송에 대해서 다루어 보기로 하자.키보드로부터 데이터를 입력받는 방법에 대해서 알아보기 전에, 지난호의 예제에서 다룬 아스키 코드와 스캔코드에 대해서 좀더 자세히 알아보기로 하자.
* ASCII 코드
위에서 우리는 ‘바이트’라는 단위가 8개의 ‘비트’가 모여서 이루어진 단위임을 알아보았다. 그런데 왜 하필이면 ‘비트’가 8개가 모인 것을 가리켜서 ‘바이트’라는 단위로 칭했을까? 그 까닭은 다음과 같이 설명될 수 있다.컴퓨터는 인간의 수고를 덜기 위해서 만들어졌다. 때문에 컴퓨터가 만들어진 영어 문화권에서 사용하는 기호체계를 컴퓨터에서 사용 가능하도록 하는 것은 너무나도 당연한 일이었다.따라서 그들이 필요로 하는 알파벱의 대소문자, 숫자, 특수문자등을 포함할 수 있는 최소 비트를 생각하게 됐고, 이 결과로 8 비트로 구성된 ‘바이트’라는 새로운 단위가 생겨났으리라. 그리고 8개의 ‘비트’로 구성된 ‘바이트’의 각각의 코드에 그들이 사용하는 기호체계를 할당하여 사용하게 되었고, 이렇게 사용되는 여러개의 코드체계 중에서 가장 널리 사용되는 코드 체계가 바로 이 ASCII 코드라는 것이다. <표 4>에서는 ASCII 코드의 각각에 할당되어져 있는 문자들을 보였다.이 표를 참조하면 키보드의 어떤 키는 어떤 코드 값을 가지며, 독자들이 어떤 문자를 화면에 출력하고자 하는 경우에는 어떤 코드를 사용하면 되는 가를 알 수 있다.지면 관계상 널리 사용되는 127번 이전의 문자들만을 실었다. 만약 다른 코드를 알고자 한다면 화면에 문자를 출력하는 간단한 프로그램을 독자들 스스로 작성해서 참조하기 바란다.
[표4] ASCII코드체계
* SCAN 코드
SCAN 코드는 키보드가 눌려진 경우에, 키보드에 있는 마이크로 프로세서가 컴퓨터로 보내는 코드값을 말한다. 이 SCAN 코드값을 얻기 위해서는 인터럽트 16h를 이용한다. <표 5>에 SCAN 코드값을 나타내었다.하나의 인터럽트가 4 Byte를 차지하는데 두 바이트씩 묶어서
[표5] SCAN 코드체계
* 키보드로부터 입력의 여러가지 방법
키보드로부터 데이터를 입력 받는 방법에는 여러가지가 있다. 먼저 <표 6>을 보기 바란다.<표 6>에서 Will Wait라는 말은 키보드에서 키가 눌려질 때까지 기다리느냐 그렇지 않느냐를 의미하고, ^Break Seen은 <Ctrl-Break>키가 눌려지는 경우에 프로그램의 실행도중이라도 프로그램 전체를 벗어나서 도스 상태로 빠져나오느냐 그렇지 않느냐를, Will Echo는 눌려지는 키를 화면에 나타내느냐 그렇지 않느냐를 나타낸다. 사용되는 곳에 알맞은 경우를 선택해서 사용하면 된다.<표 6>에 나타낸 것들이 키보드로부터 하나의 문자만을 받아들이는데 반해서 Service 0Ah는 키보드로부터 엔터키가 눌려질 때까지 키를 받아들인다. 이 서비스의 사용법은 다음과 같다.
MOV EX, OFFSET Key_Buffer
MOV AH, 0AH
INT 21H
이 서비스의 경우는 눌려지는 키가 화면에 표시됨은 물론, ^Break Seen 역시도 작용한다.
[표6] 키보드로 부터 데이터 입력의 여러가지
* 키보드로부터의 입력 예
<리스트 4>에서는 에서 알아본 키보드로부터 문자를 입력받는 여러가지 방법을 테스트 하는 프로그램으로 이 예를 통해서 각각의 방법으 가차이점을 확연히 알 수 있을 것이다.
[리스트4] 키보드 입력의 여러가지
6. 화면으로의 출력
이제는 5절에서 알아본 키보드로 부터의 입력과는 거의 대조가 되는 화면으로의 출력에 대해서 다루어보기로 하자. 어떤 문자를 화면에 출력하는 방법에도 여러가지가 있지만 여기서는 특히 비디오램을 직접 제어하는 방법을 위주로 해서 다루기로 하겠다.도스에서 제공하는 문자의 화면 출력 펑션이 있는데도 굳이 비디오램을 직접 제어하는 이유는 뭐니뭐니 해도 속도가 가장 큰 요인이 될 것이다. 아래에서 다룰 예를 통해서 독자 여러분 스스로가 느껴보길 바란다.
* 화면 출력의 여러가지 방법
지난호에서 우리는
MOV DL, 바이트 단위의 출력할 문자
MOV AH, 2
INT 21H
라는 서비스를 이용해서 화면에 한 문자를 출력하는 방법과
MOV DX, OFFSET 출력할 문자열의 처음 위치
MOV AH, 9
INT 21H
라는 서비스를 이용해서 화면에 문자열을 출력하는 두 가지의 방법을 알아보았다. 여기서는 이와는 다른 방법으로 모니터의 비디오 세그먼트 시작번지를 지정하고 이 부분에 직접 필요한 내용을 써넣는 방법에 대해서 알아보기로 하겠다.이 방법은 도스 펑션을 이용하는 것에 비해서 <표 7>에서 보는 것처럼 많은 장점을 가지고 있다. 때문에 많은 경우에 응용될 수 있으므로 잘 이해해 두기 바란다.이제부터는 <표 7>의 B와 같은 장점을 가지고 있는 비디오램을 직접 제어하여 화면에 문자열을 출력하는 방법에 대해서 알아보기로 하자. 이 방법은 여러가지 면에서 도스 펑션을 이용하는 것 보다 월등히 우수하지만 모니터를 달리하게 되면 바뀌어져야 하는 내용이 생기게 되므로 프로그래머는 이점까지 생각해야 된다는 단점이 있다. 하지만 그만한 노력에 대한 충분하 놉답은 있을 것이다.
[표7] 도스 펑션을 이용한 화면출력과(A) 비디오 램의 직접 제어에 의한 화면출력(B)
* 비디오램의 위치 지정
먼저 이 방법을 사용하기 위해서는 각각의 모니터에 합당한 비디오램의 위치를 지정해 주는 일이 기본적으로 필요하다. 이 비디오 램의 위치는 <표 8>에 정리하였다. 하지만 이것만으로 끝나는 것은 아니다. 물론 사용하는 모니터에 따라서 비디오 램의 위치를 수정하고 다시 컴파일하고 링크하는 방법으로는 실행이 가능은 하지만 이 보다는 현재 사용하고 있는 모니터의 종류를 알아내어 그에 합당한 세그먼트를 지정하도록 하는 방법이 훨씬 좋은 방법일 것이다. 이 방법은 <리스트 5>에 실었다.위의 방법으로 비디오 램의 시작 위치는 지정되었다. 그러면 어떻게 화면의 특정 부분에 문자를 출력할 수 있을까? 이문제에 대한 해담은 다음과 같은 간단한 식으로 주어질 수 있다. 만약 출력하고자 하는 화면의 위치가 (X,Y)라고 하면,
위치 = X * 160 + Y * 2
라는 식에 의해서 문자를 출력할 비디오 램의 특정 위치는 결정된다. 위의 식에 의해서 계산된 위치를 DI(BX, SI, BP 레지스터도 가능하다.) 레지스터에 넣어주고, Init_Scr에 의해서 지정되는 ES(엑스트라 세그먼트)에 워드 단위의 데이터를 출력하면 된다. 여기서 워드 단위로 출력하는 이유는 앞의 바이트는 화면에 출력될 문자를 나타내기 때문이다.
MOV AX, 7141H ; 70H : 반전 속성, 41H : 문자 ‘A’
MOV WORD PTR ES:[DI], AX ; 위는 허큘리스의 경우이다.
이 문제에 대한 좀 더 자세한 내용은 5번째의 연재인 화면제어와 파일제어에서 좀더 자세히 다룰 예정이다. 자세한 내용은 그때에 참조하기 바란다.
[표8] 각 모니터의 비디오 램 위치
* 화면 출력의 예
다음의 예는 다른 프로그램으로의 확장을 위해서 특정한 레지스터를 통해서 인수를 전달하지 않고 스택을 통해서 인수를 전달하도록 한 비디오 램을 통한 문자열 출력의 예를 보여주고 있다. 사용방법은 가장 먼저 출력할 문자열의 오프세가을 스택에 PUSH하고, 그 다음에 출력될 화면의 위치를, 그리고 마지막으로 출력될 문자의 속성내지는 색깔을 스택에 PUSH 해주는 방식으로 사용된다.
7. 예제 프로그램
지난 호에서 우리는 Code View라는 예제를 통해서 키보드로 부터 문자의 입력과 화면으로의 데이터 출력을 간단히 다루어 보아쌀. 여기서는 지난호의 Code View를 버젼업 시키기 위한 첫단계로 비디오 램을 통한 문자열의 출력을 이용해서 Code View의 화면을 구성하는 방법을 예로 보였다.
8. 그밖에
필자는 프로그래밍을 공부하는데 있어서 문법을 공부하고 프로그램을 작성하는 방법보다는 프로그래밍을 통해서 문법을 공부하는 방법을 선호한다. 때문에 연재의 방향도 문법보다는 실무를 위주로 하고 이쌀.때문에 조금은어렵게 느껴질지도 모르겠지만 여러 어셈블러 서적과 함께 이 연재를 보면 도움이 되리라 생각한다._

PC어셈블리 