티스토리 뷰

 

빌딩 블록 마이크로컴퓨터 구조

  • 버스 인터페이스 장치(bus interface unit, BIU) : 마이크로프로세서와 메모리 사이의 통신을 제어한다.

  • 시스템 버스(system bus) : 정보는 한 요소로부터 다른 요소로 통신 채널을 따라 보내지는데 이 채널을 시스템 버스라 말한다.

    • 제어 버스(control bus)

    • 데이터 버스(data bus)

    • 어드레스 버스(address bus)

  • 마이크로프로세서의 실행 장치(execution unit, EU) : 산술 연산을 수행하며 메모리 번지 계산도 한다.

메모리와 입력/출력

  • 메모리에 저장될, 또는 계산에 사용하기 위하여 메모리로부터 꺼낼 데이터 항목은 데이터 버스를 통하여 전송된다. 데이터 항목을 저장하거나 읽어낼 번지는 어드레스 번지를 통하여 전송된다. 데이터 항 목을 저장하고 읽어내는 것을 포함하여 마이크로프로세서 내에서의 모든 동작은 마이크로프로세서에 의해 수행 되지만 조종은 제어 버스가 한다.

  • 8086 패밀리를 사용한 컴퓨터에서 모든 통신은 시스템 버스를 통하여야 한다.

  • 외부 장치는 직접 시스템 버스에 연결하지 않고 Interface에 연결한다.

  • 직접 메모리 액세스(direct memory access, DMA) : 마이크로프로세서가 처음에 입출력을 시작하도록 하는 것 이외에는 마이크로프로세서의 아무런 간여 없이 메모리와 직접 입출력을 수행하는 방법이다. 따라서 입출력 동작의 속도가 높아진다. 스크린 디스플레이로의 출력은 이런 방법으로 한다.

  • 메모리의 각 장소에는 8비트가 저장되기 때문에 데이터 버스는 최소한 8가닥(전선)으로 구성된다.

  • 8086과 80186은 데이터 버스가 80286처럼 16비트이고 80386은 데이터 버스가 32비트로서 크기가 20억이 넘는 정수를 저장하고 읽어내는 일을 한 동작으로 할 수 있다.

  • 어드레스 버스

    • 8086,80188,80186 - 20비트

    • 80286 - 24비트

    • 80386,80486 - 32비트

    • 8086 패밀리의 모든 맴버는 20비트 세그먼티드 메모리 번지에 기초한 명령어들을 실행할 수 있다.

  • 80286 마이크로프로세서

    • real address mode(실제 번지 모드)

    • protected virtual address mode(보호 가상 번지 모드)

      • 다중 작업 허용

      • 다중 작업을 위해 메모리 관리와 작업 전환을 가능하게 하는 명령어가 있다.

  • 가상 모드 : 가상 모드에서 마이크로프로세서가 메모리 관리 하드웨어에 의해 물리 번지(physical address)로 변환되는 가상 번지와 함께 동작한다는 사실로부터 유래되었다.

  • 가상 번지 : 정상적인 의미로는 번지이나 각 가상 번지에 대해 메모리의한 장소가 반드시 있어야 한다는 제한은 없다. 즉, 보통 실제 메모리 장소보다 많은 가상 번지가 존재한다. ex)80286, 가상 번지 2^30개, 실제 번지 2^24개

    • 한 작업이 물리적으로 가능한 것보다 더 많은 메모리를 요구하면 명령어의 실행에 필요하지 않은 가상 위치의 내용들은 디스크에 존재하며 필요할 때 메모리로 교체된다. 80286 마이크로프로세서의 특수한 명령어와 레지스터가 이 교체 과정(swapping process)를 제어한다.

버스 인터페이스 장치

  • BIU(Bus Interface Unit) : 각 기계 코드 명령어를 일련의 작은 단계들로 나누는 전자 스위치들의 집합에 불과하다. 명령어를 그의 구성 성분들로 해독(decode)하고 멸령어가 실행되도록 준비하는 일은 BIU의 책임이다.

    • 인출 사이클(fetch cycle)

    • 해독 사이클(decode cycle)

    • 실행 사이클(execute cycle)

  • 기계 코드 명령어를 실행하는 첫 단계는 메모리로 부터 명령어를 BIU 내의 6바이트 큐에 복사하는 것이다. 버스 인터페이스 장치는 명령어 큐(instruction queue)가 항상 가득 차도록 한다.

  • 전자 클럭(electronic clock) : 컴퓨터 내에서의 동작을 동기화 시키는데 쓰인다. 펄스의 형태

  • 해독(decode) : 명령어의 동작 부분과 operand(연산수) 부분을 분리한다.

  • 산술 논리 장치(arithmetic and logic unit,ALU) : 산술 및 논리 연사을 실제로 수행한다.

8086 패밀리 칩

  • 어드레스 버스에 연결된 회로는 어드레스 버스에 있는 이 번지를 받아서 유지해야 한다. 이것은 번지를 레치(latch)한다고 한다.

  • 핀 번호 40은 8086 마이크로프로세서 기반 마이크로컴퓨터가 기동하도록 하는 신호를 받아들이는 일을 한다. 마이크로프로세서가 이 핀으로 들어오는 신호를 받으면, 명령어를 자동적으로 위치 FFFF:0000에서 가져오게 된다. 이 번지는 ROM에 있다. 그 다음에 그 명령어가 마이크로컴퓨터의 오퍼레이팅 시스템, 즉 BIOS의 처음부터 실행을 걔속하도록 한다. 그 다음에는 컴퓨터에 디스크 드라이브가 있다면 DOS를 호출한다. 이와 같이 컴퓨터를 기동시키는 것을 부트스트랩(bootstrap)이라 한다.

  • 수정 진동자 : 인텔 8284 클럭 발생기(clock generator) 칩에 타이밍 펄스를 공급한다. 이 칩은 컴퓨터 전체 동작을 위해 동기 펄스를 공급한다.

  • 8288 버스 제어기 칩 : 마이크로프로세서와 시스템 버스 사이의 인터페이스를 제어한다. 이 칩은 어뎁터 카드(adaptor card)사이의 상호 연결을 제어한다.

  • 어드레스 버스상의 번지는 8283 레치 칩이 레치하였다가 9297 버스 구동기(busdriver)에 의해 지정된 곳으로 보내진다. 이 칩을 트랜시버(transceiver)라 하는데 그 이유는 신호를 보낼 수도 있고 받을 수도 있기 때문이다. 다른 8287 버스 구동기는 데이터 버스에 사용된다.

  • 8259 인터럽트 제어기(interrupt controller) : 마이크로프로세서가 현재 실행하고 있는 프로그램이 가로채어지도록 여러 호출들을 상호 조정한다.

  • 키보드 제어기(keyboard controller) : 이 칩은 키를 누를때 키보드로부터 보내져온 신호를 해독한다. 이것은 자신의 RAM과 ROM을 가지고 있다. ROM에는 해독 프로그램이 들어있고, RAM이 들어오는 키 누름을 기억하기 때문에, 사용자가 소프트웨어가 처리할 수 잇는 속도보다 더 빨리 타이핑하여도 문자는 손실되지 않는다.

  • 프로그래머블 인터벌 타이머(programmable interval timer,PIT) : DRAM은 저장되어있는 내용을 유지하기 위하여 정기적으로 그 내용을 재충전(refresh) 해야하는 형의 메모리이다. PIT는 RAM을 재충전하는 요구를 발생하는 타이밍 신호를 만들어 낸다. 또한 내부 스피커를 구동하는 신호도 만들어 낸다.

  • 직접 메모리 액세스(DMA) 제어기 : 이 칩은 DMA를 가능하게 한다. 즉 입출력 동작을 시작하도록 하는것 외에는 마이크로프로세서의 개입 없이 메모리와 입출력하도록 한다. 이렇게 하면 입출력 동작 속도가 빨라지게 된다.

  • 프로그램 가능 주변 장치 인터페이스(programmable peripheral interface) : 키보드와 같은 시스템 주변 장치를 제어한다.

  • 리얼 타임 클럭(real time clock) : 클럭과 달력 기능이 있어서 현재 신간과 날짜를 내부 RAM에 유지한다. 배터리로 전원 공급

  • 명령어 장치(instruction unit) : 버스 인터페이스 장치가 가져온 6바이트의 큐로부터 명령어들을 가져와서 이들 명령어를 해독하고, 이 해독된 형태를 해독된 명령어 3개까지 저장할 수 있는 큐에 저장한다.

  • 보호 가상 번지 모드에서 멀티태스킹은 번지 장치(address unit)를 통하여 제어된다.

  • 실행 시간 = 클럭수의 합 / 주파수

명령어와 번지

  • BX는 프로그램 실행 동안에만 결정되는 메모리 위치를 액세스하도록 해준다.

  • 8086 패밀리 마이크로프로세서는 세그먼티드 메모리(segmented memory)를 사용하므로 모든 번지는 반드시 세그먼트:옵셋 형식으로 주어져야 한다.

  • 코드 세그먼트 레지스터 CS : 프로그램 명령어를 기억하는 메모리 세그먼트 번지를 엑세스하는 데 사용 .

  • 데이터 세그먼트 레지스터 DS : 데이터 항목을 기억하는 메모리 세그먼트 번지를 액세스하는 데 사용.

  • 스택 세그먼트 레지스터 SS : 작업 영역을 기억하는 메모리 세그먼트를 액세스하는 데 사용.

  • 엑스트라 세그먼트 레지스터 ES : 8086 패밀리의 특수 명령어가 문자열을 조작할 때 사용.

  • 명령어의 경우 옵셋은 명령어 포인터(instruction pointer,IP)라는 16비트 레지스터가 지정한다.

  • 데이터 항목의 옵셋은 프로그램에서 명시적으로 주어진 값에 의하여, BX의 내용에 의하여, 또는 다른 두 개의 16비느 레지스터 SI와 DI의 내용에 의하여 지정된다.

항목

세그먼트 레지스터

옵셋

명령어

CS

IP

프로그램 데이터

DS

명시적으로 BX,또는 SI,DI

스택내의 항목

SS

SP 또는 BP

문자열내의 문자

ES

DI

  • <그림5>BIU와 EU 내에서의 레지스터의 위치

  • MASM 에서 모든 점프는 인트라 세그먼트(intra-segment) 즉, 동일 세그먼트 내에서일어난다고 가정한다. 인터 세그먼트 형태로 할려면 (점프 명령어) LABEL FAR 로 한다. 목적지 번지는 4바이트로 표현된다.

  • 산술 연산에 자주 쓰이는 레지스터 AX,BX,CX,DX와 SP,BP,SI,DI,플래그 레지스터, ALU는 실행 장치에 위치 하고 있다.

  • SI와 DI는 배열 요소의 인덱스 번지 지정에 그리고 스트링 조작에 사용된다.

  • 세그먼트 레지스터(CS,DS,SS,ES)와 IP, 번지 생성 및 버스 제어, 명령어 큐는 버스 인터페이스 장치에 위치한다.

  • 프로그램 명령어의 번지는 CS와 IP에 의해 지정된다. 실행될 차기 명령어의 위치는 CS0 + IP 이다.

  • 데이터 항목의 번지 지정은 DS0 + 명령어에서 주어진 번지 이다.
    DS 에의 로드는 간접적으로 로드하여야 한다.
    ex)MOV AX,500H
    MOV DS,AX

  • 어셈블리의 기본 형태
    DATA SEGMEN
    데이터 항목의 정의
    DATA ENDS
    WORKING_STORAGE SEGMENT STACK
    이 프로그램의 작업 영역
    WORKING_STORAGE ENDS
    CODE SEGMENT
    ASSUME DS:DATA, SS:WORKING_STORAGE,CS:CODE

    PROG_START : 8086 패밀리 명령어
    CODE ENDS
    END PROG_START

  • ASSUME : 각 세그먼트 레지스터와 세그먼트를 결부시켜 준다.

  • 세그먼트 레지스터는 어떤 값을 직접 로드할 수 없다.

기억 공간의 할당

  • 기억 공간의 할당은 의사 명령어(pseudo-op)로 한다. 주요 다섯 가지 형식의 define 의사 멸령어는 다음과 같다.

    • DB : Define Byte(8 bits,1 byte)

    • DW : Define Word(16 bits,2 bytes)

    • DD : Define Doubleword(32 bits,4 bytes)

    • DQ : Define QuadWord(64 bits,8 bytes)

    • DT : Define Tenbytes(80 bits,10 bytes)

  • ex) DB 16H : 초기치가 16H인 한 바이트의 기억 공간 할당
    DB ? : 초기치가 정해지지 않은 한 바이트의 기억 공간 할당
    DB 'Z' : 초기치가 문자 Z에 대한 ASCII 값을 한 바이트의 기억 공간 할당
    DW 1992D : 초기치가 1992D인 두 바이트의 기억 공간 할당 . n 번지에 C8, n+1 번지에 07 위치함
    DB 21H,45H,73H,'A','B,11H,'Z'
    DB 'HELLO' : 5바이트의 기억 공간 할당. 순차적으로 저장
    DB 10H DUP('A') : 10H개의 위치를 할당하여 'A'의 아스키 값으로 초기화
    DB 80H DUP(?) : 초기치가 정해지지 않은 80H 개의 위치를 할당
    MY_BYTE DB 32H : MY_BYTE 는 변수와 같이 사용 함

  • DATA SEGMENT 다음 나오는 데이터의 옵셋은 0 이다.

데이타 항목의 액세스

  • MOV AL , AFFIRM_MESSAGE(변수) : 변수에 저장된 데이터를 레지스터에 assignment 시킨다. AFFIRM_MESSAGE에 해당하는 실제 번지가 12AB:9876이면 앞 문장은 MOV AL , [9876]과 같다(기계 코드로 변환될때 자동으로 이렇게 변환됨).

  • DEC_31_MESSAGE DB 'HAPPY NEW YEAR' : 변수명 DEC_31_MESSAGE는 첫 문자의 위치와 결부 된다.

  • 프로그램에서, 데이터 세그먼트에 저장되어 있는 데이터 항목을 사용하려면 그 데이터를 사용하기 앞서, DOS가 정한 데이터 세그먼트의 시작 번지를 DS 레지스터에 로드하여야 한다. 이 일은 데이터 세그먼트 이름이 DATA인 경우 다음과 같이 한다.
    ex)MOV AX,DATA
    MOV DS,AX

  • 옵셋 : AFFIRM_MESSAGE 번지가 102A:0200이고 DENY_MESSAGE 번지가 102A:0201이면
    ex)MOV BX,OFFSET AFFIRM_MESSAGE
    MOV CX,OFFSET DENY_MESSAGE
    에서 BX에 0200H를 로드하고, CX에는 0201H를 로드한다.

DOS 펑션

  • DOS상에서 어셈블리어 프로그램이 사용하는 펑션은 어셈블리어 프로그램의 정상적인 실행 방식 즉 한 줄 한 줄 씩 실행하는 것을 가로채는 방식으로 동작한다. 즉 오퍼레이팅 시스템의 고유 기계 코드 명령어로 분기 할 수 있다. 8086 패밀리 명령어 INT(interrupt)를 사용, 256 개의 서로 다른 종류의 인터럽트가 가능하다. 명령어 INT 21H를 이용하면 모든 입출력 펑션을 수행할 수 있다. 펑션은 레지스터 AH에 코드 번호를 넣어서 지정한다.

펑션 번호

명 칭

동 작

1

키보드 입력

키보드에 한 문자가 타이핑될 때까지 기다린다. 문자가 입력되면 그 문자의 ASCII 코드를 레지스터 AL에 넣는다. 입력된 문자는 디스플레이 스크린의 현재 커서 위치에 디스플레이된다. CTRL-BRK가 눌러지면 제어는 자동적으로 DOS로 넘어간다.

2

디스플레이 스크린에 출력

레지스터 DL에 들어있는 ASCII 코드의 문자를 디스플레이 스크린에 프린트한다. 문자는 디스플레이된 마지막 문자 바로 다음에 디스플레이된다.

3

비동기 입력

문자 한 자가 비동기 통신 어댑터 카드를 통하여 들어오기를 기다린다. 문자가 들어오면 그 문자를 AL에 기억시킨다.

4

비동기 출력

DL에 들어 있는 문자를 비동기 통신 어댑터 카드로 보낸다.

5

문자를 프린트

DL에 있는 문자를 프린터로 보낸다.

6

키보드 입력/문자 디스플레이

