본문 바로가기
IT/Assembler

어셈블리어 곱하기 소스

by Jang HyunWoong 2014. 12. 19.

.286                         ; 286명령어를 사용할수 있게 한다.

SSEG SEGMENT STACK           ; EXE파일을 만들 것이므로 스택설정한다.
     DB 256 DUP(?)
SSEG ENDS

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

DSEG SEGMENT
     BUFFER  DB ?, " * ", ?, " = ", ?, ?, 0DH, 0AH, '$'
     DIVNUM DB 10            ; 결과값이 10을 넘을 경우 두부분으로 나누기 위해 10을 넣는다.
DSEG ENDS                    ; 데이터 세그먼트 영역.
                             ; 화면에 출력할 포맷임.
                             ; 하지만 문제는 세번째 ?부분은 ?, ?가 되어야 한다.
                             ; 연산결과는 십진수로 2자리이고 바이트 1개 자리로 표현 되는
                             ; 숫자문자는 0부터 9까지만이므로 한자리가 더 필요하다.

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::


CSEG SEGMENT 'CODE'
     ASSUME CS:CSEG, SS:SSEG, DS:DSEG

MAIN PROC FAR

PUSH DS                      ; 프로그램을 정상적으로 종료시키기 위해 스택에 리턴할 주소를 넣는다.
PUSH 0                       ; 먼저 PSP(Program Segment Prefix) 세그먼트 주소를 스택에 넣고 리턴할 옵셋인 0을 넣는다.
                             ; 이렇게 하면 프로그램 종료를 위해 아래 RETF명령을 사용하면
                             ; PSP맨 앞에 있는 CD 20(INT 20h)를 실행하여 프로그램을 종료하게 된다.

MOV AX, DSEG                 ; 데이터 세그먼트로 설정된 DSEG의 세그먼트 주소를 DS에 넣는다.
MOV DS, AX


;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

MOV BH, 5                    ; 출력하고자 하는 단수. 여기에 원하는 단수를 넣으면 된다.

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

MOV CX, 9                    ; 루프 반복 횟수
MOV BL, 0                    ; 곱해지는 수 초기화(1,...,9)

L1:
ADD BL, 1                    ; BL값에 1씩 더한다. BL은 루프안에서 1부터 9까지 된다.
                             ; 간단하게 INC BL해도 된다.

MOV AL, BL                   ; BL값을 AL로 복사한다. 
MUL BH                       ; AX = BH(단수) * AL(각 단 내에서 곱해지는수)
                             ; 결과는 AX로 얻어진다.

MOV BUFFER, BH               ; (1) * (2) = (3) 에서 (1)부분 세팅
ADD BUFFER, '0'              ; 화면에 출력할 단수값을 데이터 세그먼트안의 BUFFER에 저장하고 30H('0')를 더한다.

MOV BUFFER+4, BL             ; (1) * (2) = (3) 에서 (2)부분 세팅
ADD BUFFER+4, '0'            ; 화면에 출력할 곱해지는 수를 데이터 세그먼트 안의
                             ; BUFFER에서 4번째(위에서 두번째 ?)에 저장하고 30H('0')를 더한다.

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
;
; ADD AL, '0'                ; (1) * (2) = (3) 에서 (3)부분 세팅
; MOV BUFFER+8, AL           ; 얻어진 연산결과에 30H('0')를 더한후 BUFFER에서 8번째(위에서 세번째?)에 저장한다.
;
; 위 코드는 잘못되었다. AL(AX)에 있는 값은 0부터 9까지의 수만이 아니기 때문이다.
; 그렇기 때문에 이것을 화면에 출력하려면 두 부분으로 나누어야 한다.
; 결과값을 10으로 나눈 나머지와 몫을 별도로 출력해야 한다.

CMP AL, 10                   ; 10보다 작으면 그냥 출력.
JL L2
; 10이상인경우
DIV DIVNUM                   ; 10이상이면 10으로 나눈다음.
MOV BUFFER+8, AL             ; AL에 있는 몫을 저장한다음.
ADD BUFFER+8, '0'            ; 30H를 더해 숫자문자로 변환.
MOV BUFFER+9, AH             ; AH에 있는 나머지 부분을 저장한다음.
ADD BUFFER+9, '0'            ; 30H를 더해 숫자문자로 변환한다.

JMP  short L3

L2:
MOV BUFFER+8, ' '            ; 10미만이면 앞에는 공백문자를 넣고 뒤에 결과값을
MOV BUFFER+9, AL             ; 넣고 30H를 더해 숫자문자화시킨다.
ADD BUFFER+9, '0'

L3:

;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

MOV AH, 09H                  ; 위 과정에 의해 세팅된 문자열을 화면에 출력
LEA DX, BUFFER
INT 21H

LOOP L1                      ; CX만큼 반복한다.

RET                          ; RET명령을 썻지만 어셈블하면 RETF명령에 해당되는 코드로 변환된다.
                             ; 이 명령을 사용하여 PSP:0000에 있는 CD 20을 실행하는 곳으로 간다.

MAIN ENDP

CSEG ENDS
     END MAIN

반응형