본문 바로가기
어셈블리어 공부용/x86 어셈블리어(ASSEMBLY)

emu8086으로 어셈블리어연습 [어셈블리어 구구단]

by Redoutable 2019. 8. 18.
반응형
.MODEL SMALL
.CODE
ORG 100h

PROG:
    CALL MAIN        ;MAIN 프로시저 불러오기
    HLT              ;MAIN 프로시저가 끝나면 프로그램을 중단시킨다.

BLANK1 DB 'X$'       ;구구단 출력시에 x 출력을 담당하는 데이터영역입니다.
BLANK2 DB '=$'       ;구구단 출력시에 = 출력을 담당하는 데이터영역입니다. 
CRLF DB 0Dh,0Ah,'$'  ;캐리지리턴, 라인피드 (줄바꿈)를 담당하는 데이터영역입니다.
    
    
MAIN PROC NEAR       ;메인 프로시저 시작.

MOV AL,2             ;구구단의 시작은 2 x
MOV BL,1             ;1 이니까 사용할 레지스터에 데이터를 수록합니다.

MOV CX,0             ;구구단 출력에 앞서서 cx레지스터를 청소합니다.

TOP:

PUSH AX              ;AX값을 잠시 스택에 저장합니다. (복사되어 스택에 저장되므로 레지스터값은 변함없음.)

                     ; (X * Y =) 출력하기.

MOV AH,02            ;한 문자 출력하는 기능번호 AH에 수록.

MOV DL,AL            ;DL레지스터에 AL레지스터 값을 전달합니다. (이 값은 구구단 X * Y 중 X에 해당합니다.)
ADD DL,30h           ;30h를 더해서 아스키코드화 합니다. (2 = 32h)
INT 21h              ;실행 (X가 출력됨.)

LEA DX,BLANK1        ;BLANK1 데이터영역 주소를 DX레지스터에 저장합니다. (X * Y 중에서 *에 해당함.)
MOV AH,09            ;문자열을 출력하는 기능번호 AH에 수록.
INT 21h              ;실행 (X(*) 출력됨.)

MOV AH,02            ;다시 한 문자를 출력해야 하므로 AH 레지스터에 2 수록.

MOV DL,BL            ;DL레지스터에 BL레지스터값을 전달합니다. (이 값은 구구단 X * Y중 Y에 해당합니다.)
ADD DL,30h           ;30h를 더해서 아스키코드화 합니다. (1 = 31h)
INT 21h              ;실행 (Y이 출력됨.)

LEA DX,BLANK2        ;DX 레지스터에 BLANK2데이터영역의 주소를 저장합니다.
MOV AH,09            ;문자열을 출력하는 기능번호 수록
INT 21h              ;실행 ( = 가 출력됨.)

POP AX               ;저장해 두었던 값을 스택에서 AX레지스터로 가져옵니다.
PUSH AX              ;진수변환 하면서 AX레지스터를 사용해야 하므로 다시한번 스택에 AX레지스터값을 저장합니다.

MUL BL               ; AL레지스터를 BL레지스터에 있는 값으로 곱셈(X*Y)합니다. 결과는 AX레지스터에 리턴됩니다.
INC BL               ; BL레지스터값을 늘립니다. (X*Y중에서 Y값 늘림.)

PUSH BX              ; 진수변환때 BX레지스터를 사용해야 하므로, BX레지스터값을(Y값을) 스택에 저장합니다.
MOV CX,0             ; 진수변환 앞서 청소하기


                     ;16진수 10진수로 변환한다음 스택에 저장하고 스택에 저장한걸 꺼내어 출력하기.

PUSHDECA:
    MOV DX,0         ;진수변환 앞서 DX값 청소
    MOV BX,10        ;10진수 변환은 10으로 나누어 나머지를 나열하는것이므로 10 수록.
    
    DIV BX           ;AX레지스터를 BX레지스터값으로 나눕니다. 
    PUSH DX          ;DX레지스터값(나머지)를 스택에 저장합니다.
    INC CX           ;CX값을 1 증가시킵니다. (출력할때 자릿수 세는걸로 쓰는용도임.)
    CMP AX,0         ;AX레지스터(몫)이 0인가?
    JNE PUSHDECA     ;아니라면 진수변환 계속.
    
POPDECA:
    POP DX           ;스택에서 DX레지스터로 데이터를 가져옵니다. (결과적으로 나머지가 역순으로 꺼내어짐.)
    ADD DX,30h       ;DX레지스터에 30h를 더하여 아스키코드화함.
    MOV AH,02        ;한 글자를 출력하는 기능번호 준비
    INT 21h          ;실행
    
    DEC CX           ;CX값을 1 감소시킵니다.
    CMP CX,0         ;CX값이 0인가? (모든 자릿수가 출력되었는지?)
    JNE POPDECA      ;아니라면 출력을 계속한다.

                     ;여기서 X*Y=XY 가 완전히 출력되었음.
    
    MOV DL,' '        ;DL에 공백(아스키코드로 20h) 수록.
    MOV AH,02         ;한 글자를 출력하는 기능번호 준비
    INT 21h           ;실행
        
POP BX                ;스택에 보전해두었던 데이터(Y)를 BX에 그대로 가져옴.


CMP BL,10             ;BX가 10인가?
JE SEC                ;10이라면 SEC로 보냄.(구구단은 9까지이므로 여기서 끊음.)

POP AX                ;스택에 보전해두었던 데이터(X)를 AX에 그대로 가져옴.
JMP TOP               ;구구단 출력을 계속한다.

SEC:
    POP AX            ;스택에 보전해두었던 데이터(X)를 AX에 그대로 가져옴.
    MOV BL,1          ;BL(Y값)을 1로 초기화한다. 
    INC AL            ;AL(X값)에 1을 더한다.
    CMP AL,10         ;그런데 AL이 10인가?
    JE ENND           ;AL이 10이라면 끝으로 보냄.
    
    PUSH AX           ;AX값(X값)을 스택에 보존. 줄바꿀때 AX레지스터 사용해야함.

    LEA DX,CRLF       ;줄바꿈실행
    MOV AH,9
    INT 21h

    POP AX            ;AX값(X값) 다시 가져옴.
    
    JMP TOP
    
ENND:
RET                   ;MAIN PROC에서 벗어나서 메인루틴으로 복귀한다.

MAIN ENDP
END PROG

 

 

모양이 이쁘지는 않지만 구구단 입니다.

어셈블리어에서 구구단을 짜보니까 상당히 번거롭네요.

반응형

댓글