DL=0FFH이면서 키보드에 문자가 준비되어 있으면 ZF를 0으로 하고 그 문자를 AL에 넣는다. 이때 문자가 준비되어 있지 않으면 ZF를 1로 하고 기다리지 않는다. DL<>0FFH이면 DL의 내용은 ASCII 코드로 해석되어 해당 문자가 스크린에 디스플레이된다.

7

키보드 입력/디스플레이 안함

키보드로부터 입력 문자를 기다린다. 문자가 도착하면 이를 AL에 넣는다. 문자는 자동적으로 디스프레이 스크린에 프린트되지 않는다. DOS로 돌아가기위해 CTRL-BRK를 사용할 수 없다.

8

키보드 입력/디스플레이 안함

CTRL-BRK 서비스가 제공되는 것을 제외하면 펑션 7과 같다.

9

스트링 디스플레이

DX가 가리키는 스트링을 디스플레이 한다. 이때 스트링은 끝에 $ 기호가 있어야 한다. 물론 $ 기호는 프린트 되지 않는다.

A

키보드로부터 스트링 입력

키보드로부터 스트링을 읽어 DS:DX에 있는 번지에서 시작하는 메모리에 저장한다. 사용자가 입력한 첫 번째 바이트는 스트링의 입력 가능한 최대 바이트 수이며, 두 번째 바이트는 스트링의 실제 바이트 수이다. 스트링의 실제 문자는 세번째 바이트에서부터 저장된다.

B

키보드 상태

키보드에 문자 한 자가 준비되면 AL이 0FFH로 설정된다. 그렇지 않으면 AL은 0으로 설정된다. CTRL-BRK를 체크한다.

C

키보드 버퍼 지우기

키보드 내의 키보드 버퍼를 클리어시키며, AL이 지정하는 INT 21H 펑션(1,6,7,8,0AH만 허용)을 수행한다.

4C

DOS로 복귀

프로그램 실행을 종료하고 제어를 DOS로 넘긴다. 에러 레벨을 AL에 설정할 수 있다. 보통은 AL을 0으로 설정하는 것이 가장 좋다.

  • 한 문자를 AL로 일어들여(동싱에 문자를 스크린에 디스플레이) 대문자로 변환하여 그 문자를 디스플레이한다.
    NEXT_CHARACTER: MOV AH,1
    INT 21H
    SUB AL,20H
    MOV DL,AL
    MOV AH,2
    INT 21H
    JMP NEXT_CHARACTER

  • 뉴 라인을 프린트 한다.
    MOV DL,0DH //CR
    INT 21H
    MOV DL,0AH //LF
    INT 21H

  • 프로그램 실행을 종료하고 제어를 DOS로 되돌리기
    MOV AX,4C00H (AH : 4CH, AL : 00H)
    INT 21H

실행

  • MASM filename,,,, : 어셈블 과정에서 4개의 컴마에 의해 선택된 MASM 옵션때문에 두 개의 새로운 파일이 생성된다.
    filename.LST : 어셈블리어 프로그램 그 자체. 16진수로 표현된 기계 코드. 그리고 어셈블러에 에러가 있는 경우 검출된 에러의 코드.
    filename.OBJ : 어셈블리어 프로그램에 대한 기계코드. 이것은 실행될 수 없다.

  • LINK filename,,,; : 링커는 .MAP 과 .EXE의 두 가지 파일을 새성한다.
    filename.MAP : 각종 프로그램 세그먼트의 시작 및 종료 번지의 리스트가 들어있다.

  • 프로그램과 데이터의 실제 위치는 DOS가 결정한다.

  • 어셈블코드가 바이너리로 바뀌면
    ,AX => D8H
    ,AL => D0H
    ,BX => C3H
    ,CL => C1H
    MOV AX, => B8H
    MOV AH, => B4H
    MOV CL, => B1H
    MOV DX, => 8EH
    MOV DL, => 8AH
    INT => CDH
    SUB AL, => 2CH
    ADD AX, => 03H
    ADD DL, => 02H
    JZ => 74H
    JMP => E9H

  • 절대 번지(absolute address)를 사용할 때는 DOS 또는 디버거를 건드려 시스템을 다운시킬 수도 있으므로 조심해야 한다.

  • ORG 의사명령어 : 지정한 옵셋에 이미 도달한 것처럼 멸령어나 데이터에 기억 공간을 할당하도록 한다.
    ORG 200H
    FIRST_LOCATION DB ?
    이렇게 하면 FIRST_LOCATION이 데이터 세그먼트의 시작에서 상대적인 위치 200H를 참조하게 된다.

DEBUG

  • DEBUG의 기동 : DEBUG filename.EXE 그러면 DEBUG 프롬프트(-)가 스크린의 왼쪽 가장자리에 나타난다.

CodeView

  • CodeView의 기동 :
    MASM /ZI filename,,,,
    LINK /CO filename,,,;
    CV /T filename
    CodeView의 프롬프트는 ">"이다.

  • >N16 : CodeView가 모든 숫자를 16진수로 취급하도록 한다.

  • >S& : 혼합 모드로 설정 한다.(를 하면 레지스터 윈도우가 사라지나 F2로 토글 시킬 수 있다.)

  • DWn : DS:n에서 시작하여 메모리 내용을 워도르 디스플레이한다.
    DBn : DS:n에서 시작하여 메모리 내용을 바이트로 디스플레이한다.
    DUn : DS:n에서 시작하여 메모리 내용을 부호없는 10진 정수로 디스플레이한다.
    D : 출력 형식을 모를 때는 그냥 D만 입력해 보면 알 수 있다.

  • EWn : DS:n에서 시작하여 메모리의 내용을 워드로 입력한다.
    EBn : DS:n에서 시작하여 메모리의 내용을 바이트로 입력한다.
    EIn : DS:n에서 시작하여 메모리의 내용을 정수로 입력한다.
    끝내기 위해선 ENTER 키를 누른다.

  • ? : 기호 또는 표현식의 값을 디스플레이한다.
    ex)>? LOC_ONE
    0x01ab
    >
    >? LOC_ONE,I . ? LOC_ONE,D 는 정수나 10진 형식으로 요청한다.
    >? BY SP 는 SS:SP가 가리키는 바이트의 내용을 물어 본다.(BY => BYTE)
    >? WO DS:0 는 DS:0에 있는 워드의 내용을 물어 본다.(WO => WORD)

  • F4 : 를 누르면 DOS 스크린과 디버거 스크린 사이를 왔다 갔다 할 수 있다. I/O를 사용하는 프로그램의 디벙깅

DEBUG와 CodeView의 기본 명령

플래그 이름

세트된 경우

리세트된 경우

Overflow

OV

NV

Direction

DN

UP

Interrupt

EI

DI

Sign

NG

PL

Zero

ZR

NZ

Auxiliary carry

AC

NA

Parity

PE

PO

Carry

CY

NC

  • R : 레지스터의 내용을 디스플레이한다.
    and RIP : 디버거는 레지서터 IP의 현재 내용을 디스플레이한다.

  • RCX : 디버거는 CX 레지스터의 현재 내용을 디스플레이한다. 또한 IP의 값을 바꿀 수 있다.

  • Un : CS의 옵셋 n에서 시작하여 메모리 내용을 역어셈블한다.
    and UCS:offset (or UDS:offset) 은 CS0(or DS0) + offset에서 시작하여 메모리 내용을 역어셈블한다.

  • Dn : DS의 옵셋 n에서 시작하여 메모리 내용을 16진수와 ASCII 코드로 디스플레이한다.

  • Ga : 번지 CS:IP에 있는 명령어에서 시작하여 CS의 옵셋 번지 a에 있는 명령어 바로 앞의 명령어까지 실행한다.
    실행 결과 메모리의 내용을 확인하기 위해서는 D 명령을 사용하여야 한다.

  • Tn : n개 명령어의 실행을 추적한다.
    실행될 명령어의 번지는 CS:IP에 의해 지정되기 때문에 추적을 시작하기 전에 IP 레지스터를 적절히 설정해야 한다.

  • Ea : 메모리 위치 DS:a 에 값을 입력한다.
    이때 현재값을 바꾸고 싶지 않으면 스페이스 바를 한 번 누른다. 그러면 다음 위치의 현재값을 디스플레이하고 역시 새로운 갑을 입력하도록 기다린다. 이하 마찬가지로 된다. ENTER 키를 누르면 E 명령은 끝난다.

  • Aa : 입력된 명령어를 어셈블하고 번지 CS:a 에서 시작하여 저장한다.
    ENTER 키를 누르면 A 명령은 끝난다.

  • Q : 디버거 사용을 끝내고 DOS로 돌아간다.

플래그

  • ADD와 SUB는 모든 산술 플래그에 영향을 준다. INC는 캐리 플래그를 제외한 모든 플래그에 영향을 준다. MOV는 어떤 플래그에도 영향을 주지 않는다.

  • carry flag, CF : 부호 없는 수의 산술 연산에서 어떤 명령어가 지정된 레지스터나 메모리 위치에 기억시킬 수 없을 만큼 너무 큰(또는 너무 작은) 부호 없는 수를 생성하였는지를 나타낸다.

    • 0FFH(AL) + 4 -> 103H : 1로 세트됨

    • 2 - 0FFH(AL) -> 03H : 1로 세트됨

    • 연산 결과가 잘 못 되었는지를 알 수 있다.

  • overflow flag, OF : 부호 있는 수의 연산 결과가 올바른 범위안에 있는지를 나타내는데 이용한다. 80H ~ 7FH 번위를 벗어나면 1로 세트

  • sign flag, SF : 부호 있는 수의 연산 결과가 양수인지(0으로 세트) 아니면 음수인지(1로 세트)를 나타낸다.

  • zero flag, ZF : 연산이 0을 생성했는지를 기억한다. 결과가 0이면 1로 세트, 0이 아니면 0으로 세트

  • parity flag, PF : 연산 결과에서 1의 개수가 짝수이면 1로 세트, 홀수이면 0으로 세트된다.

  • direction flag, DF : DF를 0으로 설정하면, 8086 계열의 특수하 스트링 조작 명령어가 해당 인덱스 레지스터를 증가시켜 메모리에서 번지가 증가하는 방향으로 스트링을 조작하도록 한다. DF가 1이면 반대이다.

  • 보조 캐리 플래그, AF : 오른쪽 4번째 비트에서 캐리 또는 빌림수가 발생햇는지의 여부를 나타내는 점외에는 CF와 유사하다.

  • 트랩 플래그, TF : TF를 1로하여 8086 계열 마이크로프로세서를 싱글 스텝 모드(single step mode)로 동작하도록 할 수 있다.

  • 인터럽트 가능 플래그, IF : 정상적인 8086 계열 동작이 주변 장치 및 기타 원천으로부터 인터럽트되는 것을 허용한다.

명령어

  • BYTE PTR, WORD PTR : (e.g.)  INC BYTE PTR [BX] (메모리 접근시)

  • INC : 오퍼랜드를 하나 증가시킨다. CF를 제외한 모든 산술 플래그에 영향을 준다.{레지스터,메모리}

  • DEC : 오퍼랜드를 하나 감소 시킨다. CF를 제외한 모든 산술 플래그에 영향을 준다.{레지스터,메모리}

  • ADD : 두개의 오퍼랜드를 더해서 앞의 파라미터에 저장한다. {(레지스터,숫자),(메모리,숫자),(레지스터,레지스터),(레지스터,메모리),(메모리,레지스터)}

  • ADC : 캐리 플래그의 현재 값이 덧셈에 포함된다는 점을 제외하고는 ADD와 유사하다. {(레지스터,숫자),(메모리,숫자),(레지스터,레지스터),(레지스터,메모리),(메모리,레지스터)}

    • ex) ADC AX, [BX]

    • 0AEEFFH, 4BBCH ( CF=1 )

    • 0AEFFH + 4BBCH + 1 = 0FABCH ( CF=0 )

  • SUB : 앞 파라미터에서 뒤 파라미터를 뺀 다음 앞의 파라미터에 저장한다. {(레지스터,숫자),(메모리,숫자),(레지스터,레지스터),(레지스터,메모리),(메모리,레지스터)}

  • SBB : 캐리 플래그의 현재 값이 뺄셈에 포함된다는 점을 제외하고는 SUB와 유사하다. {(레지스터,숫자),(메모리,숫자),(레지스터,레지스터),(레지스터,메모리),(메모리,레지스터)}

    • ex) SBB DX, BX

    • 캐리 플래그의 현재 내용과 BX의 현재 내용을 더하여 이를 DX 내용에서 뺀 다음 결과를 DX에 저장, 연산전 CF=1 이면 연산후 CF=0 로 된다.

  • CMP(compare) : 비교는 항상 같은 크기의 숫자 사이에서 행하여 져야한다. 레지스터 값은 변화시키지 않고 첫 번째 오퍼랜드에서 두번째를 뺀 결과에 따라 플래그를 설정한다. {(레지스터,숫자),(메모리,숫자),(레지스터,레지스터),(레지스터,메모리),(메모리,레지스터)}

  • NEG : 8비트 또는 16비트의 부호 있는 수를 2의 보수로 바꾼다. 레지스터 또는 메모리의 값이 0이 아니면 CF를 1로 세트, 레지스터 또는 메모리의 값이 0이면 CF를 0으로 세트한다. {레지스터,메모리}

  • MUL : 부호 없는 수의 곱셈 {레지스터,메모리}

  • IMUL: 부호 있는 수의 곱셉(integer multiplication) {레지스터,메모리}

    • 8비트 수를 서로 곱하면 하나는 AL레지스터에 있어야 한다. 16비트 결과는 AX에 저장된다.

    • 16비트 수를 서로 곱하면 하나는 AX레지스터에 있어야 한다. 32비트 결과는 DX(상위 16비트),AX(하위 16비트)에 저장된다.

  • DIV : 부호 없는 수의 나눗셈 {레지스터,메모리}

  • IDIV : 부호 있는 수의 나눗셈( integer division) {레지스터,메모리}

    • 32비트 수 : DX,AX에 있어야 하고 이를 16비트 레지스터 또는 메모리 워드로 나눈다. 결과는 AX에는 몫, DX에는 나머지 저장

    • 16비트 수 : AX에 있어야 하고 이 수를 8비트 레지스터 또는 메모리의 내용으로 나눈다. 결과는 AL에는 몫, AH에는 나머지 저장

    • IDIV는 항상 나머지의 부호와 제수의 부호가 같도록 한다.

  • CBW

    • 부호 있는 8비트 수를 부호 있는 16비트 수로 변환 (8비트->16비트)

    • Al의 최상위 비트를 조사하여 1이면 AH를 0FFH로, 0이면 AH를 00H로

  • CWD

    • 부호 있는 16비트 수를 등가인 32비트 부호 있는 수로 변환

    • AX -> DX,AX로 변환, AX의 최상위 비트가 1이면 DX를 0FFFFH로, 0이면 DX를 0000H로

8086 계열 조건부 점프

  • 점프 메커니즘 :
    만약에 레이블이 가리키는 명령어가 JZ 다음의 위치에서 +127 또는 -128 바이트 이내에 있다면 어셈블러는 레이블을 적절한 숫자로 대체한다. JZ가 실행될 때, 이 숫자는 IP 레지스터의 내용에 더해진다. 모든 조건부 점프가 이 형태를 따른다. 즉, 모든 조건부 점프의 목적지 번지는 조건부 점프 명령어 다음 명령어가 저장된 위치로부터 +127 또는 -128 바이트 이내의 번지라야 한다.
    만약 JMP 명령어에서 레이블이 JMP 명령어 다음 명령어가 있는 위치로부터 0에서 0FFFFH 바이트 이내에 있는 명령어를 가리키면, 어셈블러는 레이블을 두 위치 사이의 거리에 대한 부호 없는 16비트 형태의 숫자로 대체한다. JMP를 실행하면 부호없는 16비트 변위는 IP 레지스터에 더해진다.
    ex)3000 8B C3 MOV AX,BX
    3002 74 0A JZ NEAR_BY ( 0AH는 300EH - 3004H 의 값)
    -----
    300E b1 02 NEAR_BY: MOV CL, 2
    3010 03 C3 ADD AX,BX
    3012 2A C1 SUB AL,CL
    3014 E9 2D 14 JMP FAR_AHEAD (2DH 14H 는 4444H - 3016H 의 값)
    -----
    4444 8A C3 FAR_AHEAD: MOV AL,BL

  • zero 인지를 테스트

    • JZ : zero 이면 (ZF == 1)

    • JNZ : zero 가 아니면 (ZF == 0)

  • 부호 없는 수를 비교

    • JA : 위이면 (CF == 0 및 ZF == 0)

    • JB : 아래이면 (CF == 1)

    • JAE : 위 또는 같으면 (CF == 0)

    • JBE : 아래 또는 같으면 (CF == 0 또는 EF == 0)

    • JNC : 캐리가 발생하지 않으면 (CF == 0)

  • 부호 있는 수를 비교

    • JG : 보다 크면 (ZF == 0 및 SF == 0F)

    • JL : 보다 작으면 (SF != 0F)

    • JGE : 크거나 같으면 (SF == 0F)

    • JLE : 작거나 같으면 (ZF == 1 또는 SF != 0F)

  • overflow 를 테스트

    • JO : overflow가 발생했으면 (OF == 1)

    • JNO : overflow가 발생하지 않았으면 (OF == 0)

  • 부호를 테스트

    • JS : 음수 이면 (SF == 1)

    • JNS : 음수가 아니면 (SF == 0)

  • parity를 테스트

    • JPO : parity가 홀수 이면(PF == 0)

    • JPE : parity가 짝수 이면(PF == 1)

  • CX가 zero인지를 체트

    • JCXZ : CX가 0이 아니면 (CX != 0)

