코모도어 64/프로그래밍

이 문서에서는 C64 소프트웨어를 작성하는 방법에 대해서 알아보자. 이 문서를 끝까지 읽는 것만으로 당신도 C64 프로그래머!

들어가기에 앞서

프로그래밍 언어

C64는 두 가지 프로그래밍 언어를 지원한다.

  • 기본 제공하는 BASIC
    • 일단 배우기 쉽다.
    • 특별히 보조 프로그램을 사용하지 않아도 C64에서 곧장 코딩이 가능.
    • 프로그램 처리 속도는 아주 느리다.
    • 메모리에 직접 접근할 일이 있을때 불편하다.
  • 어셈블리어
    • 진입장벽이 높다.
    • 메모리 맵, 인터럽트 등 고급 지식이 필요하다.
    • 보조 프로그램을 사용하지 않으면 난이도가 비약적으로 상승.
    • 메모리를 주물주물하고, 그래픽 칩, 인터럽트, 뭐든지 마음대로 접근할 수 있다.
    • 속도가 BASIC보다 훨씬 빠르다.

서로 장단점이 있지만, 큰 프로그램을 작성하려면 결국은 어셈블리어를 사용하게 될 것이다. 컴퓨터 구조상 메모리에 직접 접근할 일이 무수히 발생하기 때문이다. 하지만 우리는 처음 시작하는 입장이니, BASIC부터 해 보도록 하자.

에뮬레이터

혹시라도 C64 본체를 가지고 있는 부러운 사람에게는 미안하지만, 우리는 에뮬레이터를 가지고 코딩을 하기로 하자. 유명한 에뮬레이터로는 CCS64, VICE, C64 Forever 등이 있는데, 여기서는 VICE를 사용하기로 하자. 홈페이지에서 다운로드 받을 수 있고, 포터블 버전이다. 32비트와 64비트 모두 지원한다.

BASIC 프로그래밍

준비

다운로드한 에뮬레이터를 실행해 보자. x64.exe라는 파일이다. 아마 창이 하나 뜨면서, 아래 사진과 같은 보라색 화면이 나타날 것이다.

C64 ready.png

달랑 커서 하나만 깜빡이고 있지만, 이것이 c64의 메인 화면이고 앞으로 계속해서 보게 될 것이다.

키보드

C64는 특수문자를 많이 사용했는데, 이 녀석들은 키보드에 따로 배정되어 있거나 특수한 조합으로 입력할 수 있었다. 지금 우리가 쓰는 키보드에는 당연히 그런 키가 없기 때문에 에뮬레이터에서 키보드 위치에 맞게 적당히 넣어 두었다. 그런데 우리는 그 위치를 모르니 일일이 눌러 가면서 외워야만 한다! 이것은 정말 끔찍한 일이므로 이곳에 '널리 쓰이는' 키보드 맵을 실어 둔다. VICE와는 다를 수 있지만 자주 쓰는 키들은 동일하다. 만약 특수한 입력법이 필요한 경우에는 따로 적도록 하겠다. return 옆의 등호(=)는, 백슬래시(\)키에 배정되어 있다.

C64-keyboard-layout.png

기본적인 것들

Hello, World

늘 그렇듯, 맨 처음엔 Hello, World를 출력해보자. READY가 표시된 상태에서 다음을 입력하고 엔터를 누른다.

PRINT"HELLO,WORLD!"

그러면 HELLO,WORLD!가 출력된 후 READY가 다시 표시될 것이다. 잘 됐다면, 축하한다, 첫 C64 프로그램 작성에 성공했다!

비록 한 줄짜리 짧은 코드이지만 여기서도 여러 것들을 배울 수 있다.

먼저, 공백 문자를 전혀 쓰지 않았다는 데에 주목해 보자. 전부 띄어쓰기 없이 붙어 있다. 공백을 넣어도 제대로 작동되는 코드들도 있지만, 바로 에러를 뱉어내는 코드도 있다. 그러니 안 쓰는 쪽으로 통일하는 편이 낫다. 다른 이유로는 메모리 문제가 있다. 아무리 64KB의 메모리가 있더라도 우리가 직접 쓸 수 있는 메모리는 한정되어 있다. 그런데 우리가 적은 코드는 전부 메모리에 저장된다. 지금은 단 한 줄 짜리 코드였지만, 당신이 정말로 작정하고 프로그램을 짠다면 몇십 줄은 고사하고 몇백 줄을 짜게 될 것이다. 만약 그 코드가 메모리에 담기에는 너무 크다면... 앞쪽에 쓴 코드부터 지워지게 된다. 그렇다, 기껏 적은 프로그램이 없어져 버리는 것이다! 때문에 최대한 메모리 사용을 줄이려는 경향이 생겼고, 공백 문자는 1순위로 지워지는 신세가 됐다.

다음으로, READY에 대해 생각해 보자. 컴퓨터를 처음 켜면 READY가 표시되고, 명령을 다 실행해도 READY가 표시된다. 이 READY는 컴퓨터가 명령을 받을 준비가 되었다는 뜻이다. 이 말은, 당장 실행중인 프로그램이 없다는 말이다.

