제목:

MSX 어셈블리어로 Hello, world! 롬 만들기 예제

날짜: Posted on

MSX 컴퓨터에 꽂으면 “Hello, world!”라는 문자열을 출력하고 끝내는 롬팩 카트리지를 만든다고 가정하고 이를 어셈블리어로 코딩해 봅시다.

CHPUT:  equ 0x00a2  ; 문자 출력을 위한 BIOS 코드

; 올바른 ROM이 되도록 설정
        org 0x4000  ; ROM 기준 주소
        
        db  "AB"    ; ROM 시그니처
        dw  Execute ; 시작 지점 지정
        db  0,0,0,0,0,0,0,0,0,0,0,0

; 시작
Execute:
        ld hl, HelloWorld     ; hl에 HelloWorld 싣기
        call Print  ; Print 루틴 호출
        di          ; 인터럽트 해제
        halt        ; 프로그램 종료

Print:
        ld a,(hl)   ; 문자열 하나 읽기
        cp 0        ; Null 값 체크
        ret z       ; Null이면 나간다, 아니면 다음
        call CHPUT  ; 문자 출력
        inc hl      ; 피연산자 hl 값 +1
        jr Print    ; 반복
        
HelloWorld:
        db "Hello, world!",0  ; HelloWorld 정의
        ds 0x8000 - $         ; 변수 저장 위치

보다시피 BASIC으로 짜면 10 PRINT "Hello, world!" 한 줄이면 될 코드가 이렇게 길게 늘어져 있습니다. 물론 이는 기계어와 1:1 대응인 어셈블리어의 특성상 어쩔 수 없는 점이기는 합니다. 이 코드가 어떻게 돌아가는지를 설명하자면,

맨 첫 줄에 문자 출력을 위한 MSX BIOS 호출 코드 0x00a2를 CHPUT라는 상수로 지정해 둡니다. 그런 다음 4번 줄에서 기준 주소를 정합니다. MSX의 ROM은 기준 주소가 0x4000입니다. 6번 줄은 첫 데이터가 “AB”로 시작하게 하는데, MSX는 ROM의 첫 데이터가 AB로 시작해야 유효한 ROM으로 인식하기 때문입니다. 7번 줄은 ‘Execute’로 정의된 주소를 워드(2바이트) 형태로 넣어서 Execute로 정의된 주소에서 시작하라는 표식을 추가합니다. 그리고 8번 줄에 Null 값을 몇 바이트 추가합니다.

이제 본격적인 시작입니다. 11번 줄은 ‘Execute’라는 정의만 있고 아무 것도 없으므로 넘기고, 12번 줄은 ‘HelloWorld’로 정의된 영역(25-27번 줄)의 데이터를 HL 레지스터에 적재합니다. 26번 줄에서 “Hello, world!” 뒤(맨 끝)에 Null 값을 추가합니다. 그리고 13번 줄은 ‘Print’로 정의된 루틴을 호출합니다. 17번 줄로 넘어갑니다.

17번 줄은 ‘Print’라는 정의만 있으므로 넘어가고, 18번 줄은 HL 레지스터에 적재된 문자열 데이터를 A 레지스터에 넣습니다. 이 때 HL 레지스터의 값은 0이므로 맨 앞의 H가 들어갑니다. 19번 줄은 방금 A 레지스터에 적재된 데이터 값이 0인지 체크합니다. 0이 아니므로 20번 줄을 건너뛰고 21번 줄로 넘어가서, 문자 출력 BIOS를 호출하여 A 레지스터에 적재된 문자 ‘H’를 출력합니다. 그런 다음 위치를 22번 줄에서 HL 레지스터의 값을 1 증가시키고, 23번 줄은 다시 17번 줄로 돌아가는 명령입니다. 또 18번 줄로 넘어가 HL 레지스터에 적재된 문자열 데이터를 A 레지스터에 넣게 되는데, HL 레지스터 값이 1 증가했으므로 H 다음의 문자열 e를 적재합니다. 그러면 21번 줄에서는 A 레지스터에 적재된 문자 ‘e’를 출력할 것입니다. 이를 반복하다가 마지막에는 맨 끝의 Null 문자가 적재되고, 이러면 19번 줄의 ‘cp 0’을 만족하게 되므로 20번 줄의 ‘ret z’ 명령을 실행, 루틴을 끝내고 ‘call Print’가 있던 줄의 다음 줄인 14번 줄로 넘어갑니다.

14번 줄은 인터럽트를 해제하는 명령입니다. 이제 ‘Hello, world!’를 출력한다는 목적은 달성했으니, 프로그램을 종료할 준비를 하기에 앞서 인터럽트를 해제하는 것입니다. 그리고 15번 줄의 halt 명령을 통해 프로그램을 완전히 종료합니다. 정확히 말하자면 이 명령은 시스템을 완전히 정지시키는 명령입니다.

이 프로그램의 실행 결과는 다음과 같습니다.

직접 확인해 볼 수 있는 링크는 [이 곳]을 클릭해 주세요.
위 링크는 소스 코드를 아래와 같이 수정하여 기계어로 변환한 것입니다.

CHPUT:  equ 0x00a2  ; 문자 출력을 위한 BIOS 코드
CLS:    equ 0x00c3  ; 화면 지우기 위한 BIOS 코드

; 올바른 ROM이 되도록 설정
        org 0x4000  ; ROM 기준 주소
        
        db  "AB"    ; ROM 시그니처
        dw  Execute ; 시작 지점 지정
        db  0,0,0,0,0,0,0,0,0,0,0,0

; 시작
Execute:
        ld hl, HelloWorld     ; hl에 HelloWorld 싣기
        xor a       ; 화면 지우기 전 처리
        call CLS    ; 화면 지우기
        call Print  ; Print 루틴 호출
        di          ; 인터럽트 해제
        halt        ; 프로그램 종료

Print:
        ld a,(hl)   ; 문자열 하나 읽기
        cp 0        ; Null 값 체크
        ret z       ; Null이면 나간다, 아니면 다음
        call CHPUT  ; 문자 출력
        inc hl      ; 피연산자 hl 값 +1
        jr Print    ; 반복
        
HelloWorld:
        db "Hello, world!"  ; HelloWorld 정의
        db 13,10,13,10      ; 줄 바꿈 두 번
        db "https://pjw48.net :)"
        db 0                ; 문자열의 끝
        ds 0x8000 - $       ; 변수 저장 위치

1개의 댓글이 있습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다