루프

  • do-while문

    • ex) START_REPEAT: -----
      -----------------------
      JNZ START_REPEAT

  • while문

    • ex) START: -----
      JNx STOP
      ----------------
      JMP START
      STOP:

  • for문

    • ex) MOV LOOP_COUNTER,initial_value
      START: CMP LOOP_COUNTER,final_value
      JA STOP
      ------------------------------------
      INC LOOP_COUNTER
      STOP:

  • LOOP,LOOPZ,LOOPNZ

    • for 루프와 같이 미리 반복 회수가 정해져 있을때 사용한다.

    • LOOP START <==> DEC CX . JNZ START

    • LOOPZ : ZF == 1 이고 CX != 0 이면 반복

    • LOOPNX : ZF == 0 이고 CX != 0 이면 반복

    • LOOP,LOOPZ,LOOPNZ,JCXZ 는 모두 +127 ~ -128 위치 이내에 있는 명령어를 참조하는 레이블이 필요 하다.

  • if-else 문

    • ex) CMP ------
      JNZ ACTION_2
      action1
      JMP DONE
      ACTION_2: action2
      DONE:

  • switch문

    • ex) CMP value,value1
      JZ ACTION_1
      CMP value,value2
      JZ ACTION_2
      --------------------
      JMP END_CASE
      ACTION_1: -----
      JMP END_CASE
      ACTION_2: -----
      JMP END_CASE
      --------------------
      END_CASE:

제어

  • HLT : 8086 계열 마이크로 프로세서를 완전히 정지(HALT) 시킨다. 일단 HLT 명령어가 수행되면 컴퓨터의 전원을 끄고 오퍼레이션 시스템을 다시 실행 시켜야 한다.

  • 서브루틴(subroutine)
    ex) 레이블: -----
    -----
    RET
    호출: CALL 레이블
    -RET 명령어는 실행을 CALL 다음의 명령어로 return 시킨다.

  • PUSH <16비트 레지스터>
    - 사본을 스택에 저장
    POP <16비트 레지스터>
    - 스택에서 되찾아 레지스터에 로드한다.
    PUSHF : 플래그 레지스터의 내용을 스택에 저장
    POPF : 플래그 레지스터의 내용을 스택에서 꺼낸다.

  • SS 레지스터에 스택의 시작 세그먼트 번지를 설정, 16비트 스택 포인터 레지스터 SP에 스택의 꼭대기로부터의 옵셋 번지를 설정( 스택 - 최대 64KB 까지 허용)

  • PUSH BX
    -1. SP 레지스터 1감소
    -2. BX의 상위 바이트가 SP가 지시하는 메모리 위치에 저장
    -3. SP레지스터 1감소
    -4. BX의 하위 바이트가 SP가 지시하는 메모리 위치에 저장

  • POP DX
    -1. SP 레지스터가 지시하는 번지에 저장된 바이트를 DL로 복사
    -2. SP레지스터 1증가
    -3. SP레지스터가 지시하는 바이트를 DH로 복사한다.
    -4. SP레지스터 1증가

  • AX와 BX레지스터의 내용 교환
    ex)PUSH AX
    PUSH BX
    POP AX
    POP BX

  • COMMENT : 이 의사 명령어 다음에 오는 빈칸이 아닌 첫번째 문자와 그 다음에 오는 똑같은 문자로 둘러싸인 내부가 설명문이 된다.
    ex)COMMENT * -----
    -----
    ----- *

  • CALL과 RET 명령어는 인트라 세그먼트(intra-segment) 명령어로 알려져 있다. 왜냐하면 서브루틴의 몸체가 CALL과 동일한 세그먼트 내에 존재하기 때문이다.

    • CALL <레이블> : 명령어 다음에 오는 레이블은 부호 없는 16비트 수에 의해 대치되는데 이것은 CALL 명령어의 번지와 서브루틴의 본체를 포함하는 첫번째 명령어의 번지와의 차이이다. CALL 명령어가 실행되면, 부호 없는 16비트 수가 IP레지스터의 내용에 더해지고 CALL 명령어 다음에 오는 명령어의 번지는 스택에 푸쉬된다.

    • RET : 명령어가 실행되면 스택의 꼭대기가 IP레지스터로 팝된다.

    • 0FFFFH 바이트 보다 더 멀리 떨어져 있으면 CALL과 RET 둘 다 인터 세그먼트(inter-segment) 형태로 사용하여야 한다.

    • CALL 레이블이 다른 세그먼트에 있는 서브루틴을 호출하는 경우는 MASM에 의해 CALL <어드레스> 형태로 번역되는데, 여기서 <어드레스>는 4바이트를 차지하며 서브루틴 본체의 번지를 나타낸다.

    • 확실히 말하지 않으면 모든 CALL과 RET 명령어는 인트라 세그먼트로 간주도니다.

  • 프로시저는 서브루틴에 단지 레이블을 붙이고 속성으로서 NEAR와 FAR 중의 하나를 갖도록 한다.
    레이블 :----- (== intra-segment)
    레이블 PROC NEAR (== intra-segment)
    레이블 PROC FAR (== inter-segment)
    ------
    RET
    레이블 ENDP

  • CALLF : 원거리에 있는 서브루틴을 호출

  • RETF : 원거리에 있는 서브루틴으로 부터 되돌아오기 위해 사용된다.

  • 스택에 들어있는 내용을 액세스 하는 방법 : BX는 DS 레지스터에 대한 옵셋인 반면, BP는 SS 레지스터에 대한 옵셋이다.
    MOV DL,[BP]
    는 SS:BP에 있는 바이트를 DL로 이동한다. or MOV register,[BP+n]
    or MOV [BP+n],register

  • RET x
    - 복귀 후 SP가 x만큼 증가한다. x는 16비트 부호없는 수 이다.

  • .RADIX
    - MASM이 가정하는 디폴트 밑수(default radix)를 2에서 16사이의 어떤 수로 설정. 뒤에 밑수를 지정하지 않으면 16진법으로 간주
    ex).RADIX 16

  • ex) PUSH A
    PUSH B
    PUSH C
    메모리
    SP->=== return address
    SP+2 =C=
    SP+4 =B=
    SP+6 =A=

논리 명령어

  • AND - , -

  • OR - , -

  • NOT - , -

  • XOR - , -

  • TEST - , - (<=> AND - , -) : TEST 명령어는 레지스터에는 영향을 끼치지 않고 단지 플래그만 변화시킨다.

쉬프트 명령어

  • SHL 레지스터(메모리) , 1 : 부호 없는 수에 대해서 모든 비트를 왼쪽으로 한 위치 이동, 오른쪽 빈자리에 0을 채운다. 2배 하는거와 같다. 왼쪽에 떨어져 나온 비트는 CF엥 넣는다.

  • SHR 레지스터(메모리) , 1 : 오른쪽으로 이동, 왼쪽 빈자리에 0을 채운다. 1/2배 하는거와 같다. CF가 1이면 2로 나누어진 숫자가 짝수가 아님을 나타낸다.

  • SAL(Shift Arithmetic Left) : 부호 있는 숫자를 2배 한다.
    ex)SAL - , 1

  • SAR : 부호 있는 숫자를 2로 나눈다. 부호 비트는 변화시키지 않는다.
    ex)SAR - , 1

  • 2비트 이상의 쉬프트
    SHL(,SHR,SAL,SAR) register(,memory) , CL(쉬프트시킬 비트 수)

회전 명령어

  • ROL(,ROR) register(,memory) , 1( or CL) : 각각 비트들을 왼쪽 또는 오른쪽으로 회전시키는데 한쪽 끝에서 떨어져 나가는 비트는 한 바퀴 돌아서 다른쪽 끝의 비어있는 위치를 채운다.

  • RCL(,RCR) register(,memory) , 1( or CL) : 한 쪽 끝에서 떨어져 나오는 비트는 캐리 플래그에 들어가고, 캐리 플래그에 있던 비트는 빈 위치로 들어간다.

  • STC(SeT Carry flag) : CF를 1로 설정

  • CLC(CLear Carry flag) : CF를 0으로 설정

  • CLD(CLear Direction flag) : DF를 0로 설정

  • STD(SeT Direction flag) : DF를 1로 설정

스트링 명령어

  • 스트링의 데이터 표현은
    MESSAGE DB 'STRING DATA','$'
    위와 같이 표현한다.

  • CX : 처리될 위치의 개수 기억

  • SI : 소스 인덱스(source index) 저장

  • DI : 목적 인덱스(destination index) 저장

  • REP <명령어> : CX가 0이 아닌한 명령어를 반복 수행한다. CX는 1씩 감소된다.

  • MOVS : SI가 가리키는 번지로부터 8비트(MOVSB) 또는 16비트(MOVSW) 를 DI가 가리키는 곳으로 이동시킨다. 그 다음 SI 및 DI는 DF가 0이면 증가하고 DF가 1이면 감소한다.
    -MOVS는 SI에 주어진 번지를 DS에 대한 옵셋 번지로 취급 , DI는 ES에 대한 옵셋 번지를 기억, 흔히 ES와 DS는 같은 값으로 초기화한다.

  • DEBUG 의 F명령(Fill)
    ex) F 214 324 41 (214~324범위, 41 채울값) 메모리의 어떤 범위를 주어진 값으로 채운다.

  • STOS : AL(또는 AX의 내용을 DI가 가리키는 메모리 위치에 저장, DI를 DF의 설정치에 따라 증가 또는 감소시킨다.
    STOSB(8비트) , STOSW(16비트)

  • LODS : SI가 가리키는 위치로부터 AL 또는 AX로 이동시킨다.
    LODSB(8비트) , LODSW(16비트)

  • CMPS : SI가 가리키는 메모리 위치의 내용인 byte 또는 word에서 DI가 가리키는 메모리 위치의 내용인 byte 또는 word 를 빼어서, 그 결과에 따라 플래그를 설정한다. (메모리의 내용은 CMPS 명령어에 의해 영향을 받지 않는다.)
    CMPSB(8비트) , CMPSW(16비트)

  • REPZ <명령어> : CX가 0이 아니고, EF가 1인한 그 명령어를 반복 수행한다.

  • SCAS : DI가 가리키는 메모리 byte 나 word를 AL 또는 AX에서 빼어서 그에 따라 플래그를 설정한다. (해당 메모리의 내용이나 AL,AX 레지스터에서의 내용은 영향을 받지 않는다. DI가 1증가.
    SCASB(8비트) , SCASW(16비트)
    SCASB 명령어의 실행에 의해 DI가 증가되기 때문에 STOS 명령어를 실행하기 전에 DI를 감소시켜야 한다.

  • REPNZ <명령어> : CX가 0이 아니고, ZF가 0인한 반복 수행한다.
    CX는 REPNZ가 중단되기 전에 감소된다. 그렇기 때문에 CX를 증가시켜야 위치 하나를 빠뜨리지 않게 된다.

테이블

  • NUMERIC_MONTH DB ?,?
    MOV NUMERIC_MONTH + 1 , AL
    <==> MOV [n] , AL
    n은 NUMERIC_MONTH의 옵셋 번지에 1을 더하여 얻어진 것이다.

  • XLAT : 테이블의 시작 번지를 BX에 저장시키고, 테이블의 시작으로 부터의 상대적인 값을 AL에 넣어서, 테이블에 있는 특정 개체를 지정하면, AL의 내용을 BX에 더하여 얻어진 번지에 들어 있는 내용을 AL에 로드한다.
    (==)MOV AL , [BX + AL] (그러나 이것은 Illegal)

  • XCHG :
    ex)1. XCHG BX
    2. XCHG CX,[SI] (워드 교환)
    3. XCHG BL,CH (바이트 교환)
    1.에서 지정된 레지스터의 내용이 AX의 내용과 교환된다. 2.3.은 서로 교환된다.

번지 지정 모드

  • 레지스터 번지 지정 모드(register mode:레지스터) : 어떤 명령어에서 모든 오퍼랜드를 레지스터로부터 가져오거나 레지스터로 보낸다.
    ex) MOV AL,BL , INC BX , DEC AL , SUB DX,CX

  • 즉석 번지 지정 모드(immediate mode:데이타) :
    ex) MOV CL,61H

  • 직접 번지 지정 모드(direct mode:변위) : 오퍼랜드의 유효 번지(effective address)를 명령어로부터 직접 취한다.
    ex) MOV AX,TOTAL

  • 레지스터 간접 번지 지정 모드(register indirect mode:[BX],[BP],[SI],[DI]) : 유효 번지는 BX,BP,SI,DI에 들어 있다. 유효 번지는 자체에서 직접 구하는 것이 아니라 다음과 같이 레지스터를 액세스하여 간접적으로 구한다.
    ex) SUB DX,[BX]

  • 직접 인덱스 번지 지정 모드([SI}+변위,[DI}+변위) : 인덱스 레지스터 DI,SI와 부호 있는 8비트 또는 16비트 숫자의 합으로 이루어진 번지로부터 데이타 항목을 가져오거나 그 곳에 저장한다.
    ex) MOV AX,[SI+4] , ADD [DI-6],CX
    MUL WORD PTR [SI-192]
    MOV AX,[SI-27] <=> MOV -27[SI],AX <=> MOV [SI]-27,AX
    MOV AX,TOTAL[BX](TOTAL은 offset 204H) <=> MOV AX,[BX+204]
    i의 값이 SI에 있고, account[i]=total; <=> MOV AX,TOTAL , MOV account[SI],AX
    -배열의 원소를 연속적으로 액세스 하는데 사용한다.

  • 베이스 상대 번지 지정([BX]+변위,[BP]+변위) : 데이타 항목의 옵셋을 부호 있는 8비트 또는 부호 없는 16비트 수를 베이스 레지스터 BX,BP 의 내용에 더하여 구한다.
    ex) MOV AX,[BX-3] , SUB [BP+4],5
    BX에 있는 번지는 DS에 대한 옵셋, BP에 있는 번지는 SS에 대한 옵셋
    -레코드의 개별 원소를 액세스 할 수 있다.

  • 베이스 인덱스 번지 지정([BX][SI]+변위,[BX][DI]+변위,[BP][SI]+변위,[BP][DI]+변위) : 베이스 레지스터의 내용과 인덱스 레지스터의 내용 및 옵션으로 8비트 부호 있는 또는 16비트 부호 없는 숫자를 더하여 구한 번지로부터 데이터 항목을 가져오거나 그 번지에 저장한다.
    ex) MOV AX,[BX+DI] , MOV [BX+SI+2],AX
    MOV AX,[SI][BX+2] <=> [BX+SI+2] <=> 2[BX}[SI} <=> [BX][SI+2]

  • BP를 사용하는 번지 지정 모드 : 펑션이 호출될때 마다 데이타 항목을 위해 메모리를 할당하여야 한다. 이와 같이 할당된 메모리를 활성 레코드(activation record)라 한다. 보통 활성 레코드를 스택에 보존한다. BP를 사용하여 활성 레코드의 시작 번지를 기억한다.

  • C언어와 같은 고급 언어 구현에서의 메모리 번지 지정 모드 사용

 

평상시

포인터

활성 레코드

정수 및 문자형 변수

직접

BX

BP+변위

배열

SI+변위,DI+변위

BX+SI,BX+DI

BP+SI+변위,BP+DI+변위