실행중인 프로그램이 없다면, 내가 방금 만든 한 줄짜리 프로그램은 어디로 가 버린 것일까? 영영 없어져 버린 것일까?

줄 번호

안타깝게도, 방금 만든 'Hello, World!'는 사라져 버렸다. 그렇다, 영영 없어져 버렸다. 메모리에도 남아 있지 않고, 단지 화면 위에 남은 글자가 그런 프로그램이 실행된 적은 있었다고 알려 주고 있을 뿐이다. 왜 이런 일이 일어났을까? 바로 줄번호를 생략했기 때문이다.

BASIC에서는 모든 코드 앞에 줄 번호를 붙인다. 이 줄 번호는 매 줄마다 붙는 꼬리표같은 것이다. 내 마음대로 설정해 줄 수 있는데, 1~63999까지 가능하다. 이 번호를 붙이지 않으면 여러 줄을 작성할 수조차 없다. 자, 이제 일회용으로 끝나지 않는 코드를 적어 보자.

10 PRINT"HELLO,WORLD!"
RUN

10번 라인을 적고 엔터를 치면, 명령이 실행되지 않고 커서가 아래로 넘어가는 것을 볼 수 있다. 다음 라인을 적을 수 있는 상태가 되는 것이다. 그리고 RUN을 적고 엔터를 치면 메모리에 올라간 모든 코드를 1번 라인부터 실행한다. 빈 라인은 모두 무시하기 때문에 번호는 맘대로 매기면 된다. 10부터 시작하든, 아니면 4272부터 시작하든, 코드는 멀쩡히 실행된다.

실행이 끝나고 READY가 표시되면, 우리는 몇 번이고 상관 없이 RUN을 사용해서 프로그램을 또 실행할 수 있다. 메모리에 프로그램이 남아 있기 때문이다. 그러면 메모리에 프로그램이 남아 있다는 걸 어떻게 확인할 수 있을까? READY가 표시된 상태에서 LIST를 적고 엔터를 쳐 보자. 조금 전에 우리가 작성한 코드를, 줄 번호를 포함해서 보여줄 것이다.

코드 수정하기

이번엔 "HELLO,WORLD!"를 다른 글자로 바꿔보자. 예를 들면, "LIBRE WIKI"로 바꿔 보도록 하자. 그런데, 우리가 조금 전에 작성한 코드를 어떻게 수정할 수 있을까? 그 코드는 메모리 속에 들어 있는데 말이다. 우리는 메모리 주소도 모르고, 단지 그 코드의 줄 번호만 LIST 명령어로 볼 수 있다. 그렇다면 줄 번호만 가지고 코드를 수정할 수 있어야 하지 않을까?

그렇다, 우리는 줄 번호만 알면 수정할 수 있다. 이미 작성된 줄 번호를 다시 적기 시작하면, 이전 내용은 사라지고 새 내용이 쓰인다. 아래 내용을 적고 실행해 보자.

10 PRINT"LIBRE WIKI"
RUN

HELLO,WORLD는 없어지고 LIBRE WIKI가 표시되는 것을 볼 수 있다. LIST로 코드를 봐도 HELLO, WORLD는 없다. 같은 줄 번호라서 덮어쓰기 된 것이다. 만약 같은 줄 번호를 적고 내용은 아무것도 적지 않으면, 빈 줄이 되고 실행할 때 없는 줄 취급된다.

그러면 새 프로그램을 적기 위해서 코드를 전부 지우려면 모든 줄 번호를 일일이 빈 줄로 만들어야 한다는 말인가? 그건 너무 가혹하다. 그래서 간단히 메모리의 프로그램을 지울 수 있는 명령어가 존재한다. NEW를 적고 엔터를 쳐 보자. RUN을 해도, LIST를 해도 아무것도 안 나온다는 것을 알 수 있다. 메모리의 프로그램이 지워진 것이다.

변수와 GOTO

BASIC에서는 변수를 따로 선언할 필요가 없다. 처음 등장한 시점에서 자동으로 선언된다. 그래서 메모리가 엉망이 된다 변수에 담을 수 있는 값은 세 종류가 있는데, 정수, 실수, 문자열이 있다. 이름은 숫자로 시작할 수 없고, 이름 맨 뒤에 기호를 붙여서 값의 종류를 나타낸다. 정수는 %, 문자열은 $를 붙인다. 실수형은 아무것도 붙이지 않는다. 당연히 BASIC 명령어는 이름으로 사용할 수 없다. 그리고 가장 중요한 것은, 값의 종류를 나타내는 기호를 제외하면 이름의 세 번째 글자부터는 인식을 하지 못한다. 그러니까, 변수 이름은 두 글자가 한계라는 말이다. 실로 혹독한 환경이 아닐 수 없다. 헝가리언 표기법? 낙타 표기법? C64에서는 부릴 수도 없는 사치인 것이다(...) 다행인지 불행인지, X1, X1%, X1$ 세 변수는 다른 변수로 취급된다. 자료형이 다르면 이름이 같아도 다른 변수가 된다.