개별 레코드

직접

BX+변위

BP+변위

레코드로된 배열

SI+변위,DI+변위

BX+SI+변위,BX+DI+변위

BP+SI+변위,BP+DI+변위

 

모듈식 프로그램

BCD 연산

  • BCD(Binary Coded Decimal)
    - 팩 BCD(packed BCD) : BCD 두 자리를 한 바이트로 묶는다.
    ex)0011,1000,0001,0010,0101
    3디지트,부호(-),1,2,5
    - 언팩 BCD(unpacked BCD) : 한 바이트에 BCD 디지트 하나를 저장
    ex)0000 01000, 0000 0001, 0000 0110, 0000 1001
    디지트수 4,부호(+),6,9

  •   19   0001 1001
    +24 +0010 0100
    --- -----------
    3?   0011 1101
    06   0000 0110(금지된 범위의 digit을 조정한다.)
    43   0100 0011
    -캐리가 발생하는 경우에도 6을 더해야 한다.
    -하위 BCD digit을 더하여 캐리가 발생하면 AF가 1로 된다.
    -CF는 상위 BCD digit을 더할때 캐리가 발생하였는지를 나타낸다.

  • DAA(Decimal Adjust for Addition) : 팩 BCD 표현을 조정해주는 명령어
    AAA(ASCII Adjust for Addition) : 언팩 BCD 표현을 조정해 주는 명령어
    -CF와 AF가 1로 되거나 두 digit의 합이 금지된 범위로 들어가는 경우, DAA는 AL에 있는 BCD 숫자의 해당 디지트에 6을 더한다. AAA로 비슷하게 동작한다.

  • DAS, AAS : 뺄셈을 위한 명령어

  • 다중 디지트 팩 BCD 숫자 두 개를 더하는 프로그램 조각에서는 두 수가 차지하는 바이트 수가 같다고 가정하며, 이 바이트 수는 CX에 저장한다. 첫 번째 BCD 수는 SI가 그 위치를 가리키며, 두 번째 BCD 수는 DI가 그 위치를 가리킨다. 두 BCD 수의 합은 DI가 가리키는 위치에 원래의 두 숫자 각각과 동일한 형태로 저장된다.

  • AAM
    ex)MUL BL
    AAM
    결과를 두갱의 언팩 BCD 디지트로 변환하여 상위 디지트를 AH에, 하위 디지트를 AL에 기억 시킨다. 이 숫자의 BCD 디지트 개수 CX
    - 다중 디지트 언팩 BCD 숫자가 SI가 가리키는 곳에 저장되어 있다고 가정, DL에는 다중 디지트 언팩 BCD 숫자에 곱할 승수인 하나의 언팩 BCD 디지트가 들어있다고 가정, 결과는 DI가 가리키는 번지에서 시작하여 저장된다.

  • AAD
    ex)AAD
    DIV DL
    AX에 있는 두 자리의 언팩 BCD 숫자를 취하여, DIV가 언팩 BCD 몫을 AL에, 그리고언팩 BCD 나머지를 AH에 두도록 하기 위한 형태로 변환한다. SI는 언팩 BCD 숫자를 가리키며, 이 숫자의 디지트 개수는 CX에 저장된다. 몫의 번지는 DI가 가리킨다. AH에는 나머지가 기억된다. DL에는 단일 언팩 BCD 디지트 제수가 기억된다.

  • 곱셈과 나눗셈의 경우는 언팩 BCD 숫자에 대해서만 연산을 할 수 있다.

어셈블리 언어 특징

  • SEG : OFFSET과 비슷하지만 세그먼트:옵셋 형식의 번지에서 세그먼트 부분을 되돌려 준다.
    ex) MOV BX,SEG RUN_ERROR

  • TYPE : 2 변수에 의해 참조된 개별 데이터 항목이 차지하는 바이트 수를 돌려준다.
    ex) NEW_CENTURY DW 2000D
    MOV AX,TYPE NEW_CENTURY
    <=> MOV AX,2
    - 레이블과 함께 사용시 레이블이 NEAR이면 -1을 리턴, FAR이면 -2를 리턴

  • LENGTH : 데이터 항목의 개수
    ex) SALES_ARRAY DB 80H DUP(0)
    MOV AX,LENGTH SALES_ARRAY
    <=>MOV AX,80H

  • SIZE : LENGTH와 TYPE의 곱을 리턴한다.
    MOV AX,SIZE SALES_ARRAY(80H*1)

  • TEST_VALUES DB 2,4,6,80AH,0CH,0EH 이 경우 TEST_VALUES는 정의된 바이트 중에서 맨 처음 바이트만 참조한다.
    LENGTH TEST_VALUES => 1
    TYPE TEST_VALUES => 1
    SIZE TEST_VALUES => 1

  • MASM은 16비트 산술 연산을 한다. 즉, 16비트를 초과하면 16비트로 절단(truncate)된다.

  • MASM 연산자

    • 산술 연산자

      • HIGH,LOW : 오퍼랜드의 상위 또는 하위 바이트를 산출한다.
        ex) MOV AL,LOW(0ABC1H)

      • *,/,MOD :
        ex) CMP DX,(132*15)/3 MOD 4

      • SHL,SHR :
        ex) CMP AH,14H SHR 6

      • +,- :
        ex) MOV AL,RECORD_START+2

    • 관계 연산자 : 1(참) 또는 0(거짓)을 되돌린다.

      • EQ : EQual

      • NE : Not Equal

      • LT : Less Than

      • LE : Less than or Equal

      • GT : Greater than

      • GE : Greater than or Equal
        MOV DL,5EH GE 6EH

    • 논리 연산자

      • NOT,AND,OR,XOR :
        ex) MOV BH,NOT 15H
        MOV CL,22H AND 0ABH

    • 값을 돌려주는 연산자
      LENGTH,SIZE,SEG,TYPE,OFFSET

    • 속성값을 설정하거나 무시하는 연산자 : 형 PTR 수식 , SHORT 레이블, THIS 형

      • THIS : 인접하는 바이트를 차지하는 두개의 데이터 항목을 하나의 워드로 취급 할 수 있게 해준다. 뒤에 BYTE,WORD,DWORD,FWORD,QWORD,TBYTE,NEAR,FAR,PROC 중 하나가 와야함
        ex) AB_WORD EQU THIS WORD
        FIRST_BYTE DB 41H
        SECOND_BYTE DB 42H
        인접한 위치 FIRST_BYTE와 SECOND_BYTE의 내용을 하나의 워드로 액세스하도록 해준다.

      • SHORT : 점프 명령어를 NEAR 점프로 인코딩 뒤게 해준다. JMP 명령어를 부호 없는 16비트 형식이 아닌 부호 있는 8비트 형식으로 인코딩하도록 한다.
        ex) JMP SHORT NEXT_BLOCK_LABEL

      • 세그먼트 오버라이 : 한 세그먼트에 정의된 데이터 항목을 다른 세그먼트에서 해당 옵셋으로 액세스하도록 해준다. 변수 또는 레이블과 연관된 세그먼트를 무시 할 수 있다.
        ex) MOV AL,ES:ABYTE
        AL을 ES에 의해 번지 지정된 세그먼트 내의 위치로부터 값을 가져와서 로드하도록 어셈블 된다.

      • PTR : ex) NEAR_LOOP : -----
        JMP NEAR_LOOP
        FAR_LOOP : EQU FAR PTR NEAR_LOOP
        JMP FAR_LOOP
        한 곳에서 레이블은 특정 형(NEAR)으로 정의해 놓고 다른 곳에서 반대의 형(FAR)을 갖는 레이블을 참조해야 할 필요가 있는 경우

    • 연산자 우선 순위
      1 : [],()
      2 : LENGTH,SIZE
      3 : 세그먼트 오버라이드 연산자(ex) ES:)
      4 : PTR,OFFSET,SEG,TYPE,THIS
      5 : HIGH,LOW
      6 : *,/,MOD,SHL,SHR
      7 : +,-(일원 및 이원 모두)
      8 : EQ,NE,LT,LE,GT,GE
      9 : NOT
      10: AND
      11:OR,XOR
      12:SHORT
      (1:우선 순위가 가장 높은,12:우선 순위가 가장 낮음)

  • 데이터 정의, 메모리, 및 프로그램 링크를 위한 MASM 의사 명령어
    -데이터 정의
    이름 LABEL 형 : 이름을 정의한다.
    DB,DW,DD,DQ,DT : 변수를 위한 메모리를 확보하고 초기화 한다.
    이름 EQU 수식 : 기호식 상수를 정의한다.
    이름 = 수식 : 재정의 될 수 있는 이름을 저의한다.
    -메모리
    이름 PROC NEAR ... 이름 ENDP : 프로시저 정의
    이름 PROC FAR ... 이름 ENDP : 프로시저 정의
    이름 SEGMENT 정렬형식 결합형식 클래스형식 : 세그먼트 정의
    -
    -
    이름 ENDS
    이름 GROUP 세그먼트 이름1,...,세그먼트 이름t : 지명된 세그먼트들을 주어진 그룹 이름으로 모든다.
    ASSUME 세그먼트레지스터:이름,세그먼트레지스터:이름,... : 에셈블러에게 어느 세그먼트 레지스터가 주어진 세그먼트를 번지 지어할 것인지를 알린다.
    ASSUME 세그먼트레지스터:NOTHING : 세그먼트 레지스터가 특정 세그먼트를 참조하지 않음
    ORG 수식 : 위치 계수기 값을 정의한다.
    EVEN : 위치 계수기를 짝수 번지로 설정한다.
    -프로그램 링크
    NAME 모듈이름 : 모듈 이름을 정의한다. PUBLIC 심볼1,심볼2,...,심볼t : 전역이름을 저의한다.
    EXTRN 이름1:형1,이름2:형2,... : 다른 모듈에 정의된 전역 이름을 참조할 수 있게 해준다.
    INCLUDE 파일이름 : 현재의 프로그램에 파일이름의 내용을 삽입. 반복할 내용이 있을때 사용

  • $(달러기호)를 사용하여 위치 계수기의 현재 값을 참조할 수 있다.
    ex) ORG $+2

  • PAGE : 페이지의 길이와 폭을 맞추는데 사용한다. 디폴트로서 페이지당 64라인 출력
    PAGE+ : 장 번호를 1증가 시킨다. 페이지 번호를 1로 리셋시킨다.
    PAGE <페이지 길이>,<페이지 폭> : : 페이지 길이(10~255), 페이지폭(80:default,60~132)

  • TITLE : 프로그램 제목 지정하는데 사용한다.
    TITLE <최대 60자 까지의 스트링>

  • SUBTTL : 각 페이지의 첫 머리에 잇는 제목 다음 줄에 프린트 하도록 한다.
    SUBTTL <최대 60자 까지의 스트링>

  • NAME 지시어를 사용하지 않고 프로그램 제목의 처음 여섯 자가 유용한 이름을 형성한다면, 이 여섯문자가 모듈(module) 이름으로 취급된다.

  • 어셈블러로부터 화일로 가는 출력은 .LIST, .XLIST 지시어로 제어할 수 있다. 디폴트는 .LIST 이다. .XLIST를 만나면 어셈블러는 .LIST 지시어를 만날 때까지 출력의 형식화를 중지한다.

  • %OUT : 긴 어셈블 과정에서 %OUT를 만날 때마다 프로그래머가 선택한 지점에서 스크린에 메세지가 디스플레이 되도록 한다.
    ex) %OUT <스트링>

STRUC

  • 구조체 이름 STRUC
    -----
    구조체 이름 ENDS
    초기화 : 구조체 변수 구조체 이름<초기값>
    사용 : ㄱ 구조체 변수.필드 이름 or [구조체 변수 번지].필드 이름
    - 항목이 하나뿐인 필드는 오버라이드 할 수 있으나, 여러 개의 항목으로 된 필드는 오버라이드 할 수 없다.
    ex) STUDENT GRADE_CARD<----->
    구조체 배열 : BX,OFFSET STUDENT
    [BX].필드 로 참조

  • MOV AX,OFFSET SUM[SI](=>name) 는 불법이다.
    MOV reg,OFFSET name = LEA reg,name

  • LEA(Load Effective Address) : 유효번지 계산에 인덱스 레지스터 또는 베이스 레지스터를 사용하려면 반드시 LEA를 사용해야 한다.

  • 구조체 내에 구조체 변수는 내포 시킬 수 없다.

RECORD

  • RECORD : 데이터를 비트 그룹으로 취급함. 한 패밀리에서 모든 그룹이 차지하는 전체 비트 수는 16비트를 초과할 수 없다.
    레코드 이름 RECORD 필드 이름:비트수,... : 비트수(1~16D)
    초기화 : 레코드 변수 레코드 이름 <초기값>

  • 레코드와 구조체, DATA SEGMENT 전에 선언, DATA SEGMENT에서 초기화, CODE SEGMENT에서 사용

  • 레코드에서 첫 번째 필드는 최상위 비트에 저장되고 오른쪽으로 가면서 하위 비트에 저장된다.
    -사용되지 않는 비트들은 값이 정해지지 않는다.
    ex) TIME RECORD HOURS:6,MINUTES:6
    START_TIME TIME <10,02>
    ????001010000010B(12비트)
    ex)MY_DATES DATE 24H DUP(<>) : 24H개의 레코드를 초기화 또는 할당

  • WIDTH : 레코드 내의 한 필드의 폭을 리턴한다.
    WIDTH 필드 이름

  • MASK : 어떤 필드가 차지하는 비트 위치들에 대한 비트 마스크를 되돌린다.
    MASK 필드 이름

  • 쉬프트 횟수 :
    MOV CL,필드 이름 (2이면 오른쪽으로 2비트 쉬프트시켜야 하기 때문이다.)

매크로

정의

FACT MACRO N

IF N-1

MOV BX,N-1

MUL BX

FACT N-1

ENDIF

ENDM

 

사용 예

NUM EQU 5

MOV AX,NUM

FACT %NUM

  • 정수 합

정의

SUM MACRO N

IF N-1

ADD AX,N-1

SUM N-1

ENDIF

ENDM

사용 예

NUM EQU 4

MOV AX,NUM

SUM %NUM

  • M의 N승

정의

POWER MACRO M,N

IF N-1

MOV BX,M

MUL BX

POWER M,N-1

ENDIF

ENDM

 

사용 예

NUM EQU 2

MOV AX,NUM

POWER %NUM,3

조건부 어셈블리

  • 형식 1

IFxxx expression

-----

ELSE

-----

ENDIF

  • 형식 2

IFxxx expression

-----

ENDIF

MASM의 조건부 의사  명령어

IFxxx

조건 아래가 실행되는 조건

IF expression

expression이 0이 아니면

IFE expression

expression이 0이면

IF1

어셈블리 패스 1에서 만나면

IF2

어셈블리 패스 2에서 만나면

IFDEF symbol

symbol이 정의되어 있거나 EXTRN으로 외부에 선언되어 있으면

IFNDEF symbol

symbol이 정의되어 있지 않거나 EXTRN으로 외부에 선언되어 있지 않으면

IFB <argument>

argument가 빈칸이면

IFNB <argument>

argument가 빈칸이 아니면

IFIDN <arg1>,<arg2>

스트링 arg1과 스트링 arg2가 같으면

IFDIF <arg1>,<arg2>

스트링 arg1과 스트링 arg2가 다르면

 

디스크 화일

  • ASCIIZ 스트링

확장 DOS 펑션 호출을 이용하여 화일을 열거나 생성하는 경우, 화일 이름을 ASCIIZ 스트링에 명시하여야 한다. ASCIIZ 스트링은 스트링의 끝에 값이 0인 바이트 하나를 붙인 것이다. ASCIIZ 스트링에는 화일 이름 뿐만 아니라 디스크 드라이브 이름과 디렉토리 경로도 지정할 수 있다.

(e.g.) FILE1 DB 'C:\COMPILERS\TURBO.EXE',0

  • 화일 핸들

화일 핸들은 화일을 지정하기 위한 16비트 수치 코드이다. 확장 DOS 펑션 호출을 이용하여 처음으로 화일을 열거나 생성할 때, 해당 핸들이 그 화일에 부여된다.

  • 확장 DOS 펑션 호출