다음으로 GOTO에 대해서 알아보자. GOTO는 줄 번호를 지정해서 그 줄로 점프하는 구문이다. 프로그래밍에 발을 담근 사람이라면 누구나 한 번쯤은 들어본 적이 있을 것이다. 까딱 잘못하면 전혀 읽을 수 없는 스파게티 코드가 되기 때문에 요즘은 절대로 쓰지 않는다. 하지만 아주 간단하고 직관적으로 프로그램을 작성할 수 있게 만들어 주는 구문이다. 웃기시네 특히 순서도를 그대로 프로그램으로 옮길 때 편하다. 다음 예제는 변수와 GOTO문을 적절히 섞은 것이다.

10 X=10
20 Y=20
30 Z=0
40 GOTO 99
50 Z=X+Y
99 ? X;Y;Z

여기에서 ?는 PRINT 구문의 약어이다. LIST로 보면 ?가 PRINT로 바뀌어 있는 것을 볼 수 있다.

40번 줄에서 99번 줄로 점프하라는 명령을 내렸기 때문에 50번 줄은 실행되지 않았고, Z의 값은 0이 된다.

반복문(루프)과 분기

루프를 만들려면 FOR 문을 쓴다. 다른 언어들과 마찬가지로 FOR 문은 지정된 횟수만큼 반복하고 종료된다. 무한 루프를 만들기 위해서는 FOR가 아니라 GOTO를 써야 한다. 왜 스파게티 코드가 나올 수밖에 없는지 슬슬 감이 올 것이다 FOR로 만든 루프는 다음과 같은 모양이다.

10 FOR CT=1 TO 4
20 ? "LIBRE WIKI";CT
30 NEXT CT

CT는 변수로, 처음은 1, 마지막에는 4의 값을 가진다. 30번 줄에서 CT의 값을 1 증가시킨다. 따라서 출력 결과는 다음과 같다.

LIBRE WIKI 1
LIBRE WIKI 2
LIBRE WIKI 3
LIBRE WIKI 4

변수 값을 얼마나 증가시킬지도 정할 수 있다. 이럴 때에는 다음처럼 쓴다.

10 FOR CT=1 TO 5 STEP 2
20 ? "LIBRE WIKI";CT
30 NEXT CT

STEP 2가 변수를 2씩 증가시키겠다는 의미이다. 출력 결과는 다음과 같다.

LIBRE WIKI 1
LIBRE WIKI 3
LIBRE WIKI 5

STEP에는 소수나 음수도 쓸 수 있다. 음수를 쓸 때에는 변수값을 (큰 수) TO (작은 수)와 같이 써 주어야 한다. 그렇게 하지 않으면 오버플로우 에러가 날 때까지 루프를 반복하게 된다.

이제 분기에 대해서 알아보자. 특정한 조건을 만족하면 분기하도록 하는 것은 프로그램의 기본이다. BASIC에서는 IF...THAN 문을 쓴다. IF (조건) THAN (분기 내용)으로 적고, 분기 내용에 숫자를 적으면 그 줄 번호로 점프(GOTO)한다. 조건은 부등호로 적는데, 같지 않다는 !=가 아니라 <>이다. 아래 예제는 여기에서 가져왔다.

10 A=0
20 IF A<=8 THEN 40
30 END
40 ?"FRODO LIVES ";A
50 A=A+2
60 GOTO 20
RUN

실행 결과는 다음과 같다.

FRODO LIVES 0
FRODO LIVES 2
FRODO LIVES 4
FRODO LIVES 6
FRODO LIVES 8

FOR문으로 짜는게 더 쉽다는 건 무시하자

입력

이번엔 입력을 받아보자. 입력을 받는 명령어는 INPUT과 GET이 있다. INPUT은 엔터 키를 눌러야 명령이 진행되고, GET은 엔터 키 입력 없이 오직 한 글자만을 받는다. 적을 때에는 INPUT (변수 이름)과 같이 한다. GET도 동일.

다음은 내가 적은 글을 그대로 반복해서 보여주는 프로그램이다.

10 INPUT A$
20 ?"YOU SAID:";A$
30 GOTO 10
RUN

숫자만 받고 싶다면 자료형을 바꾸면 된다. 잘못된 정보를 입력받으면, ?REDO FROM START 라는 메시지가 표시되면서 처음으로 되돌아간다.

구구단

지금까지 배운 모든 것을 한 데에 합쳐서, 구구단 프로그램을 작성해 보자. 억지로 입력을 끼워넣기 위해서 INPUT으로 숫자를 받아서, 그 숫자에 1부터 9를 곱한 값을 출력하도록 해보자. 또, 0을 입력하면 프로그램이 종료되도록 하는 기능도 넣어 보자. 음수와 관련된 처리를 넣지 않아서, 음수 구구단도 출력할 수 있다. 두 자리 이상 숫자도 가능. FOR문의 반복 횟수를 조절하면 19단도 만들 수 있다.

10 INPUT A%
20 IF A%=0 THEN 99
30 FOR B=1 TO 9
35 ?A%;"X";B%;"=";A%*B
40 NEXT B
50 GOTO 10
99 END
RUN