디스크 화일 데이터의 전송은 메인 메모리에 있는 버퍼를 통하여 이루어져야 한다. 이 버퍼의 옵셋 번지를, 읽거나 기록할 바이트 수와 함께 해당 DOS 펑션에 전달한다. 데이터 전송 버퍼의 허용 최대 크기는 64K 바이트 이다.

  1. 화일의 이름을 지정하는 ASCIIZ 스트링을 준비한다.

  2. 메인 메모리에 512D(예로) 바이트의 버퍼를 설정한다.

  3. 레지스터 CX에 읽거나 기록할 바이트 수(512D)를 기억시킨다.

  4. 필요하다면, 화일의 어느 레코드가 전송 대상인지를 명시한다.

순차화일로부터 일거나 순차화일에 기록하려고 할 때, DOS는 디폴트로 화일의 맨 처음에서부터 CX에 지정된 바이트 수 만틈 일거나 화일의 맨 처음에 기록한다. 그 다음에 내부의 DOS 화일 포인터는 CX의 내용만큼 증가되어 차기 읽기 또는 기록 동작의 위치가 CX의 내용만큼 영향을 받는다. 읽기 또는 기록 동작 후, 확장 DOS 펑션은 AX에 실제로 읽은 또는 기록한 바이트 수를 넘긴다. 에러가 없었다면, 캐리 플래그(CF)가 0으로 된다. AX의 내용이 0이면, 화일의 끝에 다다랐음을 나타낸다. AX의 내용이 CX보다 작으면 화일의 끝에서 레코드의 일부분을 읽었음을 의미한다. 에러가 발생하면 CF는 1로 되고, AX에는 에러의 원인을 나타내는 코드가 기억된다.

INT 21H 확장 디스크 화일 핸들링 펑션의 요약

펑션번호

목적

필요한 입력 파라미터

출력 파라미터

3CH

화일 생성

DS:DX가 열리지 않은 화일을 나타내는 ASCIIZ 스트링을 가리키고 CX에는 화일의 속성이 들어 있는 경우, 해당하는 화일을 새로 생성한다. 만약 ASCIIZ 스트링에서 지정된 화일이 이미 존재하면 그 화일의 내용은 지워진다.

AH = 3CH

CX = 화일 속성

DX = ASCIIZ 스트링의 옵셋(DS에는 세그먼트 번지가 들어있다고 가정)

CF가 0이면, AX에는 할당된 화일 핸들이 저장되어 있다. 

CF가 1이면, AX에는 에러 상황을 나타내는 3,4 또는 5가 저장되어 있다. 3이면 주어진 경로를 찾지 못한 경우이고, 4이면 여유 핸들이 없다는 것이고, 5는 액세스가 거부된 경우로서 이것은 아마 디렉토리가 꽉 찼기 때문이다.

3DH

화일 열기

DS:DX가 가리키는 ASCIIZ 스트링에서 지정한 화일을 연다.

AH = 3DH

DX = ASCIIZ 스트링의 옵셋

AL = 읽기 위해 여는 경우는 0, 쓰기 위해 여는 경우는 1, 읽고 쓰기 위해 여는 경우는 3

CF가 0이면 AX에는 할당된 핸들이 들어있다. 

CF가 1이면 AX에는 에러 상황을 나타내는 2,4,5 또는 12가 저장되어 있다. 2이면 화일을 찾지 못한 경우이고, 4이면 여유 핸들이 없다는 것이고, 5는 액세스가 거부된 경우로서 이것은 아마 디렉토리가 꽉 찼기때문이다. 그리고 12이면 AL이 3 가지 허용된 값 중의 하나로 설정되지 않았다는것을 나타낸다.

3EH

화일 닫기

이 펑션은 모든 디렉토리 정보가 갱신되도록 하기 위해 데이터를 화일에 기록한 후 반드시 호출하여야 한다.

AH = 3EH

BX = 닫을 화일의 핸들

AX = 화일 핸들

CF가 0이면 에러가 없는 경우이다. 

CF가 1이고 AX가 6이면 핸들이 잘못 되었거나 이 핸들을 가진 화일이 열려 있지 않았다는 것을 나타낸다.

3FH

화일이나 장치로부터 읽기

이 펑션은, BX에 있는 핸들을 가진 화일이 펑션 3DH로 열려 있거나 생성 펑션 3CH에 의해 새로 생성되어 잇는 경우에만 동작한다. 이 경우 CX에 지정된 숫자만큼의 바이트가 DX에 주어진 옵셋 번지에서 시작하는 메모리로 읽혀진다. 데이터는 내부 화일 포인터의 현재 값이 가리키는 위치에서 시작하여 읽혀진다. 성공적으로 읽고 나면 화일 포인터는 읽은 마지막 바이트 다음 위치의 바이트를 가리키도록 갱신된다.

AH = 3FH

BX = 화일 핸들

CX = 읽을 바이트 수

DX = 읽은 데이터를 저장할 버퍼의 옵셋 번지

CF가 0이면 AX에는 읽은 바이트 수가 기억되어 있다. (CF가 0이고 AX가 CX보다 작으면 화일의 끝에서 부분 레코드를 읽었다는 뜻이다. CF와 AX가 모두 0이면 화일의 끝에 도달했다는 것이다.) 

CF가 1이면 AX는 에러 상황을 나타내는 5 또는 6을 기억하고 있다. 5는 액세스가 거부된 경우이고, 6은 그 화일이 없다는 것을 나타낸다.

40H

화일이나 장치에 기록

이 펑션은 BX에 있는 핸들을 가진 화일이 펑션 3DH로 열려 있거나 생성 펑션 3CH에 의해 새로 생성되어 있는 경우에만 동작한다. 이 경우 DX에 주어진 옵셋 번지에서 시작하는 메모리 위치로부터 CX에 지정된 숫자만큼의 바이트를 화일에 기록한다. 데이터는 내부 화일 포인터의 현재 값이 가리키는 위치에서 시작하여 화일로 기록된다. 성공적으로 기록하고 나면 화일 포인터는 기록한 마지막 바이트, 다음 위치의 바이트를 가리키도록 갱신된다.

AH = 40H

BX = 화일 핸들

CX = 기록할 바이트 수(CX가 0이면 화일이 잘려지거나 현재 화일 포인터로 확장된다).

DX = 읽은 데이터를 저장할 버퍼의 옵셋번지(DS에 대한 상대번지)

CF가 0이면 AX에는 기록한 바이트 수가 기억되어 있다. (CF가 0이고 AX가 CX보다 작으면 목적지 디스크가 꽉 찼다는 뜻이다.) 

CF가 1이면 AX는 에러 상황을 나타내는 5 또는 6을 기억하고 있다. 5는 액세스가 거부된 경우이고, 6은 그 화일이 없다는 것을 나타낸다.

41H

화일 지우기

화일 이름이 들어 있는 ASCIIZ 스트링을 DS:DX가 가리킬 경우 해당 화일을 지운다.

AH = 41H

DX = ASCIIZ 스트링의 옵셋 번지

CF가 0이면 삭제 성공

CF가 1이면 AX에는 에러 상황을 나타내는 2,3 또는 5가 기억되어 있다. 2는 주어진 화일을 찾지 못한 경우이고, 3은 주어진 경로를 찾지 못했다는 뜻이고, 5는 액세스가 거부된 경우이다.

42H

읽기/쓰기 포인터 이동

이 펑션은 차기 읽기 또는 기록 동작을 위해 화일 포인터의 위치를 설정한다. CX,DX에 있는 값은 32비트 숫자로 해석되는데, CX에 있는 값이 높은 자리수가 된다. 이 32비트 숫자는 다음 3가지 방법 중의 하나에 따라 옵셋을 지정한다. 사용하고자 하는 방법은 그 값을 AL에 넣는다. AL이 0이면, CX,DX의 값은 32비트 양의 정수로 해석되어 화일 포인터는 항상 화일의 시작에 대한 상대적인 값이 된다. AL이 1이나 2이면, CX,DX는 32비트 부호 있는 정수로 해석되어 화일 포인터를 앞뒤로 이동시킬 수 있게 된다. AL이 1이면 화일 포인터의 현재 위치에서 앞뒤로 이동한다. AL이 2이면 화일의 끝에서 앞뒤로 이동한다. 0인 경우, 옵셋이 0이면 화일 포인터는 화일의 처음을 가리키게 되고, 마찬가지로 2인 경우 옵셋이 0이면 화일 포인터는 화일의 끝을 가리키게 된다.

AH = 42H

AL = 방법 코드: 00H이면 화일의 처음에서부터의 옵셋, 01H이면 현재 위치에서부터의 옵셋, 02H이면 화일의 끝에서부터의 옵셋

BX = 화일 핸들

CX,DX = 화일 포인터를 이동시킬 바이트 수

CF가 0이면 DX,AX에는 화일의 처음에서부터의 바이트 옵셋으로서의 새로운 포인터 위치 

CF가 1이면 AX에는 에러 상황을 나타내는 1 또는 6이 기억된다. AX가 1이면 AL은 0,1,2가 될 수 없다. AX가 6이면 핸들이 잘못되었다는 것을 나타낸다.

 

AH = 09H

스트링 출력(Display String)

DX = 출력할 스트링의 메모리 번지

AH = 0AH

스트링 입력(Buffered STDIN Input)

DX = 입력할 스트링의 메모리 번지

AH = 02H

바이트 출력(Display Output)

DL = 출력할 바이트

AH = 4CH

프로그램 종료(terminate with return code)

AL = 00H

AH=01H

에코로 바이트 입력 받음(Keyboard Input with ECHO)

 

  • 화일로서의 장치

확장 DOS 펑션은 키볻, 디스플레이 및 프린터와 같은 하드웨어 장치를 화일로서 간주하도록 해 준다. 이 때 장치에 따른 표준 핸들은 다음과 같다.

장치

표준 핸들

입력(통상적으로 키보드)

0

출력(통상적으로 디스플레이)

1

에러 출력(통상적으로 디스플레이)

2

보조 장치

3

프린터

4

 

따라서, 확장 DOS 펑션 3FH와 40H는 각각 키보드로부터 입력을 받아들이고 출력을 디스플레이 또는 프린터로 내보낼 수 있다.

  • COM 화일

COM 화일은 디스크 공간을 덜 차지하여 등가의 EXE 화일보다 더 빨리 메모리로 읽어 올 수 있는 장점이 있다. 그러나 COM 화일은 크기가 64K 바이트로 제한되며 2개 이상의 세그먼트를 번지 지정할 수 없다. 세그먼트가 한 개로 제한된다는 것은 여러 가지 문제를 야기시킨다. 이중에서 가장 중요한 것은 다른 프로그래머가 작성한 모듈을 이용하기가 어렵다는 점일 것이다. 또한 데이터와 명령어를 잘 분리해야 하는 문제도 생긴다. 따라서 대부분의 경우 EXE 화일이 바람직하지만, 프로그램이 아주 작을 때는 COm 화일이 더 좋다.

다음은 COM 프로그램 작성시의 필수적인 사항들 이다.

  1. 코드 세그먼트 하나만 허용된다.(COM 프로그램은 스택을 자동적으로 생성한다. COM 프로그램에서 데이터는 코드 세그먼트 내에 정의해야 한다.)

  2. 모든 세그먼트 레지스터는 반드시 코드 세그먼트를 가리키도록 초기화해야 한다.

  3. COM 프로그램에서 처음 100H 바이트는 프로그램 세그먼트 프리픽스(program segment prefix,PSP)가 차지하므로 프로그램의 진입점 바로 앞에는 다음과 같은 의사 명령어가 있어야 한다.  ORG 100H  그래야 프로그램이 코드 세그먼트의 시작에서부터 100H 바이트만큼 지나서 로드되게 된다. 즉 PSP에 덮어 쓰지 않게 된다.

  4. 프로그램이 단일 세그먼트로 되기 위해서는 모든 프로시져가 NEAR이어야 한다.

  5. 데이터는 프로그램의 처음이나 끝에 모아서 정의해야 한다. (EXE 프로그램의 형식을 따라서 데이터를 코드 세그먼트의 처음에 정의하도록 한다. 이러한 경우에는 데이터를 건너 뛰기 위해 JMP 명령어로써 COM 프로그램을 시작해야 한다)

어셈블 및 링크시 ML 명령에서 /AT 옵션을 준다.

COM 스택 : COM 프로그램의 경우 DOS는 자동적으로 네 개의 세그먼트 레지스터를 모두 같은 값으로 설정하며 스택도 자동적으로 정의한다. 만약 64K 범위 내에 충분한 공간이 있으면 스택은 64K 세그먼트 내에 정의되고 SP는 0FFFEH로 초기화된다. 만약 64K 세그먼트에 스택을 위한 공간이 모자라면, DOS는 스택을 메모리의 끝 부분에 설정한다.

프로그램 I/O

  • 프로그램 I/O : I/O 포트를  통하여 하드웨어 장치를 구동한다.

  • 외부 장치는 거의 대부분 시스템 버스에 직접 연결 되어 있지 않고 인터페이스에 연결되어 있다. 대부분의 인터페이스는 인터페이스 칩안에 있는 특정 레지스터에 적당한 값을 설정하므로써 그 인터페이스의 동작 모드를 결정할 수 있다. 8086 패밀리에 있는 메인 레지스터와 혼동할 가능성이 있기 때문에 주변 인터페이스 칩 레지스터는 통상적으로 포트(port)라 부른다.

    보통 인터페이스에는 세 개 또는 그 이상의 포트가 있다.

    • 제어 포트(control port) : 이 포트의 설정 값은 그 인터페이스가 보낼지 또는 받을지를 결정한다.

    • 데이터 포트(data port) : 전송될 데이터 요소를 기억하거나 받은 데이터 요소를 기억한다.

    • 상태 포트(status port) : 이 포트는 '프린터에 종이가 없으므로 더 이상의 데이터를 보내지 말라'와 같은 정보나, 직렬 전송의 경우, '데이터 요소의 모든 비트를 아직 수신하지 않았다'는 정보를 얻는 데 사용할 수 있다.

    인터페이스는 통상적으로 마더보드에 꽂을 수 있도록 인쇄 회로 기판(printed circuit board,PCB)으로 되어 있다.

  • 8086 패밀리 기종의 마이크로컴퓨터에 연결되어 있는 포트에는 0에서 0FFFFH까지의 번호가 붙어 있다.

    포트로의 출력, 누산기는 포트가 8비트냐 아니면 16비트냐에 따라 각각 AL 또는 AX가 된다.

    1. OUT DX,누산기 

    2. OUT 포트 번호,누산기

    포트 번호가 0에서 0FFH까지 사이이면 형식 2.를 사용할 수 있다. 그 외의 경우에는 형식 1.을 사용해야 한다. 이 경우에는 사전에 포트 번호를 DX에 기억시켜 놓아야 한다.

    포트에서의 입력

    1. IN 누산기,DX

    2. IN 누산기,포트 번호

  • 병렬 프린터의 프로그래밍

    병렬 프린터 인터페이스에는 다음과 같이 8비트 I/O 포트가 세 개 있다.

    포트 기능

    포트 번호

    데이터

    3BCH

    출력 제어

    3BEH

    프린터 상태

    3BDH

    병렬 프린터 인터페이스의 데이터 포트에 문자 B에 대한 ASCII 코드를 출력

    MOV AL,21H

    MOV DX,3BCH

    OUT DX,AL

    프린터 상태 포트의 내용을 AL로 복사

    MOV DX,3BDH

    IN AL,DX

    프린터 상태 포트

    bit0

    ?

    bit1

    ?

    bit2

    ?

    bit3

    0 프린터 에러

    1 프린터 정상

    bit4

    0 프린터 온라인 아님

    1 프린터 온라인

    bit4

    0 프린터에 종이가 있음

    1 프린터에 종이가 없음

    bit6

    0 인식(ACK) 펄스

    1 정상 입력

    bit7

    0 프린터가 바빠서 프린터로 데이터 전송 불가

    1 프린터가 바쁘지 않음

프린터 출력 제어 포트

bit0

0 정상 설정

1 프린터로 데이터를 출력하려면 이 비트를 1로 설정한다.

bit1

0 수동 라인 피드

1 CR 다음에 자동 LF

bit2

0 프린터를 초기화하려면 이 비트에 펄스를 보낸다.

1 정상 설정

bit3

항상 1이다

bit4

0 프린터 인터럽트 불가

1 프린터 인터럽트 가능

bit5

?

bit6

?

bit7

?

프린터가 바쁜지를 테스트 하기 위해 다음과 같이 TEST 명령어를 사용한다. TEST AL,80H 이 명령어는 프린터가 바쁘면 ZF를 1로 세트시키는데, AL의 내용은 바뀌지 않는다. 만약 프린터가 바쁘면, 다음과 같이 준비가 될 때까지 기다려야 한다.

MOV DX,3DBH

TEST_IF_BUSY:

IN AL,DX

TEST AL,80H

JZ TEST_IF_BUSY

이와 같이 프린터가 준비 완료되었는지를 반복적으로 체크하는 것을 프린터를 폴링(polling)한다고 한다.(일반적으로 말하면, 폴링은 장치가 어떤 행동을 취할 준비가 되어 있는지의 여부 또는 어떤 동작을 완료했는지의 여부를 타나내는 하나 또는 그 이상의 비트를 프로그램으로 테스트하는 것을 말한다.)

데이터 포트에 있는 문자를 프린트한다.

MOV DX,3BEH

MOV AL,0DH

OUT DX,AL ;프린트 시작

MOV AL,0CH

OUT DX,AL ;프린트 정지

실행에 앞서 최소한 50us 동안 출력 제어 레지스터의 비트 2를 0으로 하고 다시 1로 하여 프린터를 초기화시켜야 한다. 이 대기 시간은 50D 갱의 NOP 명령어를 실행하면 된다.(NOP - No Operation - 는 이러한 타이밍을 목적으로 준비된 8086 패밀리 명령어이다. 이명령어는 메모리나 레지스터의 상태에 전혀 영향을 주지 않는다. 그러나 실행시키는 데는 얼마만큼의 시간이 걸리므로 NOP를 반복해서 실행하면 동작을 동기화할 수 있다.)

인터럽트 I/O

  • 정상적인 프로그램 실행 동안에는 인터럽트는 인터럽트 서비스 루틴이 저장되어 있는 곳으로 제어를 자동적으로 넘기도록 한다. 서비스 루틴이 실행되고 나면 인터럽트가 걸리기 전에 떠났던 곳에서부터 프로그램 실행은 재개된다. 인터럽트는, 프로그램의 명령어에 의해 인터럽트가 걸렸느냐(소프트웨어 인터럽트), 아니면 하드웨어 장치에 의해 걸렸느냐(하드웨어 인터럽트)에 따라 두 가지 종류로 나뉜다.

  • CALL은 호출하고자 하는 서브루틴이 저장된 메모리의 위치로 제어를 직접 넘기는 반면, 소프트웨어 인터럽트에 해당하는 8086 패밀리 명령어는 제어를 간접적으로 넘기기 때문이다. 따라서 소프트웨어 인터럽트를 수행하면 먼저 DOS는 인터럽트를 실행하는 루틴(인터럽트 서비스 루틴)의 번지가 저장되어 있는 메모리의 번지를 찾는다. 이 번지가 CS:IP에 로드되어(CS,IP 및 플래그 레지스터의 이전 내용은 스택에 저장된다), 인터럽트 서비스 루틴의 처음에서부터 실행이 시작된다. 인터럽트 서비스 루틴의 마지막 명령어는 IRET(Interrupt RETurn) 명령어이다. IRET가 실행되면 IRET는 인터럽트 서비스 루틴이 실행되기 전의 CS,IP 및 플래그 레지스터의 내용을 스택으로부터 꺼낸다. 그래서 메인 프로그램의 정상적인 실행이 중돤되었던 곳에서부터 다시 계속될 수 있게 된다.

    인터럽트와 그의 인터럽트 서비스 루틴을 연결시키기 위해, 각 인터럽트에는 인터럽트 타입이 부여되어 있다. 따라서 소프트웨어 인터럽트는 INT 명령어를 실행함으로써 일어나게 된다.

    인터럽트 타입은 0에서 0FFH 사이의 정수이다. 주어진 타입의 인터럽트에 대해 인터럽트 서비스 루틴의 4 바이트 번지 즉 인터럽트 벡터가, 인터럽트 타입에 4를 곱하여 계산한 번지에 저장되어 있다. 따라서 INT 21H의 인터럽트 벡터는 위치 (21*4)H 즉 84H에서 찾을 수 있다. 따라서 메모리에서 처음 400H 개의 절대 위치는 인터럽트 벡터가 차지하는데, 이들 대부분은 DOS를 위해 예약되어 있다. 프로그래머는 자신의 목적을 위해 절대 번지 100H-1FFH에 인터럽트 벡터를 둘 수도 있다(이렇게 하면 인터럽트 타입은 40H-7FH가 된다).

    INT 21H

    84H

    85H

    86H

    87H

    옵셋

    세그먼트

    인터럽트 서비스 루틴

    소프트웨어 인터럽트 매커니즘

DOS 인터럽트 타입과 그의 기능 요약

타입

벡터 번지

인터럽트 클래스

인터럽트 목적

0

0-3

8086 패밀리 인터럽트

0으로 나누기

1

4-7

단일 스텝

2

8-B

차단 불능 인터럽트(nmi)

3

C-F

브레이크 포인트

4

10-13

오버플로우

5

14-17

프린트 스크린

6,7

18-1B

예약되어 있음

8

20-23

8259 하드웨어 인터럽트

타이머

9

24-27

키보드

A,B,C,D

28-37

예약되어 있음

E

38-3B

디스크

F

3C-3F

예약되어 있음

10

40-43

BIOS에 대한 소프트웨어 인터럽트

디스플레이 I/O

11

44-47

장비 체크

12

48-4B

메모리 사이즈 체크

13

4C-4F

디스크 I/O

14

50-53

통신 I/O

15

54-57

카세트 I/O

16

58-5B

키보드 입력

17

5C-5F

프린터 I/O

18

60-63

소프트웨어 인터럽트

ROM BASIC

19

64-67

디스크로부터 부트스트랩

1A

68-6B

시간

1B

6C-6F

키보드 브레이크

1C

70-73

타이머 스트로브

1D

74-77

테이블 포인터

비디오 테이블 포인터

1E

78-7B

디스크 테이블 포인터

1F

7C-7F

그래픽 문자 테이블 포인터

20

80-83

DOS에 대한 인터럽트

프로그램 종료

21

84-87

펑션 호출

22

88-8B

프로그램 종료 번지

23

8C-8F

CTRL-BREAK 탈출 번지

24

90-93

치명적인 에러

25

94-97

절대 디스크 읽기

26

98-9B

절대 디스크 쓰기

27

9C-9F

프로그램 종료, 상주한다

28,3F

A0-FF

예약되어 있다: DOS가 사용

40-7F

100-1FF

사용자 인터럽트

 

80-F0

200-3C3

BASIC 인터럽트

 

  • 하드웨어 인터럽트의 경우 8086 패밀리 마이크로프로세서가 펄스를 보낸 하드웨어 타입을 알아야 한다. 따라서 키를 누르거나 놓으면 INT 9 명령어를 실행하는 것과 등가인 하드웨어 인터럽트가 발생한다는 것이다. 이러한 인터럽트를 받으면, 8086 패밀리 마이크로프로세서는 현재 수행중인 프로그램으로부터 벗어나 키보드를 서비스하고 나서 원래의 상태로 돌아온다. 물론 인터럽트를 받은 순간에 실행중인 현재 명령어는 실행을 끝내고 인터럽트를 처리한다. 인터럽트 서비스 루틴은 단지 8086 패밀리 기계 코드 프로그램에 지나지 않기 때문에 그 자체도 인터럽트될 수 있다. 실제로 여러 장치가 동시에 인터럽트를 요구할 때도 있다. 따라서, 인터럽트를 처리하는 우선 순위를 정해야 한다. 디폴트로, 하드웨어 인터럽트와 INT는 둘 다 인터럽트 서비스 루틴 내의 무시하면 안되는 인터럽트를 제외하고 모든 인터럽트를 불가능하도록 한다. 그래서 인터럽트 서비스 루틴이 아무런 간섭을 받지 않고 실행된다. 그러나 몇 가지 인터럽트는 정지시킬 수 없으면 이들을 차단 불능 인터럽트(non-maskable interrupt,NMI)라 부른다. NMI는 인터럽트가 불가능하도록 되어 있어도 우선 순위를 무시하고 특별한 라인을 통하여 신호를 8086 패밀리 마이크로프로세서에게 보낸다.

  • 트랩 플래그는 주로 프로그램을 디버깅할 때 사용하기 위하여 마련되어 있다. 트랩 플래그가 1인 경우, 8086 패밀리 마이크로프로세서는 명령어 하나를 실행시키고 나면 타입 1 인터럽트가 발생되도록 한다. 인터럽트 벡터가 특정 레지스터와 메모리 위치의 내용을 프린트해내는 인터럽트 서비스 루틴을 가리키도록하면, 이것은 DEBUG와 CodeView의 단일 스텝 방식의 T 명령과 유사한 기능을 활성화시킨다.

    트랩 플래그를 직접적으로 1로 세트시키고 0으로 클리어시키는 명령어가 마련되어 있지 않다. 그러나 다음에서와 같이 플래그 레지스터를 수정하면 트랩 플래그를 1로 세트시킬 수 있다.

    PUSHF

    POP AX

    OR AX,0100H

    PUSH AX

    POPF

    인터럽트 가능 플래그는 인터럽트 서비스 루틴 그 자체가 인터럽트될 수 있는지를 제어하는 데 사용한다(그러나 어떠한 경우에도 NMI는 차단할 수 없다) . 인터럽트를 허용하려면 이 플래그를 1로 하여야 하고 허용하지 않으려면 0으로 하여야 한다. 8086 패밀리 어셈블리어 프로그램에서는 명령어 STI(SeT Interrupt enable flag)와 CLI(CLear Interrupt enable flag)가 각각 이러한 일을 수행한다.

8086 패밀리의 플래그 설정 명령어 요약

명령어

목적

영향

CLC

CLear Carry flag

(CF<-0)

STC

SeT Carry flag

(CF<-1)

CLI

CLear Interrupt flag - 인터럽트 불가

(IF<-0)

STI

SeT Interrupt flag - 인터럽트 가능

(IF<-1)

CLD

CLear Direction flag - LODS,STOS 등이 앞으로 수행

(DF<-0)

STD

SeT Direction flag - LODS,STOS 등이 뒤로 수행

(DF<-1)

CMC

CoMplement Carry flag

(만약 CF==0이면 CF<-1, 아니면 CF<-0)

 

  • 인터럽트 매커니즘

    1. SP를 2 감소시킨다.

    2. 플래그 레지스터를 스택에 푸시한다.

    3. 트랩 플래그와 인터럽트 가능 플래그를 클리어시켜 더 이상의 인터럽트를 불가능하게 한다.

    4. SP를 2 감소시킨다.

    5. 현재의 CS를 스택에 푸시한다.

    6. 인터럽트 벡터로부터 세그먼트 번지를 CS에 로드한다.

    7. SP를 2 감소시킨다.

    8. 현재 IP를 스택에 푸시한다.

    9. 인터럽트 벡터로부터 옵셋 번지를 IP에 로드한다.

    IRET는 스택에서 처음 두 바이트를 IP로, 그 다음 두 바이트를 CS로, 그리고 그 다음 두 바이트를 플래그 레지스터로 끄집어 낸다.

8086 패밀리의 동기화 및 인터럽트 명령어 요약

명령어

설명

HLT

HaLT -  프로세서는 정지되며, 차단 불능 하드웨어 인터럽트를 받거나, 또는 IF가 1인 경우 차단 가능 하드웨어 인터럽트를 받으면 정지 상태에서 벗어난다.

WAIT

이 명령어는 프로세서로 하여금 TEST 핀에 신호가 들어올 때까지 대기 상태로 들어가게 한다. 프로세서는 인터럽트가 발생하면 이 상태에서 벗어날 수도 있다. 인터럽트 서비스 루틴으로 리턴되면 대기 상태는 재개된다.

ESC <외부 op 코드>,<원천>

이 명령어는 메모리 오퍼랜드를 시스템 버스에 두기 위해 사용한다. 외부 op 코드는 통산 80x87 부동 소수점 처리기와 같은 다른 프로세서를 위한 명령어이다.

LOCK

이 명령어는 다른 명령어에 접두어로서 붙는다. 그러면 이 접두어가 붙은 명령어가 실행되는 동안, 마이크로프로세서의 LOCK 핀으로부터 신호가 나온다.

INT <인터럽트 타입>

이 명령어는 제어를 인터럽트 서비스 벡터에 잇는 위치로 넘기는데, 이 벡터는 절대 번지 4*(인터럽트 타입)에 저장되어 있다.

IRET

이 명령어는 인터럽트가 일어난 곳으로 제어를 되돌린다.

INTO

INTerrupt if Overflow - 이 인터럽트는 OF=1일 때만 실행된다. 이 것은 다른 인터럽트와 똑같이 실행되지만 DOS가 IRET 명령어를 가리키도록 한다는 점이 다르다.

  • BIOS

    마이크로프로세서의 BIOS는 ROM에 저장되어있는, 그리고 컴퓨터를 켤 때 전체 시스템을 초기화하는 한 조의 8086 패밀리 기계 코드프로그램이다. 또한 이들 프로그램은 컴퓨터에 연결되는 각종 장치들을 제어하는 데 필요한 최소한의 소프트웨어를 제공한다.

    전원을 켜면 8086 패밀리 마이크로프로세서는 그의 리셋트 상태인 8086 모드로 들어가며, 이 때 CS는 0FFFF로, IP는 0으로 설정된다. 따라서 8086 패밀리 마이크로프로세서가 실행할 첫 번째 명령어는 절대 번지 0FFFF0H에 있는데, 이 번지는 ROM에 할당된 것이다. 이 명령어을 통하여 BIOS는 제어를 얻고, 어떤 장치가 부착되어 있는지를 결정하기 위하여 각종 I/O 포트를 조사하며, 부착된 장치들을 초기화하고, 스피커로 삐이 소리를 낸 다음 인터럽트 서비스 루틴 어드레스 테이블을 준비한다. 이 테이블에는 BIOS 내의 번지가 들어있으므로 INT 명령어를 통하여 이들을 액세스할 수 있다.

    만약 BIOS가 시스템에 디스크 드라이브가 부착되어 있다는 사실을 발견하면, BIOS는 DOS를 부트스트랩한다. DOS는 'Enter Date' 명령을 실행하기 앞서 인터럽트 벡터 테이블에 추가로 항목들을 채운다

    키보드 및 디스플레이를 위한 몇 가지 BIOS 루틴과 그들의 인터럽트 타입

    인터럽트

    레지스터 설정및 효과(DMA 번지)

    INT 10H

     

    디스플레이 출력

     

    AH=0

    디스플레이를 AL에 의해 지정된 모드로 설정한다.

    AL=00H 40*25

    16 그레이 텍스트 EGA: 64 칼라(B000:8000H)

    AL=01H 40*25

    16/8 칼라 텍스트 EGA: 64 칼라(B000:8000H)

    AL=02H 80*25

    16 그레이 텍스트 EGA: 64 칼라(B000:8000H)

    AL=03H 80*25

    16/8 칼라 텍스트 EGA: 64 칼라(B000:8000H)

    AL=04H 320*200

    4 칼라 그래픽(B000:8000H)

    AL=05H 320*200

    4 그레이 그래픽(B000:8000H)

    AL=06H 640*200

    2 그레이 그래픽(B000:8000H)

    AL=07H 80*25

    흑백 텍스트(B000:0000H)

    AL=08H 160*200

    16 칼라 그래픽(B000:0000H)

    AL=09H 320*200

    16 칼라 그래픽(B000:0000H)

    AL=0AH 80*25

    4 칼라 그래픽(B000:0000H)

    AL=0DH 320*200

    16 칼라 그래픽(A000:0000H)

    AL=0EH 640*200

    16 칼라 그래픽(A000:0000H)

    AL=0FH 640*350

    흑백 그래픽(A000:0000H)

    AL=10H 640*350

    16/64 칼라 그래픽(A000:0000H)

    AH=2

    커서를 스크린의 지정된 위치에 설정한다. 행 0,열 0은 왼쪽 위 모서리이다. BH=디스플레이 페이지, DH=행 번호,DL=열 번호

    AH=0EH

    지정된 문자를 현재 커서 위치의 스크린에 디스플에이하고 커서를 전진시킨다. BX=0, AL=문자

    INT 16H

     

    키보드 입력

     

    AH=0

    키보드로부터 AL로 문자를 읽어들인다. ASCII 문자를 읽었으면 AH=그 문자에 대한 표준 키보드 스캔 코드, 그렇지 않고 확장 ASCII 문자를 읽었으면 AH=0

    AH=1

    키가 눌러졌으면 ZF=0으로 되고, 그렇지 않으면 ZF=1로 된다.

    AH=2

    AL 레지스터의 해당 비트에 쉬프트 키 상태를 되돌린다.

    비트7 = INSERT 키

    비트6 = CAPS LOCK

    비트5 = NUM LOCK

    비트4 = SCROLL LOCK

    비트3 = ALT SHIFT

    비트2 = CTRL SHIFT

    비트1 = 왼쪽 SHIFT

    비트0 = 오른쪽 SHIFT

DOS 인터럽트

인터럽트

기능

20H

프로그램 종료

21H

펑션 호출

22H

종료하고 제어를 종료 번지로 넘긴다

23H

CTRL-BREAK를 누를 때 활성화된다

24H

심각한 에러

25H

절대 디스크 읽기 - 섹터에 의해 선택

26H

절대 디스크 쓰지 - 섹터에 의해 선택

27H

현재 프로그램을 종료하나 메모리에 남겨둔다

28H-35H

DOS 사용을 위해 예약되어 있다

메모리 모델

To assemble and execute assembly programs with MASM,
use either of the following code skeletons.

The first one is what we have learned in class.
The second one is rather new (well, not so new) and 
more compact.

Choice 1:
----------------------------------------
WORKING_STORAGE SEGMENT STACK
DW 100H DUP(?)
WORKING_STORAGE ENDS

DATA SEGMENT
; your data goes here
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:WORKING_STORAGE
MAIN PROC
MOV AX,DATA
MOV DS, AX
; your code goes here
MOV AX, 4C00H
INT 21H
MAIN ENDP
CODE ENDS
END MAIN

Choice 2:
-----------------------------------------
.MODEL SMALL

.STACK 200H ; size in bytes - if omitted, default is 1K

.DATA
; your data goes here

.CODE
MAIN PROC
MOV AX,@DATA ; notice @
MOV DS,AX
; your code goes here
MOV AX, 4C00H
INT 21H
MAIN ENDP
END MAIN
-----------------------------------------

<Comments on Memory Models>

The size of code and data a program can have is determined by 
specifying a memory model using the .MODEL directive. 
The syntax is 

.MODEL memory_model

Unless there is a lot of code or data, the appropriate 
model is SMALL. The .MODEL directive should come before any
segment definition.

SMALL code in one segment
data in one segment

MEDIUM code in more than one segment
data in one segment

COMPACT code in one segment
data in more than one segment

LARGE code in more than one segment
data in more than one segment
no array larger than 64KB

HUGE code in more than one segment
data in more than one segment
arrays may be larger than 64KB

코드 예제

 

AX와 BX의 합이 CX의 현재 내용과 같으면 DX에 문자 Y의 ASCII 코드를 넣고 만약 그렇지 않으면 DX에 N의 ASCII 코드를 넣는 어셈블리어 프로그램을 작성하는데, 프로그램 끝에서 AX,BX,CX에 0을 넣도록 한다.

 

DATA SEGMENT
   YES DB 'Y'
   NO DB 'N'
DATA ENDS

WORKING_STORAGE SEGMENT STACK
   DW 100H DUP()
WORKING_STORAGE ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:WORKING_STORAGE
PROG_START: 

   MOV AX,DATA
   MOV DS,AX
   MOV AX,3
   MOV BX,2
   MOV CX,5
   ADD AX,BX
   SUB AX,CX
   JZ NEXT
   MOV DL,NO
   JMP LAST
NEXT: 

   MOV DL,YES
LAST: 

   MOV AX,0
   MOV BX,0
   MOV CX,0
CODE ENDS
END PROG_START


by sneakerz

레지스터 AX의 내용을 조사하여 AX가 47H이면 DX에 0을 넣고 그렇지 않으면 DX에 0FFH를 넣는 어셈블리어 프로그램 조각을 작성하라. 이 이 프로그램은 반드시 AX의 내용이 보존되어야 한다. 즉 이 프로그램이 실행되고 난 후 AX의 내용이 처음의 것과 같아야 한다.

 

DATA SEGMENT
DATA ENDS

WORKING_STORAGE SEGMENT STACK
   DW 100H DUP()
WORKING_STORAGE ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:WORKING_STORAGE
PROG_START: 

   MOV AX,DATA
   MOV DS,AX
   MOV AX,47H
   MOV BX,AX
   SUB AX,47H
   JZ DONE
   MOV DX,0FFH
   JMP LAST
DONE: 

   MOV DX,0
LAST: 

   MOV AX,BX
CODE ENDS
END PROG_START


by sneakerz

사용자가 문자 A,B,...,Z 중에서 아무 문자나 타이핑하면 그 문자와, ASCII 코드에서 그 다음의 문자를 디스플레이하고 줄을 바꾼다. 그런 다음에 이과정을 반복하도록 한다.

 

DATA SEGMENT
DATA ENDS

WORKING_STORAGE SEGMENT STACK
   DW 100H DUP(?)
WORKING_STORAGE ENDS

CODE SEGMENT
ASSUME DS:DATA,SS:WORKING_STORAGE,CS:CODE
PROG_START:

   MOV AX,DATA
   MOV DS,AX
   MOV CX,5
NEXT: 

   MOV AH,1
   INT 21H
   INC AL
   MOV AH,2
   MOV DL,AL
   INT 21H
   MOV DL,0DH
   INT 21H
   MOV DL,0AH
   INT 21H
   DEC CX
   JNZ NEXT
   MOV AX,4C00H
   INT 21H
CODE ENDS
END PROG_START


by sneakerz

사용자가 1,2,3 중에서 하나를 타이핑하면 다음과 같은 해당 메시지를 디스플레이하고 줄을 바꾼다. 

1 - HELLO 

2 - GOODBYE

3 - HAVE A NICE DAY

 

 

DATA SEGMENT
   VAR1 DB 'HELLO$'
   VAR2 DB 'GOODBYE$'
   VAR3 DB 'HAVE A NICE DAY$'
DATA ENDS

WORKING_STORAGE SEGMENT STACK
   DW 100H DUP(?)
WORKING_STORAGE ENDS

CODE SEGMENT
ASSUME DS:DATA,SS:WORKING_STORAGE,CS:CODE
PROG_START:

   MOV AX,DATA
   MOV DS,AX
   MOV CX,3
LOOP0: 

   MOV AH,1
   INT 21H
   SUB AL,30H
   DEC AL
   JZ LOOP1
   DEC AL
   JZ LOOP2
   MOV DX,OFFSET VAR3
   JMP NEXT
LOOP1: 

   MOV DX,OFFSET VAR1
   JMP NEXT
LOOP2: 

   MOV DX,OFFSET VAR2
NEXT: 

   MOV AH,9
   INT 21H
   MOV AH,2
   MOV DL,0DH
   INT 21H
   MOV DL,0AH
   INT 21H
   DEC CX
   JNZ LOOP0
   MOV AX,4C00H
   INT 21H
CODE ENDS
END PROG_START


by sneakerz

사용자로 하여금 20 개의 문자로 된 메시지(비칸 포함)를 입력하고 그 메시지를 한 그룹의 메모리 위치에 저장하도록 하는(메모리 위치의 첫 번째 위치는 USER_MESSAGE로 참조한다) 어셈블리어 명령어와 해당 DB 의사 명령어를 작성하라.

 

 

DATA SEGMENT
   USER_MESSAGE DB 20 DUP(?)
DATA ENDS

WORKING_STORAGE SEGMENT STACK
   DW 100H DUP(?)
WORKING_STORAGE ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:WORKING_STORAGE
PROG_START: 

   MOV AX,DATA
   MOV DS,AX
   MOV BX,OFFSET USER_MESSAGE
   MOV CX,19
   MOV AH,1
NEXT: 

   INT 21H
   MOV [BX],AL
   INC BX
   DEC CX
   JNZ NEXT
   MOV [BX],60H
   MOV AX,4C00H
   INT 21H
CODE ENDS
END PROG_START


by sneakerz

사용자로부터 범위가 0에서 9 사이인 디지트를 하나 받아들여, 디스플레이 스크린에 뉴라인을 출력한 다음, 새로운 줄에 입력한 디지트의 2배 값을 출력하고, 운영체제로 되돌아가는 어셈블리 언어 프로그램을 작성하라.

 

DATA SEGMENT
DATA ENDS

WORKING_STORAGE SEGMENT STACK
   DW 100H DUP()
WORKING_STORAGE ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:WORKING_STORAGE
PROG_START: 

   MOV AX,DATA
   MOV DS,AX
   MOV CL,2
   MOV CH,10
   MOV AH,1
   INT 21H
   SUB AL,30H
   CBW
   MUL CL
   MOV CL,AL
   MOV DL,0DH
   MOV AH,2
   INT 21H
   MOV DL,0AH
   INT 21H
   MOV AL,CL
   CBW
   DIV CH
   MOV CH,AL
   ADD CH,30H
   MOV CL,AH
   ADD CL,30H
   MOV AH,2
   MOV DL,CH
   INT 21H
   MOV DL,CL
   INT 21H
   MOV AX,4C00H
   INT 21H
CODE ENDS
END PROG_START


by sneakerz

사용자가 0에서 9사이의 디지트 두 개를 입력하면, 새로운 줄에 그들의 곱을 출력하고 운영체제로 되돌아가는 프로그램을 작성하라.

First digit: 3

Second digit: 7

Product is: 21

 

 

DATA SEGMENT
   DIGIT1 DB 'FIRST DIGIT: ','$'
   DIGIT2 DB 'SECEOND DIGIT: ','$'
   RESULT DB 'PRODUCT IS: ','$'
   ENTER DB 0DH,0AH,'$'
   TEN DB 10
DATA ENDS

WORKING_STORAGE SEGMENT STACK
   DW 100H DUP()
WORKING_STORAGE ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:WORKING_STORAGE
PROG_START: 

   MOV AX,DATA
   MOV DS,AX
   MOV AH,9
   MOV DX,OFFSET DIGIT1
   INT 21H
   MOV AH,1
   INT 21H
   SUB AL,30H
   MOV CL,AL
   MOV AH,9
   MOV DX,OFFSET ENTER
   INT 21H
   MOV DX,OFFSET DIGIT2
   INT 21H
   MOV AH,1
   INT 21H
   SUB AL,30H
   CBW
   MUL CL
   DIV TEN
   MOV CH,AL
   ADD CH,30H
   MOV CL,AH
   ADD CL,30H
   MOV AH,9
   MOV DX,OFFSET ENTER
   INT 21H
   MOV DX,OFFSET RESULT
   INT 21H
   MOV AH,2
   MOV DL,CH
   INT 21H
   MOV DL,CL
   INT 21H
   MOV AX,4C00H
   INT 21H
CODE ENDS
END PROG_START


by sneakerz

키보드로부터 0에서 9사이의 디지트를 최대 10D 개 이내로 입력하여 이들의 평균을 구하는 프로그램을 작성하라.

Type number of digits: 3

Please enter digit 1:4

Please enter digit 1:5

Please enter digit 1:7

Average is :5

 

 

DATA SEGMENT
   QUESTION DB 'TYPE NUMBER OF DIGITS: ','$'
   NUMBER DB 'PLEASE ENTER DIGIT ','$'
   AVERAGE DB 'AVERAGE IS:','$'
   MAXNUM DB ?
   AVG DB ?
   TOTAL DB 0
   ENTER DB 0DH,0AH,'$'
DATA ENDS

WORKING_STORAGE SEGMENT STACK
   DW 100H DUP()
WORKING_STORAGE ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:WORKING_STORAGE
PROG_START: 

   MOV AX,DATA
   MOV DS,AX
   MOV AH,9
   MOV DX,OFFSET QUESTION
   INT 21H
   MOV AH,1
   INT 21H
   SUB AL,30H
   MOV MAXNUM,AL
   MOV AH,9
   MOV DX,OFFSET ENTER
   INT 21H

   MOV BL,MAXNUM
   MOV CL,0
NEXT: 

   INC CL
   MOV AH,9
   MOV DX,OFFSET NUMBER
   INT 21H
   MOV AH,2
   ADD CL,30H
   MOV DL,CL
   INT 21H
   SUB CL,30H
   MOV DL,':'
   INT 21H
   MOV AH,1
   INT 21H
   SUB AL,30H
   ADD TOTAL,AL
   MOV AH,9
   MOV DX,OFFSET ENTER
   INT 21H
   DEC MAXNUM
   JNZ NEXT
   MOV MAXNUM,BL
   MOV AH,9
   MOV DX,OFFSET AVERAGE
   INT 21H
   MOV AL,TOTAL 
   CBW
   DIV MAXNUM
   ADD AL,30H
   MOV DL,AL
   MOV AH,2
   INT 21H
   MOV AX,4C00H
   INT 21H
CODE ENDS
END PROG_START


by sneakerz

화일 덤프 유틸리티(순차 액세스 프로그램)

 

 

CR EQU 0DH

LF EQU 0AH

DATA SEGMENT

PROMPT DB 'PLEASE TYPE THE NAME OF THE FILE TO BE DUMPED '

               DB 'AND THEN PRESS THE ENTER KEY',CR,LF,'$'

USER_STRING LABEL BYTE

MAX_LENGTH DB 30H

NAME_LENGTH DB ?

FILENAME DB 31H DUP(' ')

 

HANDEL DW ?

BUFFER DB 512D DUP(?)

CHARS_READ DW ?

DATA ENDS

WORKING_STORAGE SEGMENT STACK

DW 100H DUP(?)

WORKING_STORAGE ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:WORKING_STORAGE

;establish data segment addressability
PROG_START: 

MOV AX,DATA

MOV DS,AX

;prompt user for filename

MOV AH,9H

LEA DX,PROMPT

INT 21H

;read filename

MOV AH,0AH

LEA DX,USER_STRING

INT 21H

;print a new line

CALL PRINT_NEWLINE

;prepare ASCIIZ string representing user's filename

MOV BL,NAME_LENGTH

MOV BH,0

ADD BX,OFFSET FILENAME

MOV [BX],BYTE PTR 0

;DOS open file function

MOV AH,3DH

;open for reading only

MOV AL,0

;DX := address of ASCIIZ string

LEA DX,FILENAME

INT 21H

;if carry flag clear then

JC DONE

;begin

;store handle

MOV HANDLE,AX

;repeat

NEXT_RECORD:

MOV AH,3FH ;DOS read file function

;DX := address of data buffer

LEA DX,BUFFER

;CX := number of bytes to read

MOV CX,512b

;BX := file handle

MOV BX,HANDLE

;read next group of bytes into buffer

INT 21H

;chars_read := AX

MOV CHARS_READ,AX

;if carry flag is clear

JC UNTILCHECK

;and AX<>0

CMP AX,0

JC UNTILCHECK

;then begin

;print out record just read in hex

CALL HEX_RECORD_PRINT

;read(char) ;print (new line)

MOV AH,1

INT 21H

CALL PRINT_NEWLINE

;clear carry to indicate a char was read

CLC

;end

;until carry set or char = 'X' or AX=0

UNTILCHECK:

JC DONE

CMP AL,'X'

JZ DONE

CMP AX,0

JZ DONE

JMP NEXT_RECORD

;end

;return to DOS

;end

;return to DOS

DONE:

MOV AX,4C00H

INT 21H

HEX_RECORD_PRINT PROC NEAR

LEA SI,BUFFER

MOV CX,CHARS_READ

PRINTING:

LODSB

PUSH CX ;preserve CX so we do not lose count

CALL PRINT_AL_IN_HEX

POP CX

LOOP PRINTING

CALL PRINT_NEWLINE

RET

HEX_RECORD_PRINT ENDP

 

PRINT_AL_IN_HEX PROC NEAR

PUCH AX

MOV CL,4

ROR AL,CL

CALL PRINT_ONE_HEX_DIGIT

POP AX

PRINT_ONE_HEX_DIGIT:

AND AL,0FH

ADD AL,30H

CMP AL,3AH

JB DISPLAY_IT

ADD AL,7H

DISPLAY_IT:

MOV DL,AL

MOV AH,2H

INT 21H

RET

PRINT_AL_IN_HEX ENDP

 

PRINT_NEWLINE PROC NEAR

USH AX

MOV AH,2H

MOV SL,CR

INT 21H

MOV DL,LF

INT 21H

POP AX

RET

PRINT_NEWLINE ENDP

  

CODE ENDS
END PROG_START


by sneakerz

화일에 데이터 쓰기

 

 

CR EQU 0DH

LF EQU 0AH

DATA SEGMENT

PROMPT DB 'PLEASE TYPE THE NAME OF THE FILE TO BE CREATED '

               DB 'AND THEN PRESS THE ENTER KEY',CR,LF,'$'

USER_STRING LABEL BYTE

MAX_LENGTH DB 30H

NAME_LENGTH DB ?

FILENAME DB 31H DUP(' ')

 

HANDEL DW ?

BUFFER DB 512D DUP(?)

CHARS_READ DW 512D

DATA ENDS

WORKING_STORAGE SEGMENT STACK

DW 100H DUP(?)

WORKING_STORAGE ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:WORKING_STORAGE

;establish data segment addressability
PROG_START: 

MOV AX,DATA

MOV DS,AX

;ES := DS

MOV ES,AX

;prompt user for filename

MOV AH,9H

LEA DX,PROMPT

INT 21H

;read filename

MOV AH,0AH

LEA DX,USER_STRING

INT 21H

;print a new line

CALL PRINT_NEWLINE

;prepare ASCIIZ string representing user's filename

MOV BL,NAME_LENGTH

MOV BH,0

ADD BX,OFFSET FILENAME

MOV [BX],BYTE PTR 0

;set DOS create file function

MOV AH,3CH

;set 'normal file' attribute

MOV CX,0

;DX := address of ASCIIZ string

LEA DX,FILENAME

;create the file

INT 21H

;if carry flag clear then

JC DONE

;begin

;store handle

MOV HANDLE,AX

 

;repeat

READ_RECORD:

CLD

;count :=512D

MOV CX,512D

;DI := buffer address

LEA DI,BUFFER

;repeat read(ch)

NEXT_DATA_BYTE:

CALL READ_A_CHARACTER

;next acailable buffer location := ch

STOSB

;count := count - 1

;until ch = 1Ah or count= = 0

CMP AL,1AH

JZ SET_CHAR_COUNT

LOOPNZ NEXT_DATA_BYTE ;LOOP does count := count - 1

;if ch  = 1AH then chars_read := 512D - count

SET_CHAR_COUNT:

CMP AL,1AH

JNZ WRITE_RECORD

MOV AX,512D

SUB AX,CX

MOV CHARS_READ,AX

;write chars_read bytes from BUFFER to file

WRITE_RECORD:

MOV AH,40H

MOV BX,HANDLE

MOV CX,CHARS_READ

LEA DX,BUFFER

INT 21H

;until CF <> 0 or chars_read <> 512D

JC CLOSE

CMP CHARS_READ,512D

JZ READ_REACORD

;close file

CLOSE:

MOV AH,3EH

MOV BX,HANDLE

INT 21H

;end

;return to DOS

DONE:

MOV AX,4C00H

INT 21H

READ_A_CHARACTER PROC NEAR

MOV AH,1

INT 21H

READ_A_CHARACTER ENDP

 

PRINT_NEWLINE PROC NEAR

PUSH AX

MOV AH,2H

MOV DL,CR

INT 21H

MOV DL,LF

INT 21H

POP AX

RET

PRINT_NEWLINE ENDP

  

CODE ENDS
END PROG_START


by sneakerz

화일 복사

 

 

CR EQU 0DH

LF EQU 0AH

DATA SEGMENT

PROMPT1 DB 'PLEASE TYPE THE NAME OF THE SOURCE FILE '

                 DB 'AND THEN PRESS THE ENTER KEY',CR,LF,'$'
PROMPT2 DB 'PLEASE TYPE THE NAME OF THE FILE IN WHICH '

                 DB 'THE COPY IS TO BE MADE AND THEN PRESS THE '

                 DB 'ENTER KEY',CR,LF,'$'

 

USER_STRING1 LABEL BYTE

MAX_LENGTH1 DB 30H

NAME_LENGTH1 DB ?

FILENAME1 DB 31H DUP(' ')

HANDEL1 DW ?

 

USER_STRING2 LABEL BYTE

MAX_LENGTH2 DB 30H

NAME_LENGTH2 DB ?

FILENAME2 DB 31H DUP(' ')

HANDEL2 DW ?

 

BUFFER DB 511D DUP(?)

LAST_OF_DATA DW ?

 

;error messages

NO_SUCH_FILE DB 'NO SUCH FILE EXISTS',CR,LF,'$'

DIRECTORY_FULL DB 'CANNOT CREATE A NEW FILE - TOO MANY '

                             DB 'FILES ON THE DISK',CR,LF,'$'

DISK_FULL DB 'NO ROOM LEFT ON THE DISK',CR,LF,'$'

DISK_WRITE_PROTECTED DB 'DISK WRITE PROTECTED',CR,LF,'$'

NORMAL_END DB 'COPY COMPLETED',CR,LF,'$'

DATA ENDS

WORKING_STORAGE SEGMENT STACK

DW 100H DUP(?)

WORKING_STORAGE ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:WORKING_STORAGE

;establish data segment addressability
PROG_START: 

MOV AX,DATA

MOV DS,AX

;ES := DS

MOV EX,AX

;prompt for source filename

MOV AH,9H

LEA DX,PROMPT1

INT 21H

;read source filename

MOV AH,0AH

LEA DX,USER_STRING1

INT 21H

;print a new line

CALL PRINT_NEWLINE

;prepare ASCIIZ string representing source filename

MOV BL,NAME_LENGTH1

MOV BH,0

ADD BX,OFFSET FILENAME1

MOV [BX],BYTE PTR 0

;prompt for name of file in which copy is to be made

MOV AH,9H

LEA DX,PROMPT2

INT 21H

;read source filename

MOV AH,0AH

LEA DX,USER_STRING2

INT 21H

;print a new line

CALL PRINT_NEWLINE

;prepare ASCIIZ string representing file in which copy is to be made

MOV BL,NAME_LENGTH2

MOV BH,0

ADD BX,OFFSET FILENAME2

MOV [BX],BYTE PTR 0

;error := false;

MOV BH,0

;try to open source file for reading only

MOV AH,3DH

MOV AL,0

LEA DX,FILENAME1

INT 21H

;save handle for source file

MOV HANDLE1,AX

;if CF<> 0 then error := true;

JNC OPEN_OK

MOV BH,1

;DX := address of 'open' error message

OPEN_OK:

LEA DX,NO_SUCH_FILE

;if not error then

CMP BH,0

JNZ READ_BLOCK

;begin

;create new objext file;

MOV AH,3CH

MOV CX,0

LEA DX,FILENAME2

INT 21H

;save object file handle

MOV HANDLES2,AX

;if CF <> 0 then error := true

JNC CREATE_ok

MOV BH,1

;DX := address of 'create' error message

CREATE_OK:

LEA DX,DIRECTORY_FULL

;end

;if not error then

READ_BLOCK:

CMP BH,0

JNZ END_OF_FILE_BLOCK

;repeat

;fill buffer from source file

MOV AH,3FH

LEA DX,BUFFER

MOV CX,512D

MOV BX,HANDLE1

INT 21H

;DI := AX(* no of bytes read *)

MOV DI,AX

;write contents of buffer

;to the object file;

MOV AH,40H

MOV BX,HANDLE2

MOV CX,DI

LEA DX,BUFFER

INT 21H

;if CF <> 0 then error := true

JNC WRITE_OK

MOV BH,1

;DX := address of 'write' error message

WRITE_OK:

LEA DX,DISK_FULL

;until DI < 512D or error;

CMP DI,512D

JB END_OF_FILE_BLOCK

CMP BH,0

JNZ END_OF_FILE_BLOCK

JMP READ_BLOCK

;if not error then

END_OF_FILE_BLOCK:

CMP BH,0

JNZ DONE

;begin

;close object file

END_OF_FILE:

MOV AH,3EH

MOV BX,HANDLE2

INT 21H

;DX := address of 'close' error message

LEA DX,DISK_WRITE_PROTECTED

;if CF = 0 then DX := address of 'normal end' message

JC DONE

MOV DX,OFFSET NORMAL_END

;end

;print message addressed by DX

DONE:

MOV AH,09H

INT 21H

;return to DOS

MOV AX,4C00H

INT 21H

PRINT_NEWLINE PROC NEAR

PUSH AX

MOV AH,2H

MOV DL,CR

INT 21H

MOV DL,LF

INT 21H

POP AX

RET

PRINT_NEWLINE ENDP

 

CODE ENDS
END PROG_START


by sneakerz

랜덤 액세스 읽기 유틸리티

 

 

CR EQU 0DH

LF EQU 0AH

DATA SEGMENT

PROMPT DB 'PLEASE TYPE THE NAME OF THE FILE TO BE READ '

               DB 'AND THEN PRESS THE ENTER KEY',CR,LF,'$'

USER_STRING LABEL BYTE

MAX_LENGTH DB 30H

NAME_LENGTH DB ?

FILENAME DB 31H DUP(' ')

 

HANDEL DW ?

BUFFER DB 512D DUP(?)

DATA ENDS

WORKING_STORAGE SEGMENT STACK

DW 100H DUP(?)

WORKING_STORAGE ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:WORKING_STORAGE

;establish data segment addressability
PROG_START: 

MOV AX,DATA

MOV DS,AX

;prompt user for filename

MOV AH,9H

LEA DX,PROMPT

INT 21H

;read filename

MOV AH,0AH

LEA DX,USER_STRING

INT 21H

;print a new line

CALL PRINT_NEWLINE

;prepare ASCIIZ string representing user's filename

MOV BL,NAME_LENGTH

MOV BH,0

ADD BX,OFFSET FILENAME

MOV [BX],BYTE PTR 0

;DOS open file function

MOV AH,3DH

;open for reading only

MOV AL,0

;DX := address of ASCIIZ string

LEA DX,FILENAME

INT 21H

;if carry flag clear then

JC DONE

;begin

;store handle

MOV HANDLE,AX

;read(ch); print(new line);

MOV AH,1

INT 21H

CALL PRINT_NEWLINE

;while ch <> 'X' do

A_RECORD:

CMP AL,'X'

JZ DONE

;begin

;if ch in ['0'..'9'] then

SUB AL,30H

JAE CHECK_UPPER_LIMIT

JMP KEY_IN

CHECK_UPPER_LIMIT:

CMP AL,10D

JNB KEY_IN

;begin

;DX,AX := 512D * digit read

MOV AH,0

MOV BX,512D

MUL BX

;CX,DX := DX,AX

MOV CX,DX

MOV DX,AX

;set file pointer to ch-th group of 512 bytes

MOV AH,42H

MOV AL,0

MOV BX,HANDLE

INT 21H

;read the ch-th group of 512D bytes into buffer

MOV AH,3FH

LEA DX,BUFFER

MOV CX,512D

MOV BX,HANDLE

INT 21H

;if AX <> 0 and CF = 0

CMP AX,0

JZ READ_NEXT_ins

JC KEY_IN

;then display buffer contents 

CLD

MOV CX,AX

LEA SI,BUFFER

LODSB

MOV DL,AL

CALL PRINT_A_CHARACTER

LOOP NEXT_CHARACTER

;end

JMP READ_NEXT_INS

;else print error message

KEY_IN:

CALL ERROR_MESSAGE

;read(ch); print(new line)

READ_NEXT_INS:

CALL PRINT_NEWLINE

MOV AH,1

INT 21H

CALL PRINT_NEWLINE

;end

NEXT:

JMP A_RECORD

;end

;return to DOS

DONE:

MOV AX,4C00H

INT 21H

PRINT_A_CHARACTER PROC NEAR

MOV AH,2

INT 21H

RET

PRINT_A_CHARACTER ENDP

 

PRINT_NEWLINE PROC NEAR

PUSH AX

MOV AH,2

MOV DL,CR

INT 21H

MOVDL,LF

INT 21H

POP AX

RET

PRINT_NEWLINE ENDP

 

ERROR_MESSAGE PROC NEAR

MOV AH,2

MOV DL,'?'

INT 21H

RET

ERROR_MESSAGE ENDP

 

CODE ENDS
END PROG_START


by sneakerz

화일로서의 장치 예

 

 

CR EQU 0DH

LF EQU 0AH

DATA SEGMENT

PROMPT DB 'PLEASE TYPE A SEVEN LETTER NAME',CR,LF

REPLY DB CR,LF,'HOWDY '

PERSON DB 7 DUP(' '),CR,LF

DATA ENDS

WORKING_STORAGE SEGMENT STACK

DW 100H DUP(?)

WORKING_STORAGE ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:WORKING_STORAGE

;establish data segment addressability
PROG_START: 

MOV AX,DATA

MOV DS,AX

;prompt user for name

MOV AH,40H

MOV BX,1

LEA DX,PROMPT

MOV CX,33D

INT 21H

;read filename

MOV AH,3FH

LEA DX,PERSON

MOV BX,0

MOV CX,7

INT 21H

;display grreting

MOV AH,40H

MOV BX,1

LEA DX,REPLY

MOV CX,17D

INT 21H

;return to DOS

DONE:

MOV AX,4C00H

INT 21H

ERROR_MESSAGE ENDP

 

CODE ENDS
END PROG_START


by sneakerz

com 화일 예(메모리에 저장된 한 자리 숫자를 추측하여 맞추는 프로그램)

 

 

CR EQU 0DH

LF EQU 0AH

 

CODE SEGMENT

ASSUME CS:CODE

ORG 100H

ENTRY:

JMP START

;-------------------------data---------------------

PROMPT DB 'GUESS MY NUMBER',CR,LF,'$'

REPLY1 DB CR,LF,'GENIUS',CR,LF,'$'

REPLY2 DB CR,LF,'NOPE',CR,LF,'$'

NUMBER DB '3'

;--------------------------------------------------

;display the user prompt

START:

LEA DX,PROMPT

MOV AH,9H

INT 21H

;read a digit

MOV AH,1

INT 21H

;if guess is correct then DX points to GEIUS message

CMP AL,NUMBER

JNZ BAD_GUESS

LEA DX,REPLY1

JMP GIVE_MESSAGE

;else DX points to NOPE message

BAD_GUESS:

LEA DX,REPLY2

;display message

GIVE_MESSAGE:

MOV AH,9H

INT 21H

;return to dos

MOV AX,4C00H

INT 21H

CODE ENDS
END PROG_START


by sneakerz

키보드에서 타이핑한 프린트 가능한 문자는 병렬 인터페이스 장치를 통하여 연결된 프린터로 보내진다. 문자 X를 타이핑하면 실행이 종료되어 DOS로 돌아간다.

 

 

CR EQU 0DH

LF EQU 0AH

 

DATA SEGMENT

DATA ENDS

 

WORKING_STORAGE SEGMENT STACK

DW 100H DUP(?)

WORKING_STORAGE ENDS

 

CODE SEGMENT

ASSUME CS:CODE,DX:DATA,SS:WORKING_STORAGE

;set up data segment addressability

PROG_START:

MOV AX,DATA

MOV DX,AX

;initialize the printer

MOV DX,3BEH

;set bit 6 of output control port to 0

MOV AL,08H

OUT DX,AL

MOV AL,0CH

MOV CX,50D

;wait at least 50 microseconds

WAIT:

NOP

LOOP WAIT

;repeat read a character from the keyboard

READ:

CALL READCHAR

;print it

CALL SEND_TO_PRINTER

;if char = CR

CMP AL,CR

JNZ XCHECK

;the begin

;print a LF

MOV AL,LF

CALL SEND_TO_PRINTER

;LF to display

CALL DISPLAY_NEWLINE

;end

;until char = 'X'

XCHECK:

CMP AL,'X'

JZ DONE

JMP READ

;return to DOS

DONE:

MOV AX,4C00H

INT 21H

SEND_TO_PRINTER PROC NEAR

;save char on stack

PUSH AX

;transfer character to data port

MOV DX,3BCH

OUT DX,AL

;check if the printer is busy

MOV DX,3BDH

TEST_IF_BUSY:

IN AL,DX

TEST AL,80H

JZ TEST_IF_BUSY

;now print the character

MOV DX,3BEH

MOV AL,0DH

;start printing

OUT DX,AL

MOV AL,0CH

;stop printing

OUT DX,AL

;restore character from stack

POP AX

RET

SEND_TO_PRINTER ENDP

 

READCHAR PROC NEAR

MOVAH,1

INT 21H

RET

READCHAR ENDP

 

DISPLAY_NEWLINE PROC NEAR

MOV AH,2

MOV DL,LF

INT 21H

DISPLAY_NEWLINE ENDP

 

CODE ENDS
END PROG_START

[출처] 어셈블리|작성자 산으로

[출처] http://blog.naver.com/sneakerj/120021024068